大家好,我是骄阳,我们上一期讲了redis单线程,这一期我们聊一下redis6.0的多线程新特性
redis6之后
Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,对于小数据包,Redis服务器可以处理80,000到100,000 QPS,这也是Redis处理的极限了,对于80%的公司来说,单线程的Redis已经足够使用了。
但随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的QPS。
常见的解决方案是在分布式架构中对数据进行分区并采用多个服务器。
但该方案有非常大的缺点:
例如要管理的Redis服务器太多,维护代价大;
某些适用于单个Redis服务器的命令不适用于数据分区;
数据分区无法解决热点读/写问题;
数据偏斜,重新分配和放大/缩小变得更加复杂等等。
从Redis自身角度来说,因为读写网络的read/write系统调用占用了Redis执行期间大部分CPU时间,瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向:
(1)提高网络 IO 性能,典型的实现比如使用 DPDK 来替代内核网络栈的方式
(2) 使用多线程充分利用多核,典型的实现比如 Memcached。
但是协议栈优化的这种方式跟 Redis 关系不大,支持多线程是一种最有效最便捷的操作方式。
所以总结起来,redis支持多线程主要就是两个原因:
(1) 可以充分利用服务器 CPU 资源,目前主线程只能利用一个核
(2) 多线程任务可以分摊 Redis 同步 IO 读写负荷
Redis6.0的多线程默认是禁用的,只使用主线程。如需开启需要修改redis.conf配置文件:io-threads-do-reads yes
开启多线程后,还需要设置线程数,否则是不生效的。
官方建议:
4核的机器建议设置为2或3个线程,8核的建议设置为6个线程,线程数一定要小于机器核数。
还需要注意的是,线程数并不是越大越好,官方认为超过了8个基本就没什么意义了。
Redis 6 引入的多线程 IO 特性对性能提升至少是一倍以上。
如果开启多线程,至少要4核的机器,且Redis实例已经占用相当大的CPU耗时的时候才建议采用,否则使用多线程没有意义。
流程简述如下:
1、主线程负责接收建立连接请求,获取 socket 放入全局等待读处理队列
2、主线程处理完读事件之后,通过 RR(Round Robin) 将这些连接分配给这些 IO 线程
3、主线程阻塞等待 IO 线程读取 socket 完毕
4、主线程通过单线程的方式执行请求命令,请求数据读取并解析完成,但并不执行回写 socket
5、主线程阻塞等待 IO 线程将数据回写 socket 完毕
6、解除绑定,清空等待队列
该设计有如下特点:
1、IO 线程要么同时在读 socket,要么同时在写,不会同时读或写
2、IO 线程只负责读写 socket 解析命令,不负责命令处理
4.开启多线程后,是否会存在线程安全问题?
Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。
所以我们不需要考虑线程安全问题。
Memcached 服务器采用 master-woker 模式进行工作,服务端采用 socket 与客户端通讯。
主线程、worker线程 采用 pipe管道进行通讯。
主线程采用 libevent 监听 listen、accept 的读事件,事件响应后将连接信息的数据结构封装起来。
根据算法选择合适的worker线程,将连接任务携带的连接信息分发出去,相应的线程利用连接描述符,建立与客户端的socket连接 ,进行后续的存取数据操作。
相同点:
都采用了 master线程-worker 线程的模型
不同点:
(1)Memcached 执行主逻辑也是在 worker 线程里,模型更加简单,实现了真正的线程隔离,符合我们对线程隔离的常规理解。
(2) Redis 把处理逻辑交还给 master 线程,虽然一定程度上增加了模型复杂度,但也解决了线程并发安全等问题
好啦,今天的内容就到这里啦,喜欢我的可以点个关注,你的支持就是我更新的动力,我们下期再见。