第2章 Redis单线程vs多线程(入门版)

2.1 Redis为什么选择单线程?

2.1.1 Redis是单线程还是多线程?

这种问法其实并不严谨,为啥这样说呢? 因为跟版本有关。

  • Redis3.x ,最早版本,也就是大家口口相传的redis是单线程。
    • 数据结构简单
    • 避免锁的开销和上下文切换
    • 可以有很高的的QPS
  • Redis4.x,严格意义来说也不是单线程,而是负责处理客户端请求的线程是单线程,但是开始加了点多线程的东西(异步删除)。
  • Redis6.0.x后,告别了大家印象中的单线程,用一种全新的多线程来解决问题。

Redis之父的发言:http://antirez.com/news/132

2.1.2 我们通常说:Redis是单线程究竟何意?

Redis的单线程主要是指Redis的网络IO键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。

但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,其实是由额外的线程执行的。

总结:Redis工作线程是单线程的,但是,整个Redis来说,是多线程的。

2.1.3 Redis3.x单线程时代但性能依旧很快的主要原因

➥ 基于内存操作

Redis 的所有数据都存在内存中,因此所有的运算都是内存级别的,所以他的性能比较高;

➥ 数据结构简单

Redis 的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是 O(1),因此性能比较高;

➥ 多路复用和非阻塞 I/O

Redis使用 I/O多路复用功能来监听多个 socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,同时也避免了 I/O 阻塞操作;

➥ 避免上下文切换

因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生。

2.1.4 作者原话

翻译:Redis 是基于内存操作的,因此他的瓶颈可能是机器的内存或者网络带宽而并非 CPU。既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了,况且使用多线程比较麻烦。但是在 Redis 4.0 中开始支持多线程了,例如后台删除等功能

2.1.5 Redis 4.0之前一直采用单线程的主要原因

  1. 使用单线程模型是Redis的开发和维护更简单,因为单线程模型方便开发和调试。
  2. 即使使用单线程模型也并发的处理多客户端的请求,主要使用的是多路复用和非阻塞IO。
  3. 对于Redis系统来说,主要的性能瓶颈是内存或者网络带宽而并非CPU

2.2 为什么逐渐又加入了多线程特性?

2.2.1 单线程也有单线程的苦恼

正常情况下使用 del 指令可以很快的删除数据,而当被删除的 key 是一个非常大的对象时,例如时包含了成千上万个元素的 hash 集合时,那么 del 指令就会造成 Redis 主线程卡顿。

这就是redis3.x单线程时代最经典的故障,大key删除的头疼问题,由于redis是单线程的,del bigKey …
等待很久这个线程才会释放,类似加了一个synchronized锁,你可以想象高并发下,程序堵成什么样子?

2.2.2 如何解决

使用惰性删除可以有效的避免 Redis 卡顿的问题。
比如当我(Redis)需要删除一个很大的数据时,因为是单线程同步操作,这就会导致 Redis 服务卡顿,于是在 Redis 4.0 中就新增了多线程的模块,当然此版本中的多线程主要是为了解决删除数据效率比较低的问题。

unlink key
flushdb async
flushall async
把删除工作交给了后台的小弟(子线程)异步来删除数据。
相当于在主线程中启动了一个子线程进行异步删除

因为Redis是单个主线程处理,redis之父antirez一直强调"Lazy Redis is better Redis"
lazy free的本质就是把某些花销(主要时间复制度,占用主线程cpu时间片)较高删除操作,从redis主线程剥离让bio子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题。
在Redis 4.0就引入了多个线程来实现数据的异步惰性删除等功能,但是其处理读写请求的仍然只有一个线程,所以仍然算是狭义上的单线程。

2.3 Redis6的多线程和IO多路复用(入门篇)

2.3.1 对于Redis主要的性能瓶颈是内存或者网络带宽而并非CPU

最后Redis的瓶颈可以初步定为:网络IO(redis6,真正多线程登场

2.3.2 Unix网络编程中的五种IO模型

Redis必须安装在linux环境下,因为只有Linux/UNIX环境中有epoll函数。

  • Blocking IO – 阻塞IO
  • NoneBlocking IO – 非阻塞IO
  • IO multiplexing -- IO多路复用
    • 这是IO模型的一种,即经典的Reactor设计模式。
    • IO多路复用,简单来说就是通过监测文件的读写事件再通知线程执行相关操作,保证Redis的非阻塞IO能过顺利执行完成的机制。
    • 多路指的是多个socket连接。
    • 复用指的是复用一个线程。多路复用主要有三种技术:select、poll、epoll。
      epoll是最新的也是目前最好的多路复用技术。采用多路IO复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。
  • signal driven IO – 信号驱动IO
  • asynchronous IO – 异步IO

2.3.3 简单说明:Redis工作线程是单线程。但是,整个Redis来说,是多线程的

I/O 的读和写本身是堵塞的,比如当 socket 中有数据时,Redis 会通过调用先将数据从内核态空间拷贝到用户态空间,再交给 Redis 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。

在 Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。

结合上图可知,网络IO操作就变成多线程化了,其他核心部分仍然是线程安全的,是个不错的折中办法。

2.3.4 结论

Redis 6.0 将网络数据读写、请求协议解析通过多个IO线程的来处理,对于真正的命令执行来说,仍然使用主线程操作,一举两得,便宜占尽!

2.4 Redis6.0默认是否开启了多线程?

Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,对于小数据包,Redis服务器可以处理8W到10W的QPS,这也是Redis处理的极限了,对于80%的公司来说,单线程的Redis已经足够使用了。

在Redis6.0中,多线程机制默认是关闭的,如果需要使用多线程功能,需要在redis.conf中完成两个设置:
在这里插入图片描述

参数说明:

  • io-threads-do-reads yes,表示启动多线程
  • io-threads设置线程个数
    • 官方的建议:如果为 4 核的 CPU,建议线程数设置为 2 或 3;如果为 8 核CPU 建议线程数设置为6
    • 注意:线程数一定要小于机器核数,线程数并不是越大越好。

2.5 总结

Redis自身出道就是优秀,基于内存操作、数据结构简单、多路复用和非阻塞 I/O、避免了不必要的线程上下文切换等特性,在单线程的环境下依然很快。

但对于大数据的 key 删除还是卡顿厉害,因此在 Redis 4.0 引入了多线程unlink key/flushall async 等命令,主要用于 Redis 数据的异步删除。

而在 Redis 6.0 中引入了 I/O 多线程的读写,这样就可以更加高效的处理更多的任务了,Redis只是将I/O读写变成了多线程,而命令的执行依旧是由主线程串行执行的,因此在多线程下操作 Redis 不会出现线程安全的问题。

Redis无论是当初的单线程设计,还是如今与当初设计相背的多线程,目的只有一个:让Redis变得越来越快。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值