嵌入式技术
Redis真的是单线程吗?网上有很多关于这个问题的讨论,得出的结论也几乎是一致的。本文在讨论这个问题之前,先定义好问题中“单线程”的概念边界:
1.单线程指的是“核心网络模型”
2.单线程指的是Redis整个服务端架构的设计
对于边界1,那么答案是肯定的,在Redis v6.0 版本以前,Redis的网络模型一直都是单线程模式的,即使到了v6.0版本,所有客户端命令的执行依然是在主线程上完成的;对于边界2,答案是否定的,Redis从发布之出就有两个BIO(background I/O service)线程来异步处理aof持久化、关闭文件的任务,在Redis v4.0版本中又添加了一个BIO线程,将比较耗时的命令异步化,到了Redis v6.0,Redis核心的网络模型也被改造成了多线程。
在概念边界2的限制下,我们可以得出结论:Redis从来都不是单线程工作的 !在Redis发布近十年来,在系统架构演进过程中都遇到了哪些问题?作者antirez对这些问题是怎样思考的?采取了什么样的方案来改进?探索这些问题对于开发者的成长很有价值,也是本文的写作目的,笔者会结合相关源码与读者共同解答这些问题。
1. Redis基础架构设计
性能优异的服务离不开好的架构设计,Redis使用 I/O multiplexing 实现了单线程接收海量客户端请求;通过单线程Reactor模型实现了高性能的事件处理;基于条件变量实现的生产者消费者模型构建了自己的BIO系统。本节先简单介绍一下这些从Redis诞生以来就一直使用的基础架构设计。
1.1 Redis对 I/O multiplexing 的封装
I/O multiplexing 指的是多个网络socket I/O 复用同一个线程,它解决了C10K的问题。Redis将不同的 I/O 多路复用函数封装成相同的 API 提供给上层使用,仅仅以单线程处理网络I/O,就可以为成千上万的客户端提供服务。
Redis的I/O多路复用模块提供的API:
//下面的方法不同版本的redis在src目录下的ae_epoll.c、ae_evport.c、ae_kqueue.c、ae_select.c代码文件中都有实现 static int aeApiCreate(aeEventLoop *eventLoop) static int aeApiResize(aeEventLoop *eventLoop, int setsize) static void aeApiFree(aeEventLoop *eventLoop) static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)
Redis可以在多个平台上运行,所以会通过宏定义,根据编译平台的不同,选择不同的I/O多路复用函数作为子模块,提供给上层接口做封装。
/*下面代码在Redis不同版本的ae.c源码文件中均包含 *Include the best multiplexing layer supported by this system. * The following should be ordered by performances, descending. */ #ifdef HAVE_EVPORT #include "ae_evport.c" #else #ifdef HAVE_EPOLL #include "ae_epoll.c" #else #ifdef HAVE_KQUEUE #include "ae_kqueue.c" #else #include "ae_select.c" #endif #endif #endif
Redis 会优先选择时间复杂度为
编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !