一、Redis为什么这么快
- 基于内存操作
- 高效的数据结构:有String、List、hash、set、zset、bitMap、布隆过滤器等数据结构
- 单线程采用IO多路复用,6.0采用多线程版
- 单线程避免了加锁、线程上下文切换等开销
二、Redis IO多路复用
- Redis根据reactor模型开发了自己的事件处理器,主要分为四部分:套接字、IO多路复用程序、文件事件分派器、文件事件处理器
- 套接字:每个客户端都是一个套接字,当客户端产生连接、读取、写入、关闭都会有对应的文件事件产生
- IO多路复用程序:会同时连接多个套接字,根据操作系统自行选择select/epoll/evport/kqueue最佳实现。
IO多路复用程序会将生成了文件事件的套接字发送给文件事件分派器。等多个文件事件并发出现,IO多路复用程序会将产生了文件事件的套接字放入队列,以有序、同步、每次一个套接字的方式发送给文件派发器 - 文件事件分派器:将套接字产生的文件事件分派给文件处理器进行处理。根据套接字产生的事件调用响应的事件处理器
- 事件处理器:根据文件事件执行相应的函数,如连接、命令读取、命令写入、连接关闭等
select、epoll的区别
select
- select底层是数组结构,最大容量为1024
- select将文件描述放入数组中,同时会将数组拷贝到内核中,高并发下,会频繁拷贝
- select由操作系统遍历数组,文件描述符发生事件时会将数量传递给用户态,用户态在遍历数组找到相应的事件文件描述符
epoll
- epoll底层数据采用红黑树,没有大小限制
- epoll在内核中存储文件描述符,用户态只要告诉需要修改的文件描述符即可,不需要重新传入
- epoll采用异步驱动,将发生事件的文件描述符发送给用户态,避免了用户态遍历
)
三、Redis单线程和多线程
- Redis4.0之前是单线程的,4.0之后引入线程,如数据的删除,核心命令还是单线程的
- redis的瓶颈在于内存和网络IO,CPU不是,所以6.0引入多线程处理网络IO,但是redis的命令执行还是单线程,不存在线程安全问题。Redis多线程不会同时进行读写,要么全部读、要么全部写。
四、Redis6.0之后的处理流程
- 当接收到读事件时,redis会把客户端连接放入全局读队列中
- 读取数据时,主线程将读事件的客户端通过轮询调度算法分配给一个I/O线程,自己也处理一个客户端连接的读事件,完成后自旋等待其他I/O线程
- 根据客户端加入全局读队列的顺序,串行执行命令,执行完成后将客户端连接放入全局写队列
- 写回结果,主线程根据轮询调度算法将客户端连接分配给I/O线程,自己也处理一个客户,完成后自旋等待其他线程完成,最后清空队列
五、Redis过期策略
- 定时淘汰:设置一个定时器,将过期的key进行删除
- 定期删除:默认100ms,抽取一定数量的key,对过期的key进行删除
- 惰性淘汰:当操作key,发现key已经过期进行删除
- Redis默认采用定期+惰性删除
六、Redis淘汰策略
- noeviction:抛出异常,默认策略
- allkeys-random:从所有的key中删除部分键
- volatile-random:在设置了过期时间的key中随机删除部分键
- allkeys-lru:在所有key中,采用LRU算法删除近期最少使用的key
- volatile-lru:在设置了过期时间的key中,采用LRU算法随机删除近期最少使用的key
- allkeys-lfu:在所有key中,采用LFU算法删除使用频率最少使用的key
- volatile-lfu:在设置了过期时间的key中,采用LRU算法随机删除使用频率最少使用的key
- volatile-ttl:在设置了过期时间的key,删除过期时间最短的key
七、Redis与Memcached的区别
- Redis具有多种数据结构,Memcached只有key-value
- Redis可以持久化,Memcached只保存在内存中
- Redis可以使用持久化文件进行数据恢复,Memcached宕机后数据消息
- Memcached多核多线程,Redis6.0引入多线程
- Redis有多种淘汰策略,Memcached使用LRU策略
- Memcached使用惰性删除,Redis使用惰性删除+定期删除