redis单线程模型
我们经常说redis是单线程的,这个单线程指的是redis的网络IO的读写与数据库数据的除操作都在一个线程中完成,从而避免多线程编程的一些数据竞争的问题。
但是redis的网络IO的读取与数据库操作都在同一个线程中完成,为什么还能够达到如此的高效呢?这就要归功于IO多路复用技术、redis的高效的数据结构、没有数据竞争问题以及所有数据操作都是内存操作。关于redis的高效的数据结构,将在我的其他博客介绍。
Redis IO多路复用技术模型,使用的是单reactor模式,其模型图如下:
select/epoll 一旦监测到 FD 上有请求到达时就,就会放入一个队列中,redis主线程调用epoll_wait获取队列中的事件并且处理。如果redis调用epoll_wait时,队列中没有事件,那么就会堵塞直到有事件到达或者超时,这样一来,Redis 无需一直轮询是否有请求实际发生,可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。
更多reactor编程模式见我的博文:《Linux reactor编程模式
redis真的是单线程么?
其实redis并不是真的是单线程的,我们平时说redis是单线程,主要指的是redis的网络IO的读取与数据库操作都在同一个线程中完成。
1、Redis的AOF重写,生成RDB快照都是通过fork一个子进程,然后使用Linux的写时复制技术,在fork出的子进程中写入磁盘。
2、从Redis 4.0开始,可以通过如下的命令异步删除bigkey
unlink key
redis收到这个命令后,会将其封装成一个任务插入到队列中,然后直接给客户端返回OK,删除key的线程从队列中读到任务后,执行真正的删除操作,释放内存空间,我们称这种删除为惰性删除。相似的,清空数据库也可以异步执行,我们可以通过给命令添加ASYNC关键字:
FLUSHDB ASYNC
FLUSHALL AYSNC
3、AOF日志的每秒刷盘,如果AOF的刷盘策略配置成everysec时,当redis主线程收到命令时,会将其写入AOF的操作系统缓冲区,后台线程每秒调用fsync刷新一次到磁盘。但是需要注意的是如果由于磁盘IO繁忙,异步刷盘时,fsync超过一秒还没有执行成功,那么主线程将停止服务。
4、Redis在6.0还可以利用多线程读取网络IO数据,但是数据库的操作依然是单线程。