探究 | 谁再说Redis慢,我跟谁急( 四 )


针对建立连接请求事件 , 通过 Acceptor 处理 , 并建立对应的 handler 负责后续业务处理 。
针对非连接事件 , Reactor 会调用对应的 handler 完成 read→业务处理→write 处理流程 , 并将结果返回给客户端 。
整个过程都在一个线程里完成:
探究 | 谁再说Redis慢,我跟谁急文章插图
单线程时代
了解了 Reactor 模式后 , 你可能会有一个疑问 , 这个和我们今天的主题有什么关系呢 。 可能你不知道的是 , Redis 是基于 Reactor 单线程模式来实现的 。
IO多路复用程序接收到用户的请求后 , 全部推送到一个队列里 , 交给文件分派器 。
对于后续的操作 , 和在 Reactor 单线程实现方案里看到的一样 , 整个过程都在一个线程里完成 , 因此 Redis 被称为是单线程的操作 。
探究 | 谁再说Redis慢,我跟谁急文章插图
对于单线程的 Redis 来说 , 基于内存 , 且命令操作时间复杂度低 , 因此读写速率是非常快的 。
多线程时代
Redis6 版本中引入了多线程 。 上边已经提到过 Redis 单线程处理有着很快的速度 , 那为什么还要引入多线程呢?单线程的瓶颈在什么地方?
我们先来看第二个问题 , 在 Redis 中 , 单线程的性能瓶颈主要在网络IO操作上 。
也就是在读写网络 read/write 系统调用执行期间会占用大部分 CPU 时间 。 如果你要对一些大的键值对进行删除操作的话 , 在短时间内是删不完的 , 那么对于单线程来说就会阻塞后边的操作 。
回想下上边讲得 Reactor 模式中单线程的处理方式 。 针对非连接事件 , Reactor 会调用对应的 handler 完成 read→业务处理→write 处理流程 , 也就是说这一步会造成性能上的瓶颈 。
Redis 在设计上采用将网络数据读写和协议解析通过多线程的方式来处理 , 对于命令执行来说 , 仍然使用单线程操作 。
总结
基于内存实现:

  • 数据都存储在内存里 , 减少了一些不必要的 I/O 操作 , 操作速率很快 。
高效的数据结构:
  • 底层多种数据结构支持不同的数据类型 , 支持 Redis 存储不同的数据 。
  • 不同数据结构的设计 , 使得数据存储时间复杂度降到最低 。
合理的数据编码:
  • 根据字符串的长度及元素的个数适配不同的编码格式 。
合适的线程模型:
  • I/O 多路复用模型同时监听客户端连接;
  • 单线程在执行过程中不需要进行上下文切换 , 减少了耗时 。
Reactor 模式:
  • 传统阻塞 IO 模型客户端与服务端线程 1:1 分配 , 不利于进行扩展 。
  • 伪异步 IO 模型采用线程池方式 , 但是底层仍然使用同步阻塞方式 , 限制了最大连接数 。
  • Reactor 通过 I/O 复用程序监控客户端请求事件 , 通过任务分派器进行分发 。
单线程时代:
  • 基于 Reactor 单线程模式实现 , 通过 IO 多路复用程序接收到用户的请求后 , 全部推送到一个队列里 , 交给文件分派器进行处理 。
多线程时代:
  • 单线程性能瓶颈主要在网络 IO 上 。
  • 将网络数据读写和协议解析通过多线程的方式来处理, 对于命令执行来说 , 仍然使用单线程操作 。
作者:小莱 , 一枚后端工程师
编辑:陶家龙
【探究 | 谁再说Redis慢,我跟谁急】出处:转载自公众号IT界农民工(ID:kejishuqian)