为什么 Redis 单线程能达到百万+QPS?

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 性能测试报告查看了下阿里 Redis 的性能测试报告如下,能够达到数十万、百万级别的 QPS(暂时忽略阿里对 Redis 所做的优化),我们从 Redis 的设计和实现来分析一下 Redis 是怎么做的。

作者:在江湖中coding https://juejin.im/post/5e6097846fb9a07c9f3fe744


性能测试报告


查看了下阿里 Redis 的性能测试报告如下,能够达到数十万、百万级别的 QPS(暂时忽略阿里对 Redis 所做的优化),我们从 Redis 的设计和实现来分析一下 Redis 是怎么做的。

image.png

Redis的设计与实现


其实 Redis 主要是通过三个方面来满足这样高效吞吐量的性能需求


高效的数据结构


多路复用 IO 模型


事件机制


1、高效的数据结构

Redis 支持的几种高效的数据结构 string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)


以上几种对外暴露的数据结构它们的底层编码方式都是做了不同的优化的,不细说了,不是本文重点。


2、多路复用 IO 模型

假设某一时刻与 Redis 服务器建立了 1 万个长连接,对于阻塞式 IO 的做法就是,对每一条连接都建立一个线程来处理,那么就需要 1万个线程,同时根据我们的经验对于 IO 密集型的操作我们一般设置,线程数 = 2 * CPU 数量 + 1,对于 CPU 密集型的操作一般设置线程 = CPU 数量 + 1。


当然各种书籍或者网上也有一个详细的计算公式可以算出更加合适准确的线程数量,但是得到的结果往往是一个比较小的值,像阻塞式 IO 这也动则创建成千上万的线程,系统是无法承载这样的负荷的更加弹不上高效的吞吐量和服务了。


而多路复用 IO 模型的做法是,用一个线程将这一万个建立成功的链接陆续的放入 event_poll,event_poll 会为这一万个长连接注册回调函数,当某一个长连接准备就绪后(建立建立成功、数据读取完成等),就会通过回调函数写入到 event_poll 的就绪队列 rdlist 中,这样这个单线程就可以通过读取 rdlist 获取到需要的数据。为什么 Redis 是单线程,点击这里看下这篇文章。


另外,大家可以关注微信公众号:Java技术栈,在后台回复:redis,可以获取我整理的 N 篇 Redis 教程,都是干货。


需要注意的是,除了异步 IO 外,其它的 I/O 模型其实都可以归类为阻塞式 I/O 模型,不同的是像阻塞式 I/O 模型在第一阶段读取数据的时候,如果此时数据未准备就绪需要阻塞,在第二阶段数据准备就绪后需要将数据从内核态复制到用户态这一步也是阻塞的。而多路复用 IO 模型在第一阶段是不阻塞的,只会在第二阶段阻塞。


通过这种方式,就可以用 1 个或者几个线程来处理大量的连接了,极大的提升了吐吞量


image.png


3、事件机制


Redis 客户端与 Redis 服务端建立连接,发送命令,Redis 服务器响应命令都是需要通过事件机制来做的,如下图

image.png



首先 redis 服务器运行,监听套接字的 AE_READABLE 事件处于监听的状态下,此时连接应答处理器工作


客户端与 Redis 服务器发起建立连接,监听套接字产生 AE_READABLE 事件,当 IO 多路复用程序监听到其准备就绪后,将该事件压入队列中,由文件事件分派器获取队列中的事件交于连接应答处理器工作处理,应答客户端建立连接成功,同时将客户端 socket 的 AE_READABLE 事件压入队列由文件事件分派器获取队列中的事件交命令请求处理器关联


客户端发送 set key value 请求,客户端 socket 的 AE_READABLE 事件,当 IO 多路复用程序监听到其准备就绪后,将该事件压入队列中,由文件事件分派器获取队列中的事件交于命令请求处理器关联处理


命令请求处理器关联处理完成后,需要响应客户端操作完成,此时将产生 socket 的 AE_WRITEABLE 事件压入队列,由文件事件分派器获取队列中的事件交于命令恢复处理器处理,返回操作结果,完成后将解除 AE_WRITEABLE 事件与命令恢复处理器的关联


reactor模式


