代码又老又湿,为什么Redis6.0之前没有使用多线程?官方回答:使用Redis时,几乎没有CPU瓶颈。Redis主要受内存和网络的限制。在普通的Linux系统上,Redis通过使用流水线可以每秒处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,它几乎不会占用太多的CPU。使用单线程后,可维护性高。多线程模型虽然在某些方面表现良好,但引入了程序执行顺序的不确定性,带来了读写并发的一系列问题,增加了系统的复杂度,并且可能有线程切换甚至加锁导致的性能损失解锁和死锁。Redis通过AE事件模型和IO多路复用技术具有非常高的处理性能,所以不需要使用多线程。单线程机制大大降低了Redis内部实现的复杂度,Hash的惰性Rehash、Lpush等“线程不安全”命令可以无锁执行。在《Redis 为什么这么快?》码哥中,对牢度原理有详细的介绍。在Redis6.0之前,单线程是指Redis只有一个线程可以工作?不是,Redis在处理客户端请求时,包括获取(socket读取)、解析、执行、内容返回(socket写入)等,都是由一个序列字符串组成的,这就是所谓的“单线程”。在命令执行阶段,由于Redis是单线程处理命令,所有到达服务器的命令都不会立即执行,所有命令都会进入一个Socket队列,当socket可读时,交给单线程事件分发器一个一个被执行。此外,一些命令操作可以与后台线程或子进程一起执行(如数据删除、快照生成、AOF重写)。代码又老又湿,Redis6.0为什么要引入多线程?随着硬件性能的提升,Redis的性能瓶颈可能会出现在网络IO的读写上,即:单线程处理网络读写的速度跟不上底层网络硬件速度。读写网络的read/write系统调用在Redis执行过程中占据了大部分的CPU时间。瓶颈主要在于网络的IO消耗。优化主要有两个方向:提高网络IO性能。典型的实现是使用DPDK来代替内核网络栈的方式。使用多线程充分利用多核,提高网络请求读写的并行性,典型实现如Memcached。增加对用户态网络协议栈的支持,需要修改Redis源码中网络相关的部分(比如修改所有网络发送和接收请求函数),会带来很大的开发工作量。而且,添加新代码可能会引入新的错误,导致系统不稳定。因此,Redis使用多个IO线程来处理网络请求,以提高网络请求处理的并行度。需要注意的是,Redis的多IO线程模型只是用来处理网络读写请求的。对于Redis的读写命令,还是单线程的。这是因为网络处理往往是瓶颈,可以通过多线程并行处理来提升性能。如果继续使用单线程执行读写命令,就不需要开发多线程的安全机制来保证Lua脚本、事务等,实现起来更简单。架构图如下:图片来源:后端研究院的主线程和IO多线程是如何配合的?如下图所示:Redis多线程和IO线程的主进程:主线程负责接收连接建立请求,获取socket并放入全局等待读取处理队列;主线程通过轮询的方式将可读socket分配给IO线程;主线程阻塞等待IO线程读取socket完成;主线程执行IO线程读取并解析的Redis请求命令;主线程阻塞等待IO线程将命令执行结果写回socket;主线程清空全局队列,等待客户端后续请求。思路:将主线程的IO读写任务拆分成一组独立的线程处理,这样多个socket的读写可以并行,但是Redis的命令还是由主线程串行执行。如何启用多线程?Redis6.0的多线程默认是关闭的,只使用主线程。要启用它,需要修改redis.conf配置文件:io-threads-do-readsyes。代码又旧又湿。线程数是不是越多越好?当然不是。关于线程数的设置,官方有一个建议:4核机器建议设置2或3线程,8核机器建议设置6线程。线程数必须小于机器内核数。线程数不是越大越好。官方认为超过8个线程基本没有意义。另外,开启多线程后,还需要设置线程数,否则不会生效。io-threads4总结与思考随着互联网的飞速发展,互联网业务系统必须处理的在线流量越来越大。Redis的单线程模式会导致系统在网络I/O上消耗大量的CPU时间,从而降低吞吐量。Redis的性能提升有两个方向:优化网络I/O模块提高机器内存读写速度后者取决于硬件的发展,暂时没有解决方案。因此,只能从前者着手,网络I/O的优化分为两个方向:零拷贝技术或DPDK技术利用多核优势模型缺陷Redis的多线程网络模型实际上并不是一个标准的Multi-Reactors/Master-Workers模型。在Redis的多线程方案中,I/O线程任务只是通过socket读取和解析客户端请求命令,并不真正执行命令。所有client命令最后都需要回到主线程执行,所以多核的利用率不高,而且每次分配任务后主线程都要忙着轮询等待所有I/O线程来完成他们的任务。继续执行其他逻辑。在我看来,Redis目前的多线程方案更像是一种折中的选择:既保持了原有系统的兼容性,又利用多核来提升I/O性能。
