为什么单线程的Redis却能支撑高并发?( 三 )


在 Redis 中,我们通过宏定义的使用,合理的选择不同的子模块:
#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 因为 select 函数是作为 POSIX 标准中的系统调用,在不同版本的操作系统上都会实现,所以将其作为保底方案:
 

为什么单线程的Redis却能支撑高并发?

文章插图
 
 
Redis 会优先选择时间复杂度为 $O(1)$ 的 I/O 多路复用函数作为底层实现,包括 Solaries 10 中的 evport、linux 中的 epoll 和 macOS/FreeBSD 中的 kqueue 。
上述的这些函数都使用了内核内部的结构,并且能够服务几十万的文件描述符 。
但是如果当前编译环境没有上述函数,就会选择 select 作为备选方案,由于其在使用时会扫描全部监听的描述符,所以其时间复杂度较差 O(n) 。
并且只能同时服务 1024 个文件描述符,所以一般并不会以 select 作为第一方案使用 。
总结
Redis 对于 I/O 多路复用模块的设计非常简洁,通过宏保证了 I/O 多路复用模块在不同平台上都有着优异的性能,将不同的 I/O 多路复用函数封装成相同的 API 提供给上层使用 。
整个模块使 Redis 能以单进程运行的同时服务成千上万个文件描述符,避免了由于多进程应用的引入导致代码实现复杂度的提升,减少了出错的可能性 。
作者:Draveness来源:Draveness|
 

【为什么单线程的Redis却能支撑高并发?】


推荐阅读