大体上可以说 Redis 的工作模式是,reactor 模式配合一个队列,用一个 serverAccept 线程来处理建立请求的链接,并且通过 IO 多路复用模型,让内核来监听这些 socket,一旦某些 socket 的读写事件准备就绪后就对应的事件压入队列中,然后 worker 工作,由文件事件分派器从中获取事件交于对应的处理器去执行,当某个事件执行完成后文件事件分派器才会从队列中获取下一个事件进行处理。


可以类比在 netty 中,我们一般会设置 bossGroup 和 workerGroup 默认情况下 bossGroup 为 1,workerGroup = 2 * cpu 数量,这样可以由多个线程来处理读写就绪的事件,但是其中不能有比较耗时的操作如果有的话需要将其放入线程池中,不然会降低其吐吞量。在 Redis 中我们可以看做这二者的值都是 1。


为什么说存储的值不宜过大


比如一个 string key = a,存储了 500MB,首先读取事件压入队列中,文件事件分派器从中获取到后,交于命令请求处理器处理,此处就涉及到从磁盘中加载 500MB。


比如是普通的 SSD 硬盘,读取速度 200MB/S,那么需要 2.5S 的读取时间,在内存中读取数据比较快比如 DDR4 中 50G/秒,读取 500MB 需要 100 毫秒左右。


线程的库一般默认 10 毫秒就算慢查询了,大部分的指令执行时间都是微秒级别,此时其它 socket 所有的请求都将处于等待过程中,就会导致阻塞了 100 毫秒,同时又会占用较大的带宽导致吞吐量进一步下降。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 缓存 NoSQL
Redis单线程已经很快了6.0引入多线程
Redis单线程已经很快了6.0引入多线程
31 3
|
8月前
|
NoSQL Unix Linux
Redis核心技术与实践 03 | 高性能IO模型:为什么单线程Redis能那么快?
Redis核心技术与实践 03 | 高性能IO模型:为什么单线程Redis能那么快?
|
4月前
|
NoSQL 网络协议 Linux
Redis单线程源码深入解析
Redis单线程源码深入解析
|
10天前
|
存储 缓存 NoSQL
为什么Redis使用单线程 性能会优于多线程?
在计算机领域,性能一直都是一个关键的话题。无论是应用开发还是系统优化,我们都需要关注如何在有限的资源下,实现最大程度的性能提升。Redis,作为一款高性能的开源内存数据库,因其出色的单线程性能而备受瞩目。那么,为什么Redis使用单线程性能会优于多线程呢?
21 1
|
3月前
|
存储 消息中间件 缓存
Redis是否为单线程?
【2月更文挑战第6天】
40 1
Redis是否为单线程?
|
5月前
|
缓存 NoSQL Linux
知乎上高频提问:Redis到底是单线程还是多线程程序?
这里我们先给出问题的全面回答:`Redis`到底是多线程还是单线程程序要看是针对哪个功能而言,**对于核心业务功能部分(命令操作处理数据),Redis是单线程的,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程,所以一般我们认为Redis是个单线程程序。但是从整个框架层面出发严格来说Redis是多线程的。**
65 0
知乎上高频提问:Redis到底是单线程还是多线程程序?
|
6月前
|
NoSQL 算法 安全
Redis为什么是单线程的
Redis为什么是单线程的
|
6月前
|
存储 移动开发 缓存
单线程 Redis 如此快的 4 个原因
为什么 Redis 单线程设计会带来如此高的性能?如果利用多个线程并发处理请求不是更好吗? 在本文中,我们将探讨使 Redis 成为快速高效的数据存储的设计选择。
142 2
|
6月前
|
存储 NoSQL 中间件
GitHub数据库榜单第一:Redis核心原理实践PDF,点赞已过百万+
Redis是互联网技术领域使用最为广泛的存储中间件,它是「Remote DictionaryService」的首字母缩写,也就是「远程字典服务」。Redis 以其超高的性能、完美的文档、简洁易懂的源码和丰富的客户端库支持在开源中间件领域广受好评。国内外很多大型互联网公司都在使用Redis, 比如Twitter、YouPom、暴雪娱乐、Github、StackOverflow、 腾讯、阿里、京东、华为、新浪微博等等,很多中小型公司也都有应用。也可以说,对Redis的了解和应用实践已成为当下中高级后端开发者绕不开的必备技能。
|
7月前
|
NoSQL Redis
Redis的线程模型,单线程为啥那么快
Redis的线程模型,单线程为啥那么快
25 0