(八)Redis 主从复制、切片集群
一、主从复制
1、主从关系
都说的 Redis 具有高可靠性,这里有两层含义:一是数据尽量少丢失,二是服务尽量少中断。AOF 和 RDB 保证了前者,而对于后者,Redis 的做法就是将一份数据同时保存在多个实例上。为了保证数据一致性,Redis 提供了主从库模式,并采用读写分离的方式,如图

2、主从复制-全量
当启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系。例如,让实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5)成为主从关系的命令:replicaof 172.16.19.3 6379,当关系建立后,第一次同步分数据为三个阶段:
(1)从库给主库发送 psync 命令,表示要进行数据同步,包含主库的 runID(redis 实例启动生成的随机 ID) 和复制进度 offset 两个参数,初次复制runID 为 ?offset 为 -1,主库会用 FULLRESYNC(初次为全量复制)响应命令带上两个参数返回给从库,从库收到响应后会记录 runID、offset 两个参数。
(2)主库执行 bgsave 命令,生成 RDB 文件并发给从库,从库会先清空当前数据库,然后加载 RDB 文件。这个过程中主库不会被阻塞,为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。
(3)主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。

3、主从复制-级联
全量复制中,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件,如果从库数量很多,主线程忙于 fork 子进程生成 RDB 文件会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢。此外,传输 RDB 文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力。
我们可以通过“主-从-从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上,从而降低主库的压力。简单来说,我们在部署主从集群的时候,可以手动选择一个从库(比如选择内存资源配置较高的从库),用于级联其他的从库,相当于选择一个从库当做其他从库的主库,执行replicaof 所选从库IP 6379,建立关系。

主从复制完成后,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,可以避免频繁建立连接的开销。
4、网络问题
网络中断后,主从库会采用增量复制的方式把主从库网络断连期间主库收到的命令同步给从库,期间命令会写入 replication buffer 以及 repl_backlog_buffer 缓冲区。这是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。
起初,两个位置是相同的,但随着主库不断接收新的写操作,缓冲区中的写位置会逐步偏离起始位置,通常用偏移量来衡量这个偏移距离的大小,偏移越多,master_repl_offset 越大。
当主从库的连接恢复,从库首先会给主库发送 psync 命令把自己当前的 slave_repl_offset 发给主库,主库根据 master_repl_offset 和 slave_repl_offset 之间的差距,形成命令发送给从库进行数据同步。

需要强调的是,因为 repl_backlog_buffer 是一个环形缓冲区,所以在缓冲区写满后,主库会继续写入,此时,就会覆盖掉之前写入的操作。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。
我们可以调整 repl_backlog_size 这个参数来设置缓冲空间大小。计算公式是:缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小。在实际应用中,我们可以扩大一定倍数应对突发的请求压力。
如果并发请求量非常大,除了适当增加 repl_backlog_size 值,就需要考虑使用切片集群来分担单个主库的请求压力了。
二、切片集群
在使用 RDB 持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长,会导致 Redis 响应变慢。我们使用 INFO 命令查看 Redis 的 latest_fork_usec 指标值(表示最近一次 fork 的耗时)。所以当数据量持续增长时,通过扩大内存的方式不太适用,应该采用切片集群。
切片集群,也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。例如把 25GB 的数据平均分成 5 份(当然,也可以不做均分),使用 5 个实例来保存,每个实例只需要保存 5GB 数据。实例在为 5GB 数据生成 RDB 时,数据量就小了很多,fork 子进程一般不会给主线程带来较长时间的阻塞。
加大内存、切片集群,两种方法对应的就是 纵向扩展(scale up)和横向扩展(scale out):
(1)纵向扩展:升级单个 Redis 实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的 CPU。
(2)横向扩展:横向增加当前 Redis 实例的个数。
纵向扩展的好处是,实施起来简单、直接,但是受限于数据量增加带来的阻塞问题和硬件成本问题。与纵向扩展相比,横向扩展是一个扩展性更好的方案,要想保存更多的数据,只用增加 Redis 的实例个数就行了,相对的管理起来会复杂一点。
我们就需要解决两大问题:
(1)数据切片后,在多个实例之间如何分布?
(2)客户端怎么确定想要访问的数据在哪个实例上?
Redis 切片集群通常是通过 Redis Cluster 来实现的,用哈希槽(Hash Slot,接下来我会直接称之为 Slot),来处理数据和实例之间的映射关系,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。先根据键值对的 key 按照 CRC16 算法 计算一个 16 bit 的值,然后再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。
使用 cluster create 命令创建集群时,Redis 会自动把这些槽平均分布在集群实例上,每个实例上的槽个数为 16384/N 个。也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数。举个栗子,假设3个实例,5个哈希槽,根据实例内存情况,按下图配置:
redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4
key1 和 key2 计算完 CRC16 值后,对哈希槽总个数 5 取模,再根据各自的模数结果,就可以被映射到对应的实例 1 和实例 3 上了,这个过程就完成了数据分布的问题。(注意:手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作)
集群创建后,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端,客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。
但是,在集群中,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:
(1)在集群中,实例有新增或删除,Redis 需要重新分配哈希槽
(2)为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍
实例之间可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致。Redis Cluster 方案提供了一种重定向机制,所谓的“重定向”,就是指,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据的话,会返回 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址,客户端重定向到新实例,同时更新本地对应关系的缓存。
GET hello:key
(error) MOVED 13320 172.16.19.5:6379
在实际应用时,如果正好赶上实例数据正在迁移,访问的 Slot 2 中的数据只有一部分迁移到了实例 3,还有部分数据没有迁移。这种情况下,客户端就会收到一条 ASK 报错信息:
GET hello:key
(error) ASK 13320 172.16.19.5:6379
这表明客户端请求的键值对所在的哈希槽 13320,在 172.16.19.5 这个实例上,但是这个哈希槽正在迁移,客户端需要先给 172.16.19.5 这个实例发送一个 ASKING 命令,让这个实例允许执行客户端接下来发送的命令。然后,客户端再向这个实例发送 GET 命令,以读取数据。举个例子如图:

