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

Redis6.0新特性——13道多线程连载题!

时间:2023-03-19 15:40:27 科技观察

Redis6.0来了!在全国IT民工们都在平安过五一假期的时候,Redis6.0于5月2日正式发布,吓得我赶紧下床学个没完没了!终身学习!对于6.0版本,Redis之父Antirez在发布RC1版本时(2019-12-19)在他的博客上连续用了几个“EST”字样:迄今为止最“企业”的Redis版本//最“企业”-level“据我所知Redis最大的版本//参与人数最多的版本//这个参与人数最多的版本提供了许多令人兴奋的新特性和功能改进,例如,新的网络协议RESP3、新的集群代理、ACL等,其中最关心的应该是“多线程”,笔者也是第一次体验,问题多多,一起入手“Redis6.0new特性——多线程链13题》。Redis6.0多线程系列13Q1.Redis6.0之前的版本真的是单线程的吗?Redis在处理客户端请求时,包括获取(socketread)、解析、执行、内容返回(socketwrite)等,都是由一个串行的主线程处理的,也就是所谓的“单线程”。但严格来说,Redis4.0并不是单线程的。除了主线程,它还有后台线程处理一些慢操作,比如清理脏数据、释放无用连接、删除大键等。2、为什么Redis在6.0之前没有使用多线程?官方曾回应过类似问题:使用Redis时,几乎没有CPU瓶颈。Redis主要受内存和网络的限制。例如,在普通的Linux系统上,Redis通过使用流水线可以每秒处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,几乎不会占用过多的CPU。使用单线程后,可维护性高。多线程模型虽然在某些方面表现良好,但引入了程序执行顺序的不确定性,带来了读写并发的一系列问题,增加了系统的复杂度,并且可能有线程切换甚至加锁导致的性能损失解锁和死锁。Redis使用了AE事件模型和IO多路复用等技术实现了非常高的处理性能,所以不需要使用多线程。单线程机制大大降低了Redis内部实现的复杂度,Hash的惰性Rehash、Lpush等“线程不安全”命令可以无锁执行。3、Redis6.0为什么要引入多线程?Redis将所有数据放在内存中,内存响应时间在100纳秒左右。对于小数据包,Redis服务器可以处理80,000到100,000QPS,这也是Redis处理的极限。对于80%的公司来说,单个ThreadedRedis使用起来绰绰有余。但是随着业务场景越来越复杂,一些公司动辄上亿的交易量,需要更大的QPS。一种常见的解决方案是在分布式架构中对数据进行分区,并使用多台服务器,但这种方案存在非常严重的缺点,例如Redis服务器太多难以管理,维护成本高;命令不适用于数据分区;数据分区不能解决热点读/写问题;数据倾斜、重新分配和扩缩容等变得更加复杂。从Redis本身来看,由于Redis执行过程中读写系统调用对网络的读写占据了大部分CPU时间,瓶颈主要是网络的IO消耗。优化的方向主要有两个:?提高网络IO性能,典型的实现如使用DPDK替代内核网络栈?使用多线程充分利用多核,典型的实现如Memcached。这种协议栈优化的方法与Redis关系不大。支持多线程是最有效和方便的操作方式。所以综上所述,redis之所以支持多线程,主要有两个原因:?可以充分利用服务器CPU资源。目前主线程只能使用一个核。?多线程任务可以分担Redis同步IO读写的负载。4、Redis6.0是否默认开启多线程?Redis6.0的多线程默认是关闭的,只使用主线程。如果要启用,需要修改redis.conf配置文件:io-threads-do-readsyes5。Redis6.0开启多线程后,如何设置线程数?开启多线程后,还需要设置线程数,否则不生效。还要修改redis.conf配置文件中关于线程数的设置。官方有个建议:4核的机器建议设置成2或3线程,8核的机器建议设置成6线程。线程数必须小于机器核心数。还需要注意的是,线程数越大越好。官方认为超过8个线程基本没有意义。6、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.2xlargetest结果:详见:https://zhuanlan.zhihu.com/p/76788470注1:本次性能验证测试没有针对严格的延迟控制和不同的并发场景进行压力测试。数据仅供验证参考,不能作为线上指标。注2:如果开启多线程,至少需要一台4核的机器,只有当Redis实例已经占用了相当多的CPU时间时才推荐使用。否则,使用多线程是没有意义的。所以估计80%的公司开发人员只是看看而已。7、Redis6.0多线程的实现机制是什么?流程简述如下:1.主线程负责接收连接建立请求,获取socket放入全局等待读处理队列2.主线程处理完读事件后,分配这些连接通过RR(RoundRobin)给这些IO线程3.主线程阻塞,等待IO线程读完socket4.主线程以单线程的方式执行请求命令,读取请求的数据并解析,但未执行。5.主线程阻塞,等待IO线程将数据写回socket。6、解除绑定,清除等待队列(来源:https://ruby-china.org/topics/38957)这种设计有以下特点:1.IO线程同时在读或写socket,并且不会同时读或写2.IO线程只负责读写socket解析命令,不负责命令处理。8、启用多线程后,会不会有线程并发安全问题?从上面的实现机制可以看出,Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令还是在单线程中顺序执行。所以我们不需要考虑控制键、lua、事务、LPUSH/LPOP等的并发和线程安全问题。9.如何在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-310。Redis6.0的多线程和Memcached多线程模型对比。前几年memcached是各大互联网公司常用的缓存方案,所以redis和memcached的区别基本上已经成为面试官关于缓存的必问面试题。这几年memcached用的少了,基本都是redis。但是,随着Redis6.0加入了多线程特性,类似的问题还是会出现。接下来,我们只简单对比一下多线程模型。如上图所示:Memcached服务器工作在master-woker模式,服务器使用sockets与客户端通信。主线程和工作线程使用管道进行通信。主线程使用libevent监听listen和accept的读事件,封装事件响应后的连接信息数据结构,根据算法选择合适的工作线程,分发携带连接信息的连接任务,以及相应的线程使用连接描述符建立和通信客户端的套接字连接以及后续的访问数据操作。Redis6.0与Memcached多线程模型对比:相同点:均采用master线程-worker线程模型区别:Memcached在worker线程中执行主要逻辑,模型更简单,实现了真正的线程隔离,即符合我们要求的线程隔离的一般理解。Redis将处理逻辑返回给主线程。虽然在一定程度上增加了模型的复杂度,但也解决了线程并发安全等问题。11、Redis的作者如何评价“多线程”这个新特性?关于多线程的特性,在6.0RC1中,Antirez曾经解释过:Redis支持多线程有两种可行的方式:第一种类似于“memcached”,一个Redis实例开启多个线程,从而提高GET/Operationspersecond可以在简单的命令中执行,例如SET。这涉及到I/O、命令解析等多线程处理,所以我们称之为“I/O线程”。另一个是让耗时慢的命令可以在不同的线程中执行,保证其他客户端不被阻塞。我们称这种线程模型为“慢命令线程”。经过深思熟虑,Redis不会使用“I/O线程”。Redis在运行时主要受限于网络和内存,所以提高redis的性能主要是通过多个redis实例,尤其是redis集群。接下来主要考虑两个方面的改进:1.Redis集群的多个实例可以通过编排合理使用本地实例的磁盘,避免同时重写AOF。2、提供Redis集群代理,方便用户在没有更好的集群协议客户端的情况下抽象出一个集群。补充一下,Redis和memcached一样是一个内存系统,但是又不同于Memcached。多线程很复杂,必须考虑简单的数据模型。执行LPUSH的线程需要为其他执行LPOP的线程服务。我真正期望的实际上是“慢操作线程”。在redis6或redis7中,会提供“key-levellocking”,让线程完全获得对key的控制,以处理慢速操作。详情请见:http://antirez.com/news/12612。Redis线程中经常提到IO多路复用,怎么理解?这是IO模型中的一种,经典的Reactor设计模式,有时也叫异步阻塞IO。多路复用是指多个socket连接,多路复用是指多路复用一个线程。多路复用主要有3种技术:select、poll、epoll。epoll是目前最新最好的多路复用技术。使用多I/O多路复用技术,可以让单个线程高效处理多个连接请求(最大限度地减少网络IO的时间消耗),Redis在内存中操作数据的速度非常快(内存操作不会成为这里的性能瓶颈),主要以上两点使得Redis具有很高的吞吐量。13.你知道Redis的彩蛋LOLWUT吗?这实际上是从Redis5.0开始就存在的,但请原谅我只知道它。作者是这样描述这个功能的《LOLWUT: a piece of art inside a database command》,“数据库命令中的艺术品”。你可以称之为感情,也可以称之为彩蛋。我不会透露它是什么。和我一样不知道是什么的朋友可以参考:http://antirez.com/news/123,每次运行都会随机生成。