一、 Redis有多快? |
Redis不是一般地快!
Redis和Memcached同为内存数据库,且都支持分布式,近年来,Redis凭借着优秀的架构设计,不断蚕食Memcached领地,大有一统天下的趋势。
感受一下redis高端配置的吞吐量,横轴为连接数,纵轴为吞吐量,图片来源于官方文档
基于epoll/kqueue,Redis事件循环具有很强的可扩展性。Redis已经在60000多个连接上进行了基准测试,并且在这些条件下仍能够维持50000q/s。根据经验,具有30000个连接的实例只能处理100个连接可实现的吞吐量的一半。
二、Redis为什么快? |
2.1 采用单线程
单线程意味着,Redis不再考虑锁和进程的上下文切换及资源竞争问题。
Redis的单线程是指,网络请求处理模块使用了一个线程,Redis是线程安全的,不考虑并发安全性,也就是说,一个线程处理所有网络请求。
需要注意的是,Redis其他模块仍然使用了多个线程,如,文件的定时备份和恢复,执行数据清理策略等。
2.2 绝大部分请求是内存操作
- 内存操作:
- 内存数据读写
- 磁盘持久化操作:
- 文件备份与恢复
这里可以简单理解为,Redis处理网络请求的单个线程涉及到的操作都是内存操作,其他与磁盘相关的操作是其他线程来完成的。
2.3 采用IO多路复用策略epoll
IO多路复用的策略有select、pselect、poll和epoll,其中pselect与select大同小异,epoll是select和poll的改进版本。
epoll与select和poll相比,具有如下优点:
- 没有最大并发连接的限制。select和poll有系统FD_SETSIZE限制的问题,32位机器默认1024,64位机器默认是2048,epoll解决了select和poll只能监听有限数量FD(文件描述符)的问题,1G内存能监听10万左右的端口;
- 只遍历活跃的Socket,轮询效率高。select和poll不管Socket是否活跃,会遍历所有Socket,包括idle-connection和dead-connection,而epoll最大的优点就在于只管“活跃”的连接,与连接总数无关,因此,epoll效率更高;
- 内核空间和用户空间共享内存来减少FD复制的开销。利用mmap()文件映射内存加速与内核空间的消息传递来实现。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次,而select和poll需要将消息从内核传递到用户空间,都需要多次内核拷贝动作。
2.4 其他优化
2.4.1 压缩存储
Redis的数据类型都可能有2种或者多种内部编码实现,这使得Redis可以根据不同的场景选择最优的编码方式。
阅读源码会发现,当数据量较小时,Redis会使用ziplist实现list,使用zipmap实现HashTable,ziplist和zipmap是经过精心设计的数据编码方式,ziplist和zipmap在内存中的存储都是连续内存空间。ziplist列表两端push和pop操作都是O(1),zmap的key查询为O(n),为string-> string结构,节省了空间。
具体可参考源码:redis/src/ziplist.c和redis/src/zipmap.c
2.4.2 数据淘汰策略的优化
最新版本Redis v5.4具有8种Eviction策略,其中,LFU为最近版本加入。
值得一提的是,Redis实现的LRU是经典LRU的一种近似,简单说就是有一个专用的eviction pool,当执行evict时,采样N个样本,并非经典LRU算法的所有样本,加入到eviction pool,eviction pool的大小由EVPOOL_SIZE
来定义。正是由于选取有限个值(一般是5)使用LRU算法,这大大提高了效率。
所有的策略如下:
Policy | Description |
---|---|
noeviction | 如果在尝试插入更多数据时达到内存限制,则返回错误 |
allkeys-lru | 从所有key中删除最近最少使用的key |
allkeys-lfu | 从所有key中删除最不常用的key |
allkeys-random | 随机删除所有key中的key |
volatile-lru | 使用“expire”字段从所有key中删除最近最少使用的key |
volatile-lfu | 使用“expire”字段从所有key中删除最不常用的key |
volatile-random | 使用“expire”字段随机删除key |
volatile-ttl | 使用“expire”字段,从所有key中删除最短的生存时间和最近最少使用的key |
LRU和LFU具体算法可参考源码:redis/src/evict.c
2.4.3 数据结构及架构设计
这部分内容较为繁杂,专用的数据结构都有很多巧妙的设计,如,sds、redisobj等,有兴趣的可以读读源码。
总结 |
早期Memcached强调Cache,而如今Redis强调DB,大多时候Redis可以替代Memached。
单线程情况下,Redis往往比Memcached快,但Memcached本身基于多线程,这是它的优势所在,多线程情况下,Memcached往往比Redis快。具体的快慢总是相对的,需要根据自己的业务场景,适配合适的工具,除非性能是整个技术架构中的瓶颈,否则,应该长远考虑架构的稳定性和拓展性。
参考文献
- 聊聊IO多路复用之select、poll、epoll详解
- select和pselect区别
- How fast is Redis?
- 为什么Redis是单线程?
- Redis Eviction Policies
- Redis源码
能力有限,欢迎指错交流~
个人微信公众号WaltSmithML
主要方向为NLP和推荐系统。非常欢迎交流学习