Slot 2 正在从实例 2 往实例 3 迁移,key1 和 key2 已经迁移过去,key3 和 key4 还在实例 2。客户端向实例 2 请求 key2 后,就会收到实例 2 返回的 ASK 命令。然后给实例 3 发送 ASKING 命令,才能读取 key2 的数据。注意,和 MOVED 命令不同,ASK 命令并不会更新客户端缓存的哈希槽分配信息,如果客户端再次请求 Slot 2 中的数据,它还是会给实例 2 发送请求,重复上述步骤。
(八)Redis 主从复制、切片集群的更多相关文章
- Redis进阶实践之十 Redis主从复制的集群模式
一.引言 Redis的基本数据类型,高级特性,与Lua脚本的整合等相关知识点都学完了,说是学完了,只是完成了当前的学习计划,在以后的时间还需继续深入研究和学习.从今天开始来讲一下有关Re ...
- Redis实战——redis主从复制和集群实现原理
出自:https://blog.csdn.net/nuli888/article/details/52136822 redis主从复制redis主从配置比较简单,基本就是在从节点配置文件加上:slav ...
- 搭建Redis主从复制的集群
在主从复制模式的集群里,主节点一般是一个,从节点一般是两个或多个,写入主节点的数据会被复制到从节点上,这样一旦主节点出现故障,应用系统能切换到从节点去读写数据,这样能提升系统的可用性.而且如果再采用主 ...
- redis 主从复制 和集群
redis集群最少三个节点 之间相互通信ping-pong 投票选举机制 主从复制 的话 最少六个节点 ,主三从三
- redis主从、集群、哨兵
redis的主从.集群.哨兵 参考: https://blog.csdn.net/robertohuang/article/details/70741575 https://blog.csdn.net ...
- Redis 切片集群的数据倾斜分析
Redis 中如何应对数据倾斜 什么是数据倾斜 数据量倾斜 bigkey导致倾斜 Slot分配不均衡导致倾斜 Hash Tag导致倾斜 数据访问倾斜 如何发现 Hot Key Hot Key 如何解决 ...
- Redis 高可用集群
Redis 高可用集群 Redis 的集群主从模型是一种高可用的集群架构.本章主要内容有:高可用集群的搭建,Jedis连接集群,新增集群节点,删除集群节点,其他配置补充说明. 高可用集群搭建 集群(c ...
- Redis进阶实践之十二 Redis的Cluster集群动态扩容
一.引言 上一篇文章我们一步一步的教大家搭建了Redis的Cluster集群环境,形成了3个主节点和3个从节点的Cluster的环境.当然,大家可以使用 Cluster info 命令查看Cl ...
- 超详细的 Redis Cluster 官方集群搭建指南
今天从 0 开始搭建 Redis Cluster 官方集群,解决搭建过程中遇到的问题,超详细. 安装ruby环境 因为官方提供的创建集群的工具是用ruby写的,需要ruby2.2.2+版本支持,rub ...
- redis整合Spring集群搭建及业务中的使用
1.redis安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: 第一步:redis的源码包上传到li ...
随机推荐
- 【规范】Git分支管理,看看我司是咋整的
前言 缘由 Git分支管理好,走到哪里都是宝 事情起因: 最近翻看博客中小伙伴评论时,发现文章[规范]看看人家Git提交描述,那叫一个规矩一条回复: 本狗亲测在我司中使用规范的好处,遂把我司的Git分 ...
- MinIO使用记录
探索MinIO:高性能.分布式对象存储解决方案 注:本文除代码外多数为AI生成 最近因为有项目需要换成Amazon S3的云存储,所以把之前做过的minio部分做一个记录,后面也会把基于这版改造的S3 ...
- C#开发单实例应用程序并响应后续进程启动参数
C#默认的WinForm模板是不支持设置单实例的,也没有隔壁大哥VB.NET那样有个"生成单个实例应用程序"的勾选选项(VB某些时候要比C#更方便),实现单实例可以有多种方法: 检 ...
- CentOS7离线安装devtoolset-9并编译redis6.0.5
首先参照https://www.cnblogs.com/wdw984/p/13330074.html,来进行如何安装Centos和离线下载rpm包. 离线下载jemalloc,上传到CentOS的/d ...
- oeasy 教您玩转 linux 010214 画面转文字 asciiview
- mysql面试汇总
最近一直在关注mysql方面的面试题目,并且从最近的面试情况来看,mysql在java后端的面试中,肯定是必问的题目,所以这里有必要对这块的内容进行总结,大家可以根据下面的导图进行重点复习, 引擎 1 ...
- scratch少儿编程卡通三国背景72张全套素材包【免费下载】
scratch卡通三国题材背景图片,共72张,让你轻松打造scratch三国世界! 免费下载地址:https://www.xiaohujing.com.cn 这套背景图片以卡通风格呈现,色彩鲜艳.造型 ...
- TCP和KCP协议
TCP协议 KCP是一个快速可靠协议,能以比 TCP 浪费 10%-20% 的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果.纯算法实现,并不负责底层协议(如UDP)的收发 ...
- 买卖股票相关算法-动态规划-python
要求1: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格. 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票.设计 ...
- 10、Git之国内项目托管平台(Gitee码云)
10.1.简介 众所周知,GitHub 服务器在国外,如果网络不好的话,严重影响使用体验,甚至会出现登录不上的情况. 针对这个情况,可以使用国内的项目托管平台-- Gitee 码云,来替代 Githu ...