Redis一站式指南二:主从模式高效解决分布式系统“单点问题”
一.分布式系统的 “单点问题”核心矛盾要是服务器程序只靠一个物理服务器节点撑着会有大麻烦可用性差这台机器一挂服务直接断用户就用不了了比如网站直接打不开 。性能有限一个服务器能扛的并发请求少访问量大时就 “扛不住”卡到崩溃 。解决思路用分布式系统把任务拆给多台服务器避免 “单点依赖”让服务更稳、性能更强1.1Redis 集群的作用分布式系统里常把多个服务器部署 Redis组成Redis 集群好处很直接让 Redis 能存更多数据、扛更高并发给其他服务比如网站、APP 后台 提供更稳、更快的数据存储 。说白了以前一个 Redis 服务器 “单打独斗” 容易崩现在一群 Redis 服务器 “组队”抗造又高效二.主从模式为了让 Redis 集群更灵活有几种经典玩法主从模式核心逻辑选一台当 “主服务器Master”其他当 “从服务器Slave”。主负责写数据从负责同步主的数据、处理读请求 。好处读请求分散到从服务器减轻主的压力主挂了理论上能手动切从当主但需要人工干预 。主从 哨兵模式核心逻辑在 “主从模式” 基础上加几个 “哨兵Sentinel”。哨兵专门盯着主服务器一旦主挂了哨兵能自动选新的主不用人工插手 。好处解决主从模式 “主挂了没人管” 的问题自动切换更智能、更稳 。集群模式Cluster核心逻辑把多台 Redis 服务器分成 “分片”数据分散存在不同分片里。比如按 key 的哈希值把数据分到不同服务器并发处理能力更强 。好处支持超大规模数据存储还能自动分片、自动容错某台服务器挂了其他分片继续干活 是最常用的 “分布式 Redis” 方案 。2.1 基本概念在若干个 redis 节点中有的是 “主” 节点有的是 “从” 节点假设有三个物理服务器称为三个节点分别部署一个 redis-server 进程此时可以把其中一个节点作为 “主节点”另外两个作为 “从节点”从节点规则从节点得听主节点的从节点数据要跟随主节点变化保持一致本来主节点保存一堆数据引入从节点后主节点的数据会复制到从节点中.后续主节点修改数据都会同步到从节点上从节点是主节点的副本从节点的限制Redis 主从模式中从节点数据不允许修改只能读取数据主从模式的目标主要针对 “读操作”提高并发量 可用性写操作依赖主节点主节点不能多个 但实际业务中读操作更频繁所以主从模式能缓解压力2.2 可用性与风险单个节点的问题之前单个 redis 服务器挂了整个 redis 就挂了主从结构的优势这些 redis 机器不太可能 “同时挂”但整个机房可能被 “一锅端”异地多活可解决 节点挂掉的影响挂掉从节点没啥影响客户端继续从主 / 其他从节点读数据.挂掉主节点从节点只能读无法写数据可用性提高但未到理想程度 多个主节点的麻烦一山不容二虎两个主节点同步数据会很复杂所以主从模式一般只有一个主节点2.3 配置步骤前提需要启动多个 redis 服务器正常每个 redis 服务器应在单独主机分布式 但如果只有一个云服务器时可在一个主机运行多个 redis-server 进程通过不同端口区分 主从复制在一个服务器使用三个进程设置一个主节点两个从节点端口号638063811.创建一个文件夹rootLHY:~# mkdir redis-conf2.拷贝两份slave1.conf,slave2.confredis配置文件rootLHY:~# cp /etc/redis/redis.conf ./slave1.conf rootLHY:~# cp /etc/redis/redis.conf ./slave2.conf4.进入redis-conf文件夹打开slave1.conf配置文件rootLHY:~# cd redis-conf/ rootLHY:~/redis-conf# vim slave1.conf5.修改端口6.修改进程可以在后台方式运行其实还要默认修改主机ip地址和保护模式关闭但是已在主配置修改slave2.conf文件步骤一样9.启动6380进程6381但是三个节点是相互独立的没有主从结构的联系还要进一步配置11.进入slave1.conslave2.conff配置命令模式按G可直接到达文件末尾噢# 主从结构配置 slaveof 127.0.0.1 637912.redis配置文件要重新启动才生效现在这台机器上有三个 Redis 实例同时在跑端口PID配置文件来源6379363238默认主节点6380889894slave1.conf6381889900slave2.conf6380 和 6381 已经和 6379 建立了连接ESTABLISHED是主从复制链路。13.测试是否连接有效那从节点能否执行写操作呢不行15.主节点查看信息结构信息查看主从结构信息info replication6379 是主节点role:master有 2 个从节点slave0 → 127.0.0.1:6380slave1 → 127.0.0.1:6381状态都是 onlineoffsezh45说明数据同步正常lag0 或 lag1 表示延迟几乎没有查看子节点结构信息info replicationrole:slave → 身份是从节点master_host:127.0.0.1 / master_port:6379 → 正在跟 6379 同步master_link_status:up → 主从连接正常master_sync_in_progress:0 → 同步任务已完成slave_read_only:1 → 从节点是只读的Redis 默认如此slave_repl_offset 和 master_repl_offset 一致 → 数据已经完全同步2.4 断开和修改主从结构断开命令slaveof on oneslaveof no one (直接在 redis 客户端中的命令)直接使用这个命令断开现有的主从复制关系。从节点断开主从关系, 它就不再从属于其他节点了, 里面已经有的数据, 是不会抛弃的!!但是,后续主节点如果针对数据做出修改, 从节点就无法再自动同步数据了.修改主从结构刚才通过 slaveof 是修改了主从结构此处的修改是临时性的.如果重新启动了 redis 服务器, 仍然会按照最初在配置文件中设置的内容来建立主从关系主从复制 是从主节点到从节点不能 从从节点 到 主节点 。如果从节点允许修改, 后续对于从节点的修改, 主节点是感知不到的. 数据就不一致了。通俗解读修改的临时性当你用slaveof命令去调整主从结构比如让某个节点换个主节点或者像slaveof no one这样断开关系 这种修改只是临时生效。要是把 Redis 服务器重启了它会回到配置文件里最初设置的主从关系。举个例子你配置文件里写好了 6379 是主节点6380 是从节点你临时用命令让 6380 断开了和 6379 的关系可一旦重启 Redis6380 又会自动作为从节点连接到 6379 那里 。主从复制方向主从复制的方向是单向的只能是主节点把数据同步给从节点而不能反过来让从节点把数据同步给主节点 。数据不一致风险要是从节点允许被修改数据实际正常主从模式里从节点默认是不能修改的这里是假设情况 之后从节点自己被改了数据主节点不会知道从节点的数据有变化这样主节点和从节点的数据就对不上了出现数据不一致的问题 。2.5 主从复制的基本流程2.5.1 同步流程在 Redis 主从架构中以从节点slaveof 127.0.0.1 6379即连接本地 6379 端口的主节点和主节点master端口 6379从节点自身端口为 6380为例其连接与数据同步流程如下1. 保存主节点信息从节点首先会保存主节点的 IP 地址和端口信息将其存储为变量这是后续建立连接的基础属于系统层面的操作。2. 建立 TCP 连接三次握手从节点基于保存的主节点 IP 和端口信息与主节点进行 TCP 连接通过三次握手来验证通信双方是否能够正确读写数据确保网络通路是畅通的。3. 发送 ping 命令从节点向主节点发送 ping 命令这一步是为了验证主节点是否能够正常工作属于应用程序层面的检查类似于检查车辆是否能正常行驶。4. 权限验证如果 Redis 主节点开启了密码验证从节点需要进行相应的权限验证只有验证通过才能继续后续操作。5. *同步数据集在完成上述步骤后从节点会与主节点进行数据集的同步。6. *命令持续复制这是复制数据的最关键操作从节点会持续复制主节点的命令以保持与主节点数据的实时一致性。7. 同步方式全量同步在初始连接或某些特定情况下从节点会获取主节点的全部数据进行同步。增量同步在正常持续运行过程中从节点主要同步主节点新增或修改的数据以提高同步效率。2.5.2同步命令 psyncRedis 数据同步命令 psync:2.5.3replication idRedis 提供了 psync 命令来完成数据同步的过程。psync 命令具有自动化特性不需要我们手动去执行。当 Redis 服务器成功建立主从同步关系之后它会自动执行 psync 命令。在主从同步架构中从节点负责执行 psync 命令其作用是从主节点这边拉取数据就好比助教老师主动来找学生这里从节点类似学生主节点类似数据源头助教老师即数据同步机制主动帮学生获取知识即数据 以实现主从节点间的数据同步。psync 命令的格式为 PSYNC replicationid offset 其中 replicationid 是复制 ID用于唯一标识一个数据集版本offset 是偏移量用于记录复制的进度等信息。通过这两个参数psync 能够精准地实现数据的增量同步等操作。replication id 相关内容生成规则主节点启动、从节点晋升为主节点时生成同一主节点每次重启生成的 replication id 不同类似重启换 “身份证号”。传递逻辑从节点与主节点建立复制关系后主动获取主节点的 replication id 用于确认数据同步来源。实际操作执行 info replication 命令查看主节点执行后结果里 master_replid 字段即主节点的 replication id master_replid2 一般场景用不上 。特殊场景网络波动主节点 A、从节点 B 同步时网络波动B 误判 A 宕机并自行晋升为主节点会生成新 replication id 同时将 A 旧的 replication id 存于 replid2后续网络恢复B 可通过 replid2 尝试重新同步回 A 但需手动干预 。2.5.4 offsetoffset偏移量 相关内容核心作用主节点、从节点均维护整数偏移量标记数据同步进度类似直播 “进度条” 。主节点 offset主节点接收的写命令如 set、del 按字节数累加总和为其 offset代表数据变更 “总进度” 。从节点 offset表示从节点同步主节点数据的进度位置类似直播中自己 “进度条走到哪” 。同步完成标志从节点 offset 与主节点 offset 相等时说明从节点数据和主节点完全一致即 “赶上直播实时进度” 。2.5.5 全量复制1.核心基础offset 控制同步范围offset -1原文逻辑offset 写 -1 时从节点直接获取全量数据不管之前同步到哪重新拉取所有数据。offset 具体正整数原文逻辑offset 填正整数如 100从节点从当前偏移量位置继续同步只拉取没同步过的新数据。2.全量复制 vs 增量复制核心同步逻辑2.1全量复制的触发场景首次同步从节点第一次连主节点没任何历史同步记录必须全量拉取类似第一次看直播得从头开始看。主节点无法部分复制主节点判断 “不方便给部分数据”如数据差异太大、网络不稳定强制全量同步类似直播平台故障只能重新发完整回放。3.全量复制的执行流程结合 rdb 、aof 3.1. 主节点的核心动作生成 rdb 文件rdb 特点二进制格式体积小、节省空间类似把 “文字笔记” 压缩成 “加密压缩包”传输更快。生成逻辑主节点执行bgsave命令重新生成 rdb 文件不能用旧文件因为数据可能已变化。3.2. 全量复制的步骤以首次同步为例从节点发psync -1因首次同步无主节点 ID 和偏移量用 -1 表示全量。主节点回复FULLRESYNC开始全量复制。主节点执行bgsave生成新 rdb 文件传给从节点。从节点接收 rdb 文件加载数据到本地类似解压 “压缩包”恢复数据。主节点把 “生成 rdb 期间的新操作” 记录到缓冲区等从节点加载完 rdb 后再把这些新操作同步给从节点保证数据不丢。3.3. aof 日志的特殊处理从节点开启 aof 时从节点加载 rdb 数据时会生成大量 aof 日志类似边看直播边记超详细笔记可能有冗余内容。需整理 aof 日志如bgrewriteaof减少冗余类似把 “啰嗦笔记” 精简成 “重点大纲” 。4.全量复制的优化无硬盘模式diskless4.1. 优化逻辑主节点生成 rdb 后不写本地硬盘直接通过网络发给从节点省去 “写硬盘 → 读硬盘” 的步骤更快。从节点接收 rdb 后不写本地硬盘直接加载数据省去 “存硬盘 → 读硬盘” 的步骤更快。4.2. 优化的局限性2.5.6 部分复制1.部分复制的触发场景从节点之前同步过数据但因网络抖动、从节点重启等中断此时只需要拉取新数据类似直播断流后从断流位置接着看不用重看已看内容。部分复制主要是 Redis 针对全量复制的过高开销做出的⼀种优化措施使⽤ psync replicationIdoffset 命令实现。当从节点正在复制主节点时如果出现⽹络闪断或者命令丢失等异常情况时从节点会向主节点要求补发丢失的命令数据如果主节点的复制积压缓冲区存在数据则直接发送给从节点这样就可以保持主从节点复制的⼀致性。补发的这部分数据⼀般远远⼩于全量数据所以开销很小。网络中断主节点判定故障当主从节点间网络中断且超过repl - timeout时间主节点会判定从节点故障终止复制连接。主节点在中断期间的行为网络中断时主节点依旧正常响应外部 “修改数据” 等命令 。但本应发给从节点的 “复制命令”因网络不通无法及时发送会暂时存到复制积压缓冲区里。网络恢复从节点重连主从节点网络恢复后从节点会主动再次连接主节点 。从节点发起部分复制请求从节点连接主节点时会把之前保存的replicationId复制标识用于主从配对和复制偏移量记录之前同步到哪一步作为psync部分复制命令的参数发给主节点请求 “接着之前的进度同步不用全量复制” 。主节点验证并准备数据主节点收到psync请求后先做必要验证比如replicationId是否匹配、偏移量是否有效 。验证通过后根据从节点发的offset去复制积压缓冲区找对应的数据然后响应CONTINUE给从节点告诉从节点可以继续同步 。完成数据同步主节点把从节点需要的 “未同步数据”通过连接发给从节点从节点接收并应用这些数据最终主从节点数据再次保持一致完成恢复后的同步流程2.5.7 实时复制1.实时复制基础流程从节点完成初始数据同步后主节点会持续接收新的 “修改数据请求” 自身数据改变后要把这些修改同步给从节点保证数据一致性 。2.主从节点数据同步方式连接建立从节点和主节点间建立TCP 长连接作为数据传输通道。同步流程主节点收到 “修改数据请求” 后通过上述长连接把请求发给从节点从节点接收请求依据请求修改自身内存数据 。不过这个同步过程会有时间延迟正常很短多级从节点树形结构、层级多的话延迟会上升 。3.连接可用性保障心跳包机制为确保主从节点间的 TCP 长连接可用有 “心跳包机制”主节点行为默认每隔 10s 给从节点发ping命令从节点收到返回pong用于检测从节点是否在线 。从节点行为默认每隔 1s 给主节点发特定请求上报自身复制数据的进度用offset标识 让主节点掌握同步情况 。补充说明像 10s、1s 这类时间以及文中提到的 60s未明确关联场景可理解为相关机制里的默认配置 都属于可修改的配置不用死记 。简单概括就是主从节点靠 TCP 长连接同步数据修改用心跳包维持连接可用同步有延迟且受从节点结构影响心跳相关时间可灵活调整 。核心是保障主从数据一致同时通过心跳确保连接 “活着” 能传输数据 。三.其他补充3.1Nagle 算法在游戏开发中尤其是对即时性要求极高的 FPS、MOBA 等类型游戏主节点和从节点间通过网络TCP传输数据。TCP 内部默认开启支持 Nagle 算法该算法目的与 TCP 捎带应答类似即针对小的 TCP 数据报进行合并以减少包的个数开启它会增加 TCP 传输延迟但节省网络带宽关闭则减少延迟却增加带宽占用。而“repl-disable-tcp-nodelay”选项可在主从同步过程中关闭 TCP 的 Nagle 算法让从节点能更快速地与主节点同步。通俗解读网络传输方式主节点和从节点之间是通过TCP 网络来传输数据实现主从同步的 。Nagle 算法介绍TCP 协议里默认开启了Nagle 算法。它的作用有点像 “攒一波再发” 开启时会把一些小的 TCP 数据报合并起来发送这样发送的网络包数量就减少了能节省网络带宽但会增加数据传输的延迟。比如说本来要发好几个小数据包现在合并成一个大的发带宽省了可数据从主节点到从节点就得等合并慢了点 。关闭时小数据报就会马上发送不会攒着这样传输延迟会减少数据能更快同步但因为发的包多了会增加网络带宽的使用。对游戏开发的影响在一些对即时性要求很高的游戏开发场景里像 FPS 射击游戏、MOBA 竞技游戏 延迟很关键。要是主从同步延迟高可能游戏里数据更新就不及时影响玩家体验 。Redis 里的优化选项Redis 有个配置项repl-disable-tcp-nodelay用它可以在主从同步的过程中关闭 Nagle 算法。这样做能让从节点更快速地和主节点同步数据减少延迟适合对同步速度要求高的场景 。3.2 拓扑结构在由若干个节点组成的系统中探讨节点间以何种方式进行组织连接。以 Redis 主从节点为例存在 Redis-A主节点Master和 Redis-B从节点Slave 。主节点负责处理写数据请求同时也能处理读数据请求从节点主要处理读数据请求。当写数据请求过多时会给主节点造成一定压力。可以通过关闭主节点的 AOFAppend - Only File一种数据持久化方式只在从节点上开启 AOF 来缓解主节点压力。然而这种设定方式存在严重缺陷主节点一旦挂掉不能自动重启。若自动重启由于没有 AOF 文件就会丢失数据并且进一步的主从同步操作会把从节点的数据也删除。改进办法是当主节点挂了之后让主节点从从节点这里获取到 AOF 的文件再启动。3.3 扁平化结构在实际开发中读请求往往远超过写请求。在扁平化结构中存在 Redis-A主节点它连接着多个从节点如 Redis-E、Redis-B、Redis-C、Redis-D 等从节点。当主节点上的数据发生改变时会把改变的数据同时同步给所有的从节点。但随着从节点个数的增加同步一条数据就需要传输多次。这样一来主节点就不需要那么高的网卡带宽了不过一旦数据进行修改同步的延时会比之前更长。3.4 replid与runid的区别举个栗子~核心耗时仍在网络传输不管有没有硬盘操作大规模数据全量复制的网络传输时间省不了类似发大文件不管存不存硬盘传文件本身就慢。replidreplication id作用主从复制的核心标识主从关系中相同主节点生成从节点同步主节点的 replid 体现 “数据传承关系” 。runid作用标识 Redis 实例的一次 “运行”每次启动 / 重启runid 不同类似 “运行会话 ID” 。关联逻辑主要支撑Redis 哨兵sentinel功能用于哨兵识别实例、判断故障转移 和主从复制无直接关联。replid≈ 主从复制的 “家族族谱 ID”主节点有一个从节点同步主节点的主从 “族谱” 相同用来确认数据同步关系。runid≈ Redis 实例的 “运行身份证”每次启动换一个主要给哨兵用和主从复制 “不是一家人”。