Redis线程

88 阅读4分钟

Redis4.0前都是单线程,4.0后开始出现多线程

image.png

单线程时代

Redis3.X单线程时代依旧能很快的原因

  1. 基于内存操作: Redis 的所有数据都存在内存中,因此所有的运算都是内存级别的,所以他的性能比较高
  2. 数据结构简单:Redis 的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是 O(1),因此性能比较高
  3. 多路复用和非阻塞 I/O:Redis使用I/0多路复用功能来监听多个socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,同时也避免了I/O阻塞操作
  4. 避免上下文切换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了 多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生

Redis单线程时的缺陷

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

这就是redis3.x单线程时代最经典的故障,大key删除的头疼问题,

由于redis是单线程的,del bigKey ..... 等待很久这个线程才会释放,类似加了一个synchronized锁,可以想象高并发下,程序堵成什么样子?

解决办法

Redis4.0时代为了解决删除数据效率低这个问题,引入了多线程(此时多线程主要是解决删除数据的问题)

惰性删除

  • 不用del删大key,用unlink key
  • flushdb async 异步清除
  • flushall async 把删除工作交给了子线程异步删除数据

lazy free的本质就是把某些cost(主要时间复制度,占用主线程cpu时间片)较高删除操作,从redis主线程剥离让bio(非阻塞)子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题

Redis性能影响因素

影响Redis性能的主要是内存和网络IO,而不是CPU

多线程时代

在Redis6/7中,非常受关注的第一个新特性就是多线程。

这是因为,Redis一直被大家熟知的就是它的单线程架构,虽然有些命今操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF重写)但是,从网络IO处理到实际的读写命令处理,都是由单个线程完成的。

随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络1O的处理上,也就是说,单个主线程处理网络请求的速度跟不上底层网络硬件的速度,

为了应对这个问题:

采用多个IO线程来处理网络请求,提高网络请求处理的并行度,Redis6/7就是采用的这种方法。

但是,Redis的多I0线程只是用来处理网络请求的,对于读写操作命令(set get)Redis仍然使用单线程来处理。这是因为,Redis处理请求时,网络处理经常是瓶颈,通过多个IO线程并行处理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为了保证Lua脚本、事务的原了性,额外开发多线程互斥加锁机制了(不管加锁操作处理),这样一来,Redis线程模型实现就简单了

image.png

image.png

网络编程中的五种IO模型

  1. Blocking IO (阻塞IO)
  2. NoneBlocking IO (非阻塞IO)
  3. IO multiplexing (IO多路复用)
  4. signal driven IO(信号驱动IO)
  5. asynchronous IO (异步IO)

IO多路复用概念

一种同步的IO模型,实现*一个线程监视多个文件句柄。一旦某个文件句柄就绪就能够通知到对应应用程序进行相应的读写操作,没有文件句柄就绪时就会阻塞应用程序从而释放CPU资源

image.png

image.png

image.png