当前位置: 首页 > 科技观察

支持多线程的Redis6.0终于发布了!

时间:2023-03-18 16:20:36 科技观察

支持多线程的Redis6.0版本终于在2020年5月2日发布了,为什么Redis突然支持多线程了?如何启用多线程?启用后性能提升效果如何?如何设置线程数?会不会有线程安全问题?多线程的实现原理是什么?带着这些问题,让我们开始Redis的新特性——多线程链13题。图片来自Pexels。Redis6.0来了。在国泰民安,IT民工欢庆五一假期的时候,Redis6.0在5月2日正式发布,吓得我赶紧从床上爬起来。学无止境!学无止境!对于6.0版本,Redis之父Antirez在发布RC1版本时(2019-12-19)在他的博客上连续用了几个“EST”字眼:迄今为止最“企业”的Redis版本//最大的发布据我所知,Redis的最大版本//参与人数最多的版本//参与人数最多的版本提供了许多令人兴奋的新特性和功能改进,例如新网络协议RESP3,新集群代理、ACL等,其中最受关注的应该是“多线程”。笔者也是第一次体验。带着诸多疑问,下面开始《Redis6.0新特性-多线程连载13问》。Redis6.0多线程系列13题①Redis6.0之前的版本真的是单线程的吗?Redis在处理客户端的请求时,包括获取(Socket读)、解析、执行、内容返回(Socket写)等,都是由一个序列字符串组成的行,由主线程处理,称为“单线程”.但是严格来说Redis在4.0之后就不是单线程的了。除了主线程,它还有后台线程处理一些慢操作,比如清理脏数据、释放无用连接、删除大键等。②为什么Redis在6.0之前没有使用多线程?官方曾回应过类似问题:使用Redis时,几乎没有CPU瓶颈。Redis主要受内存和网络的限制。例如,在普通的Linux系统上,Redis通过使用Pipelining可以每秒处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,它几乎不会占用太多的CPU。使用单线程后,可维护性高。多线程模型虽然在某些方面表现良好,但引入了程序执行顺序的不确定性,带来了读写并发的一系列问题,增加了系统的复杂度,并且可能有线程切换甚至加锁导致的性能损失解锁和死锁。Redis通过AE事件模型和IO多路复用技术具有非常高的处理性能,所以不需要使用多线程。单线程机制大大降低了Redis内部实现的复杂度,Hash的惰性Rehash、Lpush等“线程不安全”命令可以无锁执行。③Redis6.0为什么要引入多线程?Redis将所有数据放在内存中,内存响应时间在100纳秒左右。对于小数据包,Redis服务器可以处理80,000到100,000QPS,这也是Redis处理的极限。对于80%的公司来说,单线程的Redis就足够了。但是,随着业务场景越来越复杂,一些公司动辄上亿的交易量,需要更大的QPS。一种常见的解决方案是在分布式架构中对数据进行分区并使用多台服务器,但这种方案存在非常严重的缺点,例如Redis服务器太多难以管理,维护成本高。一些适用于单个Redis服务器的命令不适用于数据分区;数据分区不能解决热点读写问题;dataskew,reallocationandscalingup/down变得更加复杂等。从Redis本身来看,由于Redis执行过程中Read/Write系统调用读写网络占用了大部分CPU时间,瓶颈主要是网络的IO消耗。优化主要有两个方向:提升网络IO性能,典型的实现方式如使用DPDK替换内核网络栈。使用多线程充分利用多核,典型的实现如Memcached。这种协议栈优化的方法与Redis关系不大。支持多线程是最有效和方便的操作方式。所以总结一下,Redis之所以支持多线程,主要有两个原因:可以充分利用服务器CPU资源,目前主线程只能使用一个核。多线程任务可以分担Redis同步IO的读写负载。④Redis6.0是否默认开启多线程?Redis6.0默认关闭多线程,只使用主线程。要启用它,需要修改redis.conf配置文件:io-threads-do-readsyes。⑤Redis6.0开启多线程时,如何设置线程数?开启多线程后,还需要设置线程数,否则不生效。同样修改redis.conf配置文件:关于线程数的设置,官方有一个建议:4核机器推荐2或3线程,8核机器推荐6线程。线程数必须小于机器内核数。数字。还需要注意的是,线程数越大越好。官方认为超过8个线程基本没有意义。⑥Redis6.0采用多线程后,性能提升效果如何?Redis作者antirez在RedisConf2019的分享中提到:Redis6引入的多线程IO特性至少让性能提升了一倍。国内也有大牛用unstable版本在阿里云esc上测试过。4线程IO中GET/SET命令的性能几乎是单线程的两倍。测试环境:Redis服务器:阿里云Ubuntu18.04,8个CPU2.5GHZ,8G内存,主机型号ecs.ic5.2xlargeRedisBenchmark客户端:阿里云Ubuntu18.04,8个2.5GHZCPU,8G内存,主机型号ecs.ic5.2xlarge测试结果:详见:https://zhuanlan.zhihu.com/p/76788470注1:本次性能验证测试没有针对严格的延迟控制和不同的并发场景进行压力测试。数据仅供验证参考,不能作为线上指标。注2:如果开启多线程,需要一台至少4核的机器,只有在Redis实例已经占用相当多CPU时间的情况下才推荐使用。否则,使用多线程是没有意义的。所以估计公司80%的开发人员只是看看而已。⑦Redis6.0多线程的实现机制?流程简述如下:主线程负责接收连接建立请求,获取Socket并放入全局等待读处理队列。主线程处理完read事件后,通过RR(RoundRobin)将这些连接分配给这些IO线程。主线程阻塞等待IO线程读完Socket。主线程以单线程的方式执行请求命令,读取并解析请求数据,但不执行。主线程阻塞等待IO线程将数据写回Socket。解除绑定并清空等待队列。图片来源:https://ruby-china.org/topics/38957这种设计有以下特点:IO线程要么同时对Socket进行读写,要么不会同时读写。IO线程只负责读写Socket解析命令,不负责命令处理。⑧启用多线程后,会不会有线程并发安全问题?从上面的实现机制可以看出,Redis的多线程部分只是用来处理网络数据读写和协议解析,执行命令依然是单线程顺序执行。所以我们不需要考虑控制Key、Lua、事务、LPUSH/LPOP等的并发和线程安全问题。⑨如何在Linux环境下安装Redis6.0.1(6.0官方版本是6.0.1)?这个和安装其他版本的Redis没什么区别,整个过程没有什么坑,这里就不赘述了。唯一需要注意的是配置的多线程数必须小于CPU的核心数。使用命令查看核心数:[root@centos7.5~]#lscpuArchitecture:x86_64CPUop-mode(s):32-bit,64-bitByteOrder:LittleEndianCPU(s):4On-lineCPU(s)list:0-3⑩Redis6.0的多线程模型与Memcached的多线程模型对比。官方缓存必问的面试题,Memcached这几年用的少了,Redis基本都用了。但是随着Redis6.0加入了多线程特性,类似的问题还是有可能出现。接下来,我们将只对多线程模型进行简单的比较。如上图所示:Memcached服务器工作在master-woker模式,服务器使用Socket与客户端通信。主线程和工作线程使用Pipe进行通信。主线程使用Libevent监听Listen和Accept的读事件,封装事件响应后的连接信息数据结构,根据算法选择合适的工作线程,分发携带连接信息的连接任务,以及相应的线程使用连接描述符与客户端的Socket连接建立并通信,并进行后续的数据访问操作。Redis6.0与Memcached多线程模型对比:相同点:均采用Master线程-Worker线程模型。区别:Memcached在Worker线程中执行主要逻辑。该模型更简单,实现了真正的线程隔离,符合我们对线程隔离的常规理解。Redis将处理逻辑返回给Master线程。虽然在一定程度上增加了模型的复杂度,但是也解决了线程并发安全的问题。?Redis的作者如何评价“多线程”这个新特性?关于多线程的特性,在6.0RC1中,Antirez曾经解释过:Redis支持多线程有两种可行的方式:第一种是像“Memcached”这样,一个Redis实例启动多个线程,从而增加每秒的操作数这可以通过简单的命令(例如GET/SET)来执行。这涉及到I/O、命令解析等多线程处理,所以我们称之为“I/O线程”。另一个是让耗时慢的命令可以在不同的线程中执行,保证其他客户端不被阻塞。我们称这种线程模型为“慢命令线程”。经过深思熟虑,Redis不会使用“I/O线程”。Redis在运行时主要受限于网络和内存,所以提升Redis性能主要是通过多个Redis实例,尤其是Redis集群。接下来主要考虑两个方面的改进:Redis集群的多个实例可以通过编排合理使用本地实例的磁盘,避免同时重写AOF。提供一个Redis集群代理,方便用户在没有更好的集群协议客户端的情况下抽象出一个集群。补充一下,Redis和Memcached一样是一个内存系统,但是又不同于Memcached。多线程很复杂,必须考虑简单的数据模型。执行LPUSH的线程需要服务于其他执行LPOP的线程。我真正期待的其实是“慢操作线程化”,在Redis6或者Redis7中,会提供“key-levellocking”,让线程完全获得key的控制权来处理慢操作。详见:http://antirez.com/news/126?IO多路复用在Redis线程中经常被提及,如何理解?这是一种IO模型,即经典的Reactor设计模式,有时也叫异步阻塞IO。多路复用是指多个Socket连接,多路复用是指多路复用一个线程。多路复用主要有三种技术:Select、Poll和Epoll。Epoll是目前最新最好的多路复用技术。使用多I/O多路复用技术,可以让单个线程高效处理多个连接请求(最大限度地减少网络IO的时间消耗),Redis在内存中操作数据的速度非常快(内存操作不会成为这里的性能瓶颈),主要以上两点使得Redis具有很高的吞吐量。?你知道Redis的彩蛋LOLWUT吗?这个其实从Redis5.0开始就有了,但是原谅我才知道。作者是这样描述这个功能的《LOLWUT: a piece of art inside a database command》,“数据库命令中的艺术品”。你可以称之为感情,也可以称之为彩蛋。我不会透露它是什么。和我一样不知道是什么的朋友可以参考:http://antirez.com/news/123,每次运行都会随机生成。参考和感谢:Redis作者Antirez的博客:http://antirez.comhttps://www.zhihu.com/question/26943938/answer/68773398https://zhuanlan.zhihu.com/p/76788470http://www.web-lovers.com/redis-source-6-rc-mult-thread.htmlhttps://ruby-china.org/topics/38957https://redis.io/topics/faq#redis-is-single-threaded-how-can-i-exploit-multiple-cpu--coreshttps://juejin.im/post/5e9ae485f265da47b04d95d2https://www.cnblogs.com/gattaca/p/6929361.html作者:剑圣编辑:陶佳龙来源:转载自微信公众号码大叔(ID:ma_dashu)