redis 如何通过读写分离来承载读请求 QPS 超过 10 万 +?
首先我们来聊一下QPS
关于高并发程序的几个重要概念
吞吐量(TPS)、QPS、并发数、响应时间(RT)
QPS
原理:每天80%的访问集中在20%的时间里,这20%时间叫做峰值时间。
公式:( 总PV数 * 80% ) / ( 每天秒数 * 20% ) = 峰值时间每秒请求数(QPS) 。
机器:峰值时间每秒QPS / 单台机器的QPS = 需要的机器 。
每天300w PV 的在单台机器上,这台机器需要多少QPS?
( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)。
一般需要达到139QPS,因为是峰值。
若百亿级数据 QPS为462,962。
QPS
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
每秒查询率
因特网上,经常用每秒查询率来衡量域名系统服务器的机器的性能,其即为QPS。
对应fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。
计算机语言
一种计算机编程语言。用于数据分析和报表产出。运作的平台是MRDCL。支持的数据文件包括ASC格式和CSI格式。
其中CSI格式为QPS独有数据格式。是极其专业的用于数据分析、数据清理和报表产出的语言,目前应用最广的是市场调研行业。中国国内运用的相对比较少。
开发的原因,需要对吞吐量(TPS)、QPS、并发数、响应时间(RT)几个概念做下了解,查自百度百科,记录如下:
1. 响应时间(RT)
响应时间是指系统对请求作出响应的时间。直观上看,这个指标与人对软件性能的主观感受是非常一致的,因为它完整地记录了整个计算机系统处理请求的时间。由于一个系统通常会提供许多功能,而不同功能的处理逻辑也千差万别,因而不同功能的响应时间也不尽相同,甚至同一功能在不同输入数据的情况下响应时间也不相同。所以,在讨论一个系统的响应时间时,人们通常是指该系统所有功能的平均时间或者所有功能的最大响应时间。当然,往往也需要对每个或每组功能讨论其平均响应时间和最大响应时间。
对于单机的没有并发操作的应用系统而言,人们普遍认为响应时间是一个合理且准确的性能指标。需要指出的是,响应时间的绝对值并不能直接反映软件的性能的高低,软件性能的高低实际上取决于用户对该响应时间的接受程度。对于一个游戏软件来说,响应时间小于100毫秒应该是不错的,响应时间在1秒左右可能属于勉强可以接受,如果响应时间达到3秒就完全难以接受了。而对于编译系统来说,完整编译一个较大规模软件的源代码可能需要几十分钟甚至更长时间,但这些响应时间对于用户来说都是可以接受的。
2. 吞吐量(Throughput)
吞吐量是指系统在单位时间内处理请求的数量。对于无并发的应用系统而言,吞吐量与响应时间成严格的反比关系,实际上此时吞吐量就是响应时间的倒数。前面已经说过,对于单用户的系统,响应时间(或者系统响应时间和应用延迟时间)可以很好地度量系统的性能,但对于并发系统,通常需要用吞吐量作为性能指标。
对于一个多用户的系统,如果只有一个用户使用时系统的平均响应时间是t,当有你n个用户使用时,每个用户看到的响应时间通常并不是n×t,而往往比n×t小很多(当然,在某些特殊情况下也可能比n×t大,甚至大很多)。这是因为处理每个请求需要用到很多资源,由于每个请求的处理过程中有许多不走难以并发执行,这导致在具体的一个时间点,所占资源往往并不多。也就是说在处理单个请求时,在每个时间点都可能有许多资源被闲置,当处理多个请求时,如果资源配置合理,每个用户看到的平均响应时间并不随用户数的增加而线性增加。实际上,不同系统的平均响应时间随用户数增加而增长的速度也不大相同,这也是采用吞吐量来度量并发系统的性能的主要原因。一般而言,吞吐量是一个比较通用的指标,两个具有不同用户数和用户使用模式的系统,如果其最大吞吐量基本一致,则可以判断两个系统的处理能力基本一致。
3. 并发用户数
并发用户数是指系统可以同时承载的正常使用系统功能的用户的数量。与吞吐量相比,并发用户数是一个更直观但也更笼统的性能指标。实际上,并发用户数是一个非常不准确的指标,因为用户不同的使用模式会导致不同用户在单位时间发出不同数量的请求。一网站系统为例,假设用户只有注册后才能使用,但注册用户并不是每时每刻都在使用该网站,因此具体一个时刻只有部分注册用户同时在线,在线用户就在浏览网站时会花很多时间阅读网站上的信息,因而具体一个时刻只有部分在线用户同时向系统发出请求。这样,对于网站系统我们会有三个关于用户数的统计数字:注册用户数、在线用户数和同时发请求用户数。由于注册用户可能长时间不登陆网站,使用注册用户数作为性能指标会造成很大的误差。而在线用户数和同事发请求用户数都可以作为性能指标。相比而言,以在线用户作为性能指标更直观些,而以同时发请求用户数作为性能指标更准确些。
4. QPS每秒查询率(Query Per Second)
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。对应fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。 (看来是类似于TPS,只是应用于特定场景的吞吐量)
redis 高并发跟整个系统的高并发之间的关系
搞高并发的话,不可避免的要把底层的缓存搞得很好,这里就是 redis
使用 mysql 来支撑高并发的话,就算做到了,那么也是通过一系列复杂的分库分表方案。订单系统中是有事务要求的,QPS 到几万,就已经比较高了,很难提升上去了
要做一些电商的商品详情页,真正的超高并发,QPS 上十万,甚至是百万,一秒钟百万的请求量
光是 redis 是不够的,但是 redis 是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节
首先,你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构的设计(多级缓存架构、热点缓存),支撑真正的上十万,甚至上百万的高并发
redis 不能支撑高并发的瓶颈在哪里?
就是 单机
单机 redis 一般情况下能够承载的 QPS 上万到几万不等,根据你的业务操作的复杂性, redis 提供很多复杂的操作,如 lua 脚本等复杂的操作,那么可能会更低。 比如就简单的 kv 查询来说还是比较容易达到上万的。
假设有上千万、上亿的用户来访问,直接就能把你的单机 redis 干宕机
如果 redis 要支撑超过 10万+ 的并发,那应该怎么做?
单机的 redis 几乎不太可能 QPS 超过 10万+,除非一些特殊情况,比如你的机器性能特别好,配置特别高,真实物理机,维护做的特别好,而且你的整体的操作不是太复杂
单机在一般就几万。要提高并发,一般的方案是 读写分离,一般来说,对缓存,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就一秒钟几千,一两千,大量的请求都是读,一秒钟二十万次读
也就是 读多写少 的情况下才能用缓存。写多读少可以选择使用异步写
如上图,一主多从,主负责写,并且将数据同步复制到其他 slave 节点,从节点负责读,还可水平扩展 slave 节点以支撑更多的 QPS
主从架构 -> 读写分离 -> 支撑 10万+ 读 QPS 的架构
接下来要讲解的就是怎么实现 redis 的主从架构。
redis replication 以及 master 持久化对主从架构的安全意义
redis 高并发的思路:redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑高并发
本章节主要讲解 redis replication 的最最基本的原理,作为铺垫
图解 redis replication 基本原理
在前一章节基本上已经讲过了,如上图差不多。写操作成功之后,会异步的把数据复制到 slave 上
redis replication 的核心机制
- redis 采用异步方式复制数据到 slave 节点
不过 redis 2.8 开始,slave node 会周期性地确认自己每次复制的数据量 - 一个 master node 是可以配置多个 slave node 的
- slave node 也可以连接其他的 slave node
- slave node 做复制的时候,是不会 block master node 的正常工作的
- slave node 在做复制的时候,也不会 block 对自己的查询操作
它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了 - slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量
实现高可用性 slave 有很大的关系,后面会讲解
master 持久化对于主从架构的安全保障的意义
如果采用了主从架构,那么建议必须开启 master node 的持久化!
很简单的道理,master 提供写,它自己的数据是最完整的,所以需要它自己来做持久化。
如果不使用 master 做持久化的冷备,而采用 slave 来做冷备的话,当 master 死机再重启,因为自己本地没有数据,会将空的数据同步到所有的 slave 上去。
其次 master 的各种备份方案,要不要做,万一说本地的所有文件丢失了; 从备份中挑选一份 rdb 去恢复 master; 这样才能确保 master 启动的时候,是有数据的
后面会讲解哨兵(sentinal)高可用机制,即使采用了该高可用机制,slave node 可以自动接管 master node,但是也可能 sentinal 还没有检测到 master failure,master node 就自动重启了,还是可能导致上面的所有 slave node 数据清空故障
总结:
- master 持久化开启
- 冷备方案一定要做(之前讲解的定时备份的方案)
redis 主从复制原理、断点续传、无磁盘化复制、过期 key 处理
主从架构的核心原理
当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node,
- 如果是重新连接:master node 仅仅会复制给 slave 部分缺少的数据;
- 如果是首次连接:会触发一次 full resynchronization(全量同步)
开始 full resynchronization 的时候,master 会启动一个后台线程,开始生成一份 RDB 快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB 文件生成完毕之后,master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后 master 会将内存中缓存的写命令发送给 slave,slave 也会同步这些数据。
slave node 如果跟 master node 有网络故障,断开了连接,会自动重连。master如果发现有多个 slave node 都来重新连接,仅仅会启动一个 rdb save 操作,用一份数据服务所有 slave node。
在正常情况下异步复制会很简单,来一条,异步复制一条
主从复制的断点续传
从 redis 2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node 会在内存中创建一个 backlog,master 和 slave 都会保存一个 replica offset 和 master id,offset 就是保存在 backlog 中的。如果 master 和 slave 网络连接断掉了,slave 会让 master 从上次的 replica offset 开始继续复制,但是如果没有找到对应的 offset,那么就会执行一次 resynchronization
无磁盘化复制
master 在内存中直接创建 rdb,然后通过网络发送给 slave,不会在自己本地落地磁盘了
该功能是通过配置文件配置的,主要涉及到以下两个参数:
- repl-diskless-sync:无磁盘同步 默认为 no(关闭状态)
- repl-diskless-sync-delay:等待一定时长再开始复制,因为要等更多 slave 重新连接过来
过期 key 处理
- slave 不会过期 key
- 只会等待 master 过期 key。
如果 master 过期了一个 key,或者通过 LRU 淘汰了一个 key,那么会模拟一条 del 命令发送给 slave。