<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Redis - Jul1en</title>
    <link>https://Jul1en-Lin.github.io/categories/redis/</link>
    <description>Redis - Jul1en</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <copyright>Jul1en</copyright>
    <lastBuildDate>Mon, 15 Jun 2026 09:07:51 +0800</lastBuildDate>
    <atom:link href="https://Jul1en-Lin.github.io/categories/redis/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Redis 缓存</title>
      <link>https://Jul1en-Lin.github.io/p/redis-%E7%BC%93%E5%AD%98/</link>
      <pubDate>Thu, 04 Jun 2026 22:42:48 +0800</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/redis-%E7%BC%93%E5%AD%98/</guid>
      <description>&lt;p&gt;这篇主要整理 Redis 缓存的数据更新方式、淘汰策略和常见异常场景。&lt;/p&gt;
&lt;h2 id=&#34;数据变更后的处理&#34;&gt;
    数据变更后的处理
&lt;/h2&gt;
&lt;p&gt;当 MySQL 发生新增、修改、删除时，缓存也要跟着处理。常见思路是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先修改 MySQL。&lt;/li&gt;
&lt;li&gt;删除 Redis 中对应的 key。&lt;/li&gt;
&lt;li&gt;下次查询时再按实时生成流程写回 Redis。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第二步选择“删除缓存”，不直接修改缓存里的值&lt;/strong&gt;。原因是缓存里的数据可能不是数据库单表字段，可能经过了关联查询、计算、排序、过滤，直接修改缓存值容易遗漏逻辑。&lt;/p&gt;
&lt;p&gt;如果倒过来，先删缓存再改 MySQL，在单一线程下一般没有问题；在并发情况下，可能出现这种顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;线程 A 删除缓存。&lt;/li&gt;
&lt;li&gt;线程 B 查询缓存未命中，读取旧 MySQL 数据，并写入 Redis。&lt;/li&gt;
&lt;li&gt;线程 A 修改 MySQL。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这会导致 Redis 里留下的还是旧数据，后续处理起来会比较麻烦。&lt;/p&gt;
&lt;h2 id=&#34;缓存更新策略&#34;&gt;
    缓存更新策略
&lt;/h2&gt;
&lt;p&gt;缓存更新本质上是在处理两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis 里应该提前放哪些数据。&lt;/li&gt;
&lt;li&gt;MySQL 数据变化后，Redis 里的旧数据怎么办。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;定期生成&#34;&gt;
    定期生成
&lt;/h3&gt;
&lt;p&gt;定期生成就是按固定周期把一批数据写入 Redis。比如每隔一段时间，通过 shell 或 Python 脚本从 MySQL 查出热门数据，再写入缓存。&lt;/p&gt;
&lt;p&gt;适合场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据变化频率不高。&lt;/li&gt;
&lt;li&gt;查询量比较大。&lt;/li&gt;
&lt;li&gt;允许短时间读到旧数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它的好处是读请求来了以后可以直接查 Redis，请求链路比较短。问题是数据会有延迟：如果 MySQL 已经变化，但下一轮缓存生成还没执行，用户可能读到旧数据。&lt;/p&gt;
&lt;h3 id=&#34;实时生成&#34;&gt;
    实时生成
&lt;/h3&gt;
&lt;p&gt;实时生成也就是常见的 Cache Aside 读流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;请求查询 key，先访问 Redis。&lt;/li&gt;
&lt;li&gt;Redis 命中则直接返回；未命中则查询 MySQL。&lt;/li&gt;
&lt;li&gt;MySQL 查询到数据，返回并更新 Redis；未查询到则直接返回。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种方式不会一开始就把所有数据放进 Redis，而是用户访问到哪个 key，就把哪个 key 放进去。它适合数据量比较大、热点数据会自然出现的场景。&lt;/p&gt;
&lt;p&gt;经过一段时间的动态平衡，Redis 中存储的数据会逐渐成为热点数据。随着时间推移，数据越写越多，可能逐渐达到 Redis 的内存上限。旧的热点 key 访问变少，新的热点 key 又无法插入，此时就需要引入&lt;strong&gt;内存淘汰策略&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;注意事项&#34;&gt;
    注意事项
&lt;/h2&gt;
&lt;h3 id=&#34;内存淘汰策略&#34;&gt;
    内存淘汰策略
&lt;/h3&gt;
&lt;p&gt;如果 Redis 内存达到上限，就会触发淘汰策略。这里不一定是物理内存，也可能是 Redis 配置中规定的最大内存容量。&lt;/p&gt;
&lt;p&gt;常见策略有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FIFO（First In First Out）&lt;/strong&gt;：先进先出，删除缓存中存在时间最久的 key。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LRU（Least Recently Used）&lt;/strong&gt;：淘汰最久未使用的 key，根据最近一次访问时间选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LFU（Least Frequently Used）&lt;/strong&gt;：淘汰访问次数最少的 key，根据最近一段时间的访问频率选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Random&lt;/strong&gt;：随机淘汰 key。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;缓存预热&#34;&gt;
    缓存预热
&lt;/h3&gt;
&lt;p&gt;Redis 服务器首次接入时没有任何数据，所有请求都会先访问 MySQL，再逐渐写入 Redis，数据库的压力只会慢慢下降。&lt;/p&gt;
&lt;p&gt;缓存预热就是为了解决这个问题：它将定期生成和实时生成结合，通过离线统计先找出一批热点数据，预先导入 Redis，提前帮数据库承担一部分访问压力。随着后续访问变化，再逐渐使用新的热点数据淘汰旧数据。&lt;/p&gt;
&lt;h3 id=&#34;缓存穿透cache-penetration&#34;&gt;
    缓存穿透（Cache Penetration）
&lt;/h3&gt;
&lt;p&gt;请求查询一个不存在的数据，Redis 没有，MySQL 也没有。每次请求都会打到 MySQL，缓存没有起到保护作用。&lt;/p&gt;
&lt;p&gt;可能原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务设计不合理，缺少必要的参数校验。&lt;/li&gt;
&lt;li&gt;开发或运维误操作，将部分数据从数据库中删除。&lt;/li&gt;
&lt;li&gt;恶意攻击。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;缓存空值&lt;/strong&gt;：MySQL 查询不到时，把空结果也写入 Redis，并设置较短的过期时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布隆过滤器&lt;/strong&gt;：先判断 key 是否可能存在，不可能存在就直接拦截。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数校验&lt;/strong&gt;：明显非法的 id、页码、业务参数，不进入缓存和数据库查询流程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缓存空值时要注意过期时间不能太长，否则真实数据后来写入 MySQL 后，Redis 里仍然保留空结果，用户会继续查询不到。&lt;/p&gt;
&lt;h3 id=&#34;缓存雪崩cache-avalanche&#34;&gt;
    缓存雪崩（Cache Avalanche）
&lt;/h3&gt;
&lt;p&gt;短时间内大量缓存 key 同时失效，或者 Redis 整体不可用，导致缓存命中率大幅下降。请求集中访问 MySQL，数据库压力迅速上升，甚至直接宕机。&lt;/p&gt;
&lt;p&gt;典型场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis 突然不可用，或者集群模式下大量节点宕机。&lt;/li&gt;
&lt;li&gt;某个时间点大量 key 同时过期。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;处理思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;给过期时间增加随机值，避免大量 key 同时失效。&lt;/li&gt;
&lt;li&gt;对特别核心的数据做缓存预热。&lt;/li&gt;
&lt;li&gt;对数据库访问进行限流，避免请求把 MySQL 打满。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缓存雪崩是“大面积缓存同时失效”的问题。沿着这个问题继续看，还会出现一个更具体的场景：&lt;mark class=&#34;hltr-green-light&#34;&gt;不是很多 key 同时失效，而是针对热点 key 失效&lt;/mark&gt;，大量请求都冲向同一份数据，这就是缓存击穿。&lt;/p&gt;
&lt;h3 id=&#34;缓存击穿cache-breakdown&#34;&gt;
    缓存击穿（Cache Breakdown）
&lt;/h3&gt;
&lt;p&gt;缓存击穿可以看作缓存雪崩的特殊情况。热点 key 突然失效时，大量并发请求同时发现 Redis 未命中，随后集中访问 MySQL。&lt;/p&gt;
&lt;p&gt;它和缓存雪崩的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;缓存雪崩&lt;/strong&gt;：大量 key 同时失效，影响面大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存击穿&lt;/strong&gt;：一个热点 key 失效，但访问量非常大。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;热点 key 设置更长的过期时间，或者使用逻辑过期控制刷新。&lt;/li&gt;
&lt;li&gt;进行服务降级。&lt;/li&gt;
&lt;li&gt;访问数据库时使用分布式锁，限制查询数据库的并发数。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Docker 部署 Redis 集群</title>
      <link>https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/</link>
      <pubDate>Mon, 01 Jun 2026 16:01:33 +0800</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/</guid>
      <description>&lt;p&gt;这次用 Docker 部署 11 个 Redis 节点，九个用于部署集群，两个用于扩容练习，集群的结构类似于如图，由于 Redis 部署集群时内部的随机性，可能节点的静态 ip 所属的角色都不太一样，无伤大雅～
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-layout_hu_17e84e305bf30699.webp&#34; width=&#34;1600&#34; height=&#34;1600&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-layout_hu_fcb9aafe5612ff45.webp 800w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-layout_hu_17e84e305bf30699.webp 1600w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-layout_hu_fdebd95eaa17c03a.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Docker Redis cluster layout&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;100&#34; data-flex-basis=&#34;240px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;step-1创建目录和配置&#34;&gt;
    Step 1：创建目录和配置
&lt;/h2&gt;
&lt;p&gt;创建 &lt;code&gt;redis-cluster&lt;/code&gt; 目录，在目录内部创建 &lt;code&gt;docker-compose.yml&lt;/code&gt; 和 &lt;code&gt;generate.sh&lt;/code&gt; 文件，对应命令为&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir redis-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; redis-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim docker-compose.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim generate.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;文件结构为&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;redis-cluster/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── docker-compose.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── generate.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;step-2编写脚本&#34;&gt;
    Step 2：编写脚本
&lt;/h2&gt;
&lt;p&gt;脚本 &lt;code&gt;generate.sh&lt;/code&gt; 里内容为&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; port in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 9&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p redis&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;touch redis&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/redis.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; EOF &amp;gt; redis${port}/redis.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;port 6379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;bind 0.0.0.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;protected-mode no
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;appendonly yes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-enabled yes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-config-file nodes.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-node-timeout 5000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-ip 172.30.0.10${port}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-port 6379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-bus-port 16379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 注意 cluster-announce-ip 的值有变化.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; port in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; 11&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p redis&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;touch redis&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/redis.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; EOF &amp;gt; redis${port}/redis.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;port 6379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;bind 0.0.0.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;protected-mode no
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;appendonly yes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-enabled yes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-config-file nodes.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-node-timeout 5000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-ip 172.30.0.1${port}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-port 6379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;cluster-announce-bus-port 16379
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存后就能执行脚本啦，这个脚本的意思是在当前目录 &lt;code&gt;redis-cluster&lt;/code&gt; 中建立从 redis 1～redis 11 的文件夹，每个中都有对应节点的必要配置文件。
&lt;strong&gt;⚠️注意：如果你服务器上有其他的网段占用，则需要修改当前脚本与后续的 &lt;code&gt;YAML&lt;/code&gt; 文件中的网段配置，只要不冲突即可。&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sh generate.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行完后如果没有任何反应那就是执行成功了，我们可以看看
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-folders_hu_1bdada3e0b7a1031.webp&#34; width=&#34;1600&#34; height=&#34;216&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-folders_hu_48398032ac3a245e.webp 800w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-folders_hu_1bdada3e0b7a1031.webp 1600w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-folders_hu_44efa2fac06f0bea.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster generated folders&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;740&#34; data-flex-basis=&#34;1776px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;step-3配置-yaml&#34;&gt;
    Step 3：配置 YAML
&lt;/h2&gt;
&lt;p&gt;我们接着来配置 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件，内容有点长&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.7&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipam&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;subnet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.0&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/24&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis1/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6371&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16371&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.101&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis2/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6372&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16372&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.102&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis3/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6373&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16373&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.103&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis4/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6374&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16374&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.104&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis5&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis5/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6375&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16375&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.105&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis6&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis6/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6376&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16376&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.106&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis7&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis7/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6377&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16377&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.107&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis8/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6378&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16378&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.108&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis9&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis9/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.109&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis10&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis10/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6380&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16380&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.110&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;redis11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis11&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./redis11/:/etc/redis/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6381&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;16381&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server /etc/redis/redis.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mynet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipv4_address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;172.30.0.111&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果没问题，就执行 &lt;code&gt;sudo docker-compose up -d&lt;/code&gt;，启动容器并后台运行。&lt;/p&gt;
&lt;h2 id=&#34;step-4配置集群&#34;&gt;
    Step 4：配置集群
&lt;/h2&gt;
&lt;p&gt;还有一个步骤，就是让各自的节点都能“认识对方”，目前只是配置了各个节点的配置，还没有配置它们之间的联系，需要用到一行命令，手动的将各个主机都联系起来。
这个命令直接在 cluster 路径下直接执行即可，无需进入 Redis 服务。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行后 redis 会默认帮你弄好集群的分片配置，这里都描述了每个分片的 slot 数量，主从节点的分配等。确认无误的话就能输入 yes 下一步真正配置咯
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-create_hu_d8aa1296c7fbf135.webp&#34; width=&#34;1600&#34; height=&#34;1038&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-create_hu_e2d1c9467695eb6.webp 800w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-create_hu_d8aa1296c7fbf135.webp 1600w, https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/assets/docker-cluster-create_hu_ff4b81d74f4de3e0.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster create result&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;154&#34; data-flex-basis=&#34;369px&#34;&gt;

到这里 Redis 的分片集群就真正配置好了，我们还剩两台 Redis 服务器未用上。这是用于扩容的，继续。&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Redis 集群</title>
      <link>https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/</link>
      <pubDate>Sun, 31 May 2026 23:16:16 +0800</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;
    概述
&lt;/h2&gt;
&lt;p&gt;其实集群的概念很广泛。广义上，只要多个机器共同组成一个分布式系统，都可以叫集群。之前的主从复制、哨兵模式，也可以看成广义集群。Redis 这里说的集群，一般指 Redis Cluster。它主要解决的是&lt;strong&gt;存储空间不足&lt;/strong&gt;的问题：把数据拆到多台机器上，每台机器只保存一部分数据。&lt;/p&gt;
&lt;p&gt;哨兵模式解决的是可用性问题，但本质上还是主从节点都保存完整数据。只要数据全集超过单机能承受的内存，就需要引入分片。&lt;/p&gt;
&lt;h2 id=&#34;分片&#34;&gt;
    分片
&lt;/h2&gt;
&lt;p&gt;分片可以理解成把数据一片一片分开。分片就是把数据拆成多份，分别放到不同节点上。
&lt;strong&gt;所以每一台机器上面的数据都是不一样的。&lt;/strong&gt;
比如有 1TB 数据，可以这样拆：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 台机器，每台大约存 512GB。&lt;/li&gt;
&lt;li&gt;3 台机器，每台大约存 300 多 GB。&lt;/li&gt;
&lt;li&gt;4 台机器，每台大约存 256GB。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;机器越多，每台机器承担的数据越少。但是实际部署时，每个存数据的主节点通常还要配从节点，用来提高可用性。所以扩容的时候并不是只需要一台，可能是需要很多台机器。对于数据存放的思路，有以下这几种算法可以实现。&lt;/p&gt;
&lt;h2 id=&#34;哈希求余&#34;&gt;
    哈希求余
&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-mod_hu_158921f365814859.webp&#34; width=&#34;1600&#34; height=&#34;881&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-mod_hu_e91e2ce6166111a5.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-mod_hu_158921f365814859.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-mod_hu_518e1d954cb26027.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Hash modulo sharding&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;181&#34; data-flex-basis=&#34;435px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;哈希求余的思路是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hash(key) % N
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;N&lt;/code&gt; 是分片数量。Redis 的数据都是 key-value 结构，所以可以先对 key 做 hash，再对分片数量求余，得到应该放到哪个分片。查询时也一样：key 不变，hash 函数不变，算出来的分片编号也不变。&lt;/p&gt;
&lt;p&gt;这种方式简单，但是扩容很麻烦。因为一旦分片数量 &lt;code&gt;N&lt;/code&gt; 改了，&lt;code&gt;hash(key) % N&lt;/code&gt; 的结果会整体变化，很多数据都要重新搬运。&lt;/p&gt;
&lt;h2 id=&#34;一致性哈希&#34;&gt;
    一致性哈希
&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-consistent-hash_hu_e7d93fb8389d091a.webp&#34; width=&#34;1600&#34; height=&#34;1600&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-consistent-hash_hu_4a5f7dbc25fb32cb.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-consistent-hash_hu_e7d93fb8389d091a.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-consistent-hash_hu_299438d315a49070.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Consistent hashing&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;100&#34; data-flex-basis=&#34;240px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;一致性哈希把 hash 空间看成一个环，比如范围是 &lt;code&gt;0 ~ 2^32 - 1&lt;/code&gt;。分片也落在这个环上，key 计算 hash 后，按环上的位置往顺时针跑，找到第一个分片的分割点，那就属于是当前的分片。&lt;/p&gt;
&lt;p&gt;就像图里的，原本只有分片 012，若新增了分片 3，则扩容时不用让所有 key 重新分布，只需要搬动新节点影响到的一段数据。图中的 keyC 原本是属于分片 0 的，现在顺时针跑遇到的第一个分片是 3，那么它就属于新分片 3 的范围咯～&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比哈希求余的数据搬运量小&lt;/li&gt;
&lt;li&gt;扩容成本更低&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但有个问题是如果节点分布不好，分片上的数据量可能不均匀，专业数据叫做数据倾斜～&lt;/p&gt;
&lt;h2 id=&#34;redis-哈希槽&#34;&gt;
    Redis 哈希槽
&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-slot_hu_85d66e1d3ca1de7c.webp&#34; width=&#34;1600&#34; height=&#34;1067&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-slot_hu_e6df7f1d4a20c828.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-slot_hu_85d66e1d3ca1de7c.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/redis-cluster-hash-slot_hu_bc2ab00c22f20500.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis hash slots&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;150&#34; data-flex-basis=&#34;360px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;Redis Cluster 真正采用的是哈希槽方案，将哈希求余➕一致性哈希，结合起来了。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;slot = CRC16(key) % 16384
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Redis Cluster 固定有 &lt;code&gt;16384&lt;/code&gt; 个槽位，也就是 &lt;code&gt;2^14&lt;/code&gt; 个。key 不是直接映射到分片，而是先映射到槽位，再由槽位映射到分片。&lt;/p&gt;
&lt;p&gt;流程可以理解为：key -&amp;gt; 槽位(slot) -&amp;gt; 分片&lt;/p&gt;
&lt;p&gt;扩容或迁移时，不需要按单个 key 去重新分配，而是迁移一部分槽位。只有这些槽位对应的数据需要搬运，所以比简单的哈希求余更适合扩容。&lt;/p&gt;
&lt;p&gt;例如 3 个分片时，可以大致这样分：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 号分片：[0, 5461]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 号分片：[5462, 10923]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 号分片：[10924, 16383]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果扩成 4 个分片，也可以从原来的几个分片中各拿出一部分槽位给新分片。这样每个分片大约持有 &lt;code&gt;4096&lt;/code&gt; 个槽位。&lt;/p&gt;
&lt;h2 id=&#34;槽位数量&#34;&gt;
    槽位数量
&lt;/h2&gt;
&lt;p&gt;Redis 使用 &lt;code&gt;16384&lt;/code&gt; 个槽位，是一个折中的数量。可以简单的算一下它的大小的，看着挺多，其实没占多少空间&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;16384 bit = 2048 byte = 2KB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果槽位太少，每个分片能分到的槽位少，数据均衡性不容易保证，某些槽位可能有很多 key，某些槽位也可能没有 key。&lt;/p&gt;
&lt;p&gt;如果槽位太多，节点之间通信的元数据会变大。因为 Redis 节点之间需要通过心跳包通信，心跳包中包含了该节点持有哪些 slots，这个是使用位图这样的数据结构表示的。如果槽位数量变成 &lt;code&gt;65536&lt;/code&gt;，位图就会变成 &lt;code&gt;8KB&lt;/code&gt;，虽然看着也不大，但是在这种频繁发送心跳包的场景里，网络带宽负担还是比较明显。&lt;/p&gt;
&lt;p&gt;slots 通常会用位图表示：第 &lt;code&gt;i&lt;/code&gt; 位为 &lt;code&gt;1&lt;/code&gt;，表示这个节点持有第 &lt;code&gt;i&lt;/code&gt; 个槽位；第 &lt;code&gt;i&lt;/code&gt; 位为 &lt;code&gt;0&lt;/code&gt;，表示不持有。注意这里表示的是节点是否持有槽位，不是这个槽位里有没有 key。&lt;/p&gt;
&lt;h2 id=&#34;集群部署&#34;&gt;
    集群部署
&lt;/h2&gt;
&lt;p&gt;具体部署步骤单独整理到：&lt;a class=&#34;link&#34; href=&#34;https://Jul1en-Lin.github.io/p/docker-%E9%83%A8%E7%BD%B2-redis-%E9%9B%86%E7%BE%A4/&#34;&gt;Docker 部署 Redis 集群&lt;/a&gt;
。&lt;/p&gt;
&lt;p&gt;部署集群后，可以通过 &lt;code&gt;docker-compose ps&lt;/code&gt; 命令来查看各个节点的状态
若想查看它们之间的分片主从关系，可通过 &lt;code&gt;cluster nodes&lt;/code&gt; 查看，这个命令要在 redis-cli 中执行
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-nodes_hu_7c427d50a72be6f.webp&#34; width=&#34;1600&#34; height=&#34;657&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-nodes_hu_99d7075b21207d3a.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-nodes_hu_7c427d50a72be6f.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-nodes_hu_a0dbd1d6cc21399e.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster nodes&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;243&#34; data-flex-basis=&#34;584px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;Redis 分片后，每个分片的槽位都不同，如果在分片 1 中，写入的 key 刚好位于分片 2 的 slot，则会无法插入，如图（主节点与从节点同理）
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-without-c_hu_da74e5e847c925f3.webp&#34; width=&#34;1600&#34; height=&#34;291&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-without-c_hu_69b0049da47b2aba.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-without-c_hu_da74e5e847c925f3.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-without-c_hu_a27c7fb12ddc5bc9.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster moved error without client mode&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;549&#34; data-flex-basis=&#34;1318px&#34;&gt;

如需要插入 key 1，则需要手动切换至 172.30.0.102:6379 这个节点，非常麻烦，有没有办法能够既可以插入，又可以无需手动切换 redis 节点呢？有的有的，只需要在进入 redis-cli 中加入 &lt;code&gt;-c&lt;/code&gt; 命令，Redis 客户端就会根据当前 key 实际算出来的槽位号，自动找到匹配的分片主机，也就是能够在分片 1 节点上插入属于其他分片的 key 值。
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-with-c_hu_c970c62cc6c02848.webp&#34; width=&#34;1600&#34; height=&#34;366&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-with-c_hu_7e1f8fb7196974fe.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-with-c_hu_c970c62cc6c02848.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-set-with-c_hu_3eb1d157bf06dd14.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster client mode redirects key write&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;436&#34; data-flex-basis=&#34;1048px&#34;&gt;

这次就能帮你切换到应该的节点，成功。仅需输入一次 &lt;code&gt;-c&lt;/code&gt; 即可&lt;/p&gt;
&lt;h2 id=&#34;故障转移&#34;&gt;
    故障转移
&lt;/h2&gt;
&lt;p&gt;这里的故障转移与&lt;a class=&#34;link&#34; href=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/&#34;&gt;Redis 哨兵&lt;/a&gt;
的不太一样，主要的区别在于投票选出新的主节点上&lt;/p&gt;
&lt;p&gt;具体演示下，将 redis 1 主节点给手动停掉，命令 &lt;code&gt;docker stop redis1&lt;/code&gt;
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-stop-redis1_hu_9323a33c159ed4c2.webp&#34; width=&#34;1600&#34; height=&#34;505&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-stop-redis1_hu_f3287270c0d897f1.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-stop-redis1_hu_9323a33c159ed4c2.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-stop-redis1_hu_e112fcbcf6ca8356.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Stop redis1 container&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;317&#34; data-flex-basis=&#34;760px&#34;&gt;

&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-failover-promote_hu_3784b73e71874238.webp&#34; width=&#34;1600&#34; height=&#34;520&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-failover-promote_hu_a17bac8d54325080.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-failover-promote_hu_3784b73e71874238.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-failover-promote_hu_44860b6dfaa43313.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis cluster failover promotes replica&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;307&#34; data-flex-basis=&#34;738px&#34;&gt;

可以看到，101 主节点挂了后，原先 101 的从节点：105 被提拔为了新的主节点，101 原本的从节点 106 此刻也变成了 105 的从节点，那么我们再试试重启 101 节点，看看是什么变化（&lt;code&gt;docker start redis1&lt;/code&gt;）
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-redis1-restart_hu_925265a003da9fc9.webp&#34; width=&#34;1600&#34; height=&#34;486&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-redis1-restart_hu_eae5c3ae9f50cf9c.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-redis1-restart_hu_925265a003da9fc9.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-redis1-restart_hu_d2da24fa0ca4207e.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Restarted redis1 becomes replica&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;329&#34; data-flex-basis=&#34;790px&#34;&gt;

它也变成了 105 的从节点。
能看出集群也能够处理故障转移，而且这看起来跟哨兵的故障转移很像，那我们说的不同点在哪呢？不同在于过程～&lt;/p&gt;
&lt;h3 id=&#34;过程&#34;&gt;
    过程
&lt;/h3&gt;
&lt;h4 id=&#34;故障判定&#34;&gt;
    故障判定
&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;节点 A 给节点 B 发送 ping 包，B 就会给 A 返回一个 pong 包。ping 和 pong 除了 message type 属性之外，其他部分都是一样的。这里包含了集群的配置信息（该节点的 id，该节点从属于哪个分片，是主节点还是从节点，从属于谁，持有哪些 slots 的位图……）&lt;/li&gt;
&lt;li&gt;每个节点，每秒钟，都会给一些随机的节点发起 ping 包，而不是全发一遍。这样设定是为了避免在节点很多的时候，心跳包也非常多（比如有 9 个节点，如果全发，就是 9 * 8 有 72 组心跳了，而且这是按照 N^2 这样的级别增长的）。&lt;/li&gt;
&lt;li&gt;当节点 A 给节点 B 发起 ping 包，B 不能如期回应的时候，此时 A 就会尝试重置和 B 的 TCP 连接，看能否连接成功。如果仍然连接失败，A 就会把 B 设为 &lt;strong&gt;PFAIL 状态&lt;/strong&gt;（相当于主观下线）&lt;/li&gt;
&lt;li&gt;A 判定 B 为 PFAIL 之后，会通过 Redis 内置的 Gossip 协议，和其他节点进行沟通，向其他节点确认 B 的状态。（每个节点都会维护自己的“下线列表”，由于视角不同，每个节点的下线列表也不一定相同）。&lt;/li&gt;
&lt;li&gt;此时 A 发现其他很多节点，也认为 B 为 PFAIL，并且数目超过总集群个数的一半，那么 A 就会把 B 标记成 &lt;strong&gt;FAIL&lt;/strong&gt; （相当于客观下线），并且把这个消息同步给其他节点（其他节点收到之后，也会把 B 标记成 FAIL）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;故障迁移&#34;&gt;
    故障迁移
&lt;/h4&gt;
&lt;p&gt;如果 B 是从节点，那么不需要进行故障迁移
如果 B 是主节点，那么就会由 B 的从节点（比如 C 和 D）触发故障迁移了&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从节点判定自己是否具有参选资格。如果从节点和主节点已经太久没通信（此时认为从节点的数据和主节点差异太大了，说明很久没有同步过数据），时间超过阈值，就失去竞选资格。&lt;/li&gt;
&lt;li&gt;具有资格的节点，比如 C 和 D，就会先休眠一定时间。休眠时间 = 500 ms 基础时间 + [0, 500 ms] 随机时间 + 排名 * 1000 ms。（offset 越大，数据就越接近主节点，排名就要靠前，休眠时间就更短）&lt;/li&gt;
&lt;li&gt;比如 C 的休眠时间到了，C 就会给其他所有集群中的节点，进行拉票操作。&lt;strong&gt;但是只有主节点才有投票资格&lt;/strong&gt;（谁休眠时间短，大概率就是新的主节点了）&lt;/li&gt;
&lt;li&gt;主节点就会把自己的票投给 C（每个主节点只有 1 票）。当 C 收到的票数超过主节点数目的一半，C 就会晋升成主节点（C 自己负责执行 &lt;code&gt;slaveof no one&lt;/code&gt;，并且让 D 执行 &lt;code&gt;slaveof C&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;同时，C 还会把自己成为主节点的消息，同步给其他集群的节点。大家也都会更新自己保存的集群结构信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;更多的时候，是为了选一个节点出来，至于选谁，没那么重要。所以你看，不同点在于：哨兵，是先竞选出 leader，leader 负责找一个从节点升级成主节点，&lt;strong&gt;这里是直接投票选出新的主节点&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;集群扩容&#34;&gt;
    集群扩容
&lt;/h2&gt;
&lt;h3 id=&#34;扩容主节点&#34;&gt;
    扩容主节点
&lt;/h3&gt;
&lt;p&gt;这里将 redis-10 作为主节点，redis-11 作为从节点。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 添加 redis-10 的地址（172.30.0.110:6379）到集群中的任意一个节点地址（172.30.0.101:6379）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-master_hu_861718925a68abf2.webp&#34; width=&#34;1600&#34; height=&#34;1175&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-master_hu_1cdfb137dac848be.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-master_hu_861718925a68abf2.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-master_hu_fac1bf8c3b56c184.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Add redis10 as cluster master&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;136&#34; data-flex-basis=&#34;326px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;添加成功后 &lt;code&gt;cluster nodes&lt;/code&gt; 查看 redis-10 已经作为主节点进入集群，但还未分配到 slots
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-new-master-no-slots_hu_4f93f4ae6c54a8c2.webp&#34; width=&#34;1600&#34; height=&#34;589&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-new-master-no-slots_hu_303ea656e8ad19fa.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-new-master-no-slots_hu_4f93f4ae6c54a8c2.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-new-master-no-slots_hu_dda2bf3982bf7dd7.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis10 joined with no slots&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;271&#34; data-flex-basis=&#34;651px&#34;&gt;

&lt;strong&gt;重新分配 slots&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# reshard （重新切分）后的地址是集群中的任意节点地址&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;redis-cli --cluster reshard 172.30.0.101:6379
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行后会进行交互操作，具体有&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;选择多少个 slots 分配到该节点（原先有 3 个分片，现扩容至 4 分片，16384 slots 平均到一个分片为 4096）
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-slots-count_hu_ec9179da53455cf3.webp&#34; width=&#34;1600&#34; height=&#34;1419&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-slots-count_hu_ca48175150b08f2d.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-slots-count_hu_ec9179da53455cf3.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-slots-count_hu_675220c4bfc1bd1f.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Choose reshard slot count&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;112&#34; data-flex-basis=&#34;270px&#34;&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;选择将 slots 转移到哪个节点上（此处填写节点的 id，如图）
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-target-node_hu_9aaac0e5a4585fec.webp&#34; width=&#34;1600&#34; height=&#34;1366&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-target-node_hu_795f72a8897a3c2a.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-target-node_hu_9aaac0e5a4585fec.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-target-node_hu_a2a69713788a0325.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Choose reshard target node&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;117&#34; data-flex-basis=&#34;281px&#34;&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这些 slots 从哪些节点搬运过来（all 表示每个主节点都搬一点，若选择 done 则需手动填写主节点 id）
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-source-nodes_hu_e09d9675efbb19f0.webp&#34; width=&#34;1600&#34; height=&#34;251&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-source-nodes_hu_e8f66041a674d01c.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-source-nodes_hu_e09d9675efbb19f0.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-reshard-source-nodes_hu_7bb90892296414ab.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Choose reshard source nodes&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;637&#34; data-flex-basis=&#34;1530px&#34;&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确定之后，会初步打印出搬运方案，让用户确认，之后就会进行集群的 key 搬运工作，主节点就配置好了&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;扩容从节点&#34;&gt;
    扩容从节点
&lt;/h3&gt;
&lt;p&gt;仅需一行命令&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 添加 redis-11（172.30.0.111:6379）到集群中（集群任意一个节点地址）作为从节点 （--cluster-slave），后跟上要跟随的主节点 id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;172.30.0.110 节点的 nodeId（主节点 id）&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行完毕后，从节点就已经被添加完成了，可见 &lt;strong&gt;redis-10 占了其他三个分片的部分 slots&lt;/strong&gt;，redis-11 也成功成为了 redis-10 的从节点
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-replica-result_hu_fac9cd3ff739230.webp&#34; width=&#34;1600&#34; height=&#34;877&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-replica-result_hu_260572166d4e2833.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-replica-result_hu_fac9cd3ff739230.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/assets/cluster-add-replica-result_hu_b8f88894fd424bcd.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis10 slots and redis11 replica result&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;182&#34; data-flex-basis=&#34;437px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;
    总结
&lt;/h2&gt;
&lt;p&gt;Redis Cluster 的核心是分片。主从复制和哨兵主要解决可用性，集群模式进一步解决单机存储容量限制。部署后可以通过 &lt;code&gt;redis-cli -c&lt;/code&gt; 让客户端自动跟随槽位跳转；扩容时则先添加主节点，再通过 reshard 分配 slots，最后把新从节点挂到对应主节点下面。&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Redis 哨兵</title>
      <link>https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/</link>
      <pubDate>Sun, 31 May 2026 22:26:24 +0800</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/</guid>
      <description>&lt;p&gt;Redis 的&lt;a class=&#34;link&#34; href=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/&#34;&gt;主从复制&lt;/a&gt;
模式下，一旦主节点不能提供服务，就需要人工进行主从切换，这非常麻烦。后续如果要解决单机存储容量限制，需要继续看&lt;a class=&#34;link&#34; href=&#34;https://Jul1en-Lin.github.io/p/redis-%E9%9B%86%E7%BE%A4/&#34;&gt;集群&lt;/a&gt;
。&lt;/p&gt;
&lt;h2 id=&#34;主从复制局限性&#34;&gt;
    主从复制局限性
&lt;/h2&gt;
&lt;p&gt;主从复制能够很好地平衡数据一致性问题，但是当遇到故障时，还是会遗留一些问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;主节点发生故障时，需要手动切换主节点，非常复杂。&lt;/li&gt;
&lt;li&gt;主节点能够将读压力分担到从节点中，但是主节点仍然承担写压力，受到单机限制。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;来看第一个问题，如果出现故障了，大致流程是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查主节点是否健康，是否还能工作或抢救。&lt;/li&gt;
&lt;li&gt;如果短时间不能排查问题，则需要手动挑一个从节点设置为新的主节点。&lt;/li&gt;
&lt;li&gt;把选好的从节点通过 &lt;code&gt;slaveof no one&lt;/code&gt; 升级成主节点。&lt;/li&gt;
&lt;li&gt;再将原来的从节点通过 &lt;code&gt;slaveof 主节点的 ip port&lt;/code&gt; 连上新的主节点。&lt;/li&gt;
&lt;li&gt;修改客户端配置，让客户端能够顺利连接到另一个主节点。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这步骤看着都头疼&amp;hellip;于是 Redis 就引入了哨兵来解决这个问题。通常哨兵也不会只设置一个，而会部署一个哨兵集群，防止哨兵挂了或单个哨兵误判。&lt;/p&gt;
&lt;h2 id=&#34;实现原理&#34;&gt;
    实现原理
&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-overview_hu_1eced5a7a628084b.webp&#34; width=&#34;1600&#34; height=&#34;1067&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-overview_hu_4ac784e7f6fc8c2b.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-overview_hu_1eced5a7a628084b.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-overview_hu_a7def29a8e9533a0.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis Sentinel overview&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;150&#34; data-flex-basis=&#34;360px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;正常运行状态时，哨兵集群中的每个节点都是单独的 &lt;code&gt;redis-sentinel&lt;/code&gt; 进程，会监控现有的 &lt;code&gt;redis-master&lt;/code&gt; 和 &lt;code&gt;slave&lt;/code&gt;。它们的监控是通过 TCP 长连接定期发送心跳包。&lt;/p&gt;
&lt;p&gt;不过，一个哨兵节点发现主节点挂了还不够，需要多个哨兵节点共同认同这件事，才会进行接下来的操作，主要是为了防止误判。&lt;/p&gt;
&lt;p&gt;当多数哨兵都认为主节点挂了，就会接着往下操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;哨兵节点中会先挑选出一个 leader，由这个 leader 负责从现有从节点中挑选一个作为新的主节点。leader 会通过投票方式选出，每个哨兵都有一票，票数多的成为 leader。&lt;/li&gt;
&lt;li&gt;挑选出从节点后，哨兵会控制这个节点执行 &lt;code&gt;slaveof no one&lt;/code&gt;，并控制其他节点修改 &lt;code&gt;slaveof&lt;/code&gt; 到新的主节点上。&lt;/li&gt;
&lt;li&gt;然后自动通知客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;docker-部署&#34;&gt;
    Docker 部署
&lt;/h2&gt;
&lt;p&gt;这里使用 Docker 做多个 Redis 的部署练习，结构是一个主节点、两个从节点、一个哨兵集群（三个 sentinel）。&lt;/p&gt;
&lt;h3 id=&#34;主从节点配置&#34;&gt;
    主从节点配置
&lt;/h3&gt;
&lt;p&gt;在云服务器上运行 Docker，首先要安装 Docker：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install docker-compose
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果本身有 Redis 进程，可以先停掉之前的服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;service redis-server stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后使用 Docker 拉取 Redis 镜像：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker pull redis:5.0.9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首次拉取可能会出现拉取超时，这是由于国内网络环境导致的。要么给云服务器加代理，要么配置镜像源。我这里配置了镜像源，只需要逐条执行即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mkdir -p /etc/docker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo tee /etc/docker/daemon.json &amp;gt;/dev/null &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;  &amp;#34;registry-mirrors&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;    &amp;#34;https://docker.1ms.run&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;    &amp;#34;https://hub-mirror.c.163.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl restart docker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo docker pull redis:5.0.9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后使用下面的命令查看镜像是否拉取成功：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker images
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们需要创建两个文件夹。建议在主目录中建一个 &lt;code&gt;redis&lt;/code&gt; 文件夹，在里面再分成 &lt;code&gt;redis-data&lt;/code&gt; 和 &lt;code&gt;redis-sentinel&lt;/code&gt; 文件夹：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir redis
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; redis
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir redis-data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir redis-sentinel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最终你在 &lt;code&gt;redis&lt;/code&gt; 目录中会有这两个文件夹：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-folders_hu_cb721e02d0ff0856.webp&#34; width=&#34;1600&#34; height=&#34;548&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-folders_hu_8263a276ba677403.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-folders_hu_cb721e02d0ff0856.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-folders_hu_bd22fd8805949aa4.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis folders&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;291&#34; data-flex-basis=&#34;700px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;进入 &lt;code&gt;redis-data&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; redis-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;新建配置文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim docker-compose.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这个文件名称必须是 &lt;code&gt;docker-compose.yml&lt;/code&gt;，然后把这段配置粘贴进去：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.7&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;master&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-master&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server --appendonly yes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;slave1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-slave1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server --appendonly yes --slaveof redis-master 6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6380&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;slave2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-slave2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-server --appendonly yes --slaveof redis-master 6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;6381&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后启动：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;哨兵配置&#34;&gt;
    哨兵配置
&lt;/h3&gt;
&lt;p&gt;进入哨兵文件夹：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; redis-sentinel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样创建配置文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim docker-compose.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置内容如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.7&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sentinel1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel-1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel /etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./sentinel1.conf:/etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;26379&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;26379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sentinel2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel-2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel /etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./sentinel2.conf:/etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;26380&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;26379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sentinel3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;redis:5.0.9&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel-3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-sentinel /etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./sentinel3.conf:/etc/redis/sentinel.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;26381&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;26379&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 用于解析处于不同局域网的主节点。&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 主从节点使用另一个 docker-compose 配置，这个 Docker 网络内无法直接解析对应域名。&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 可以用 docker network ls 列出 Docker 中的局域网。&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;external&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;redis-data_default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; 的意思是在后台运行。执行到这里就部署完成了。&lt;/p&gt;
&lt;p&gt;如果想查看 Redis 日志，可以使用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker-compose logs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是各个哨兵节点的日志：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-logs_hu_89880ca2e86e4564.webp&#34; width=&#34;1600&#34; height=&#34;865&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-logs_hu_3e98919d55189086.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-logs_hu_89880ca2e86e4564.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/sentinel-logs_hu_724c6258254b399a.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis Sentinel logs&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;185&#34; data-flex-basis=&#34;444px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;也能查看主从节点日志，只需切换到对应文件夹即可：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/redis-data-logs_hu_9ad70c381a485b47.webp&#34; width=&#34;1600&#34; height=&#34;706&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/redis-data-logs_hu_ef32101629986db0.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/redis-data-logs_hu_9ad70c381a485b47.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E5%93%A8%E5%85%B5/assets/redis-data-logs_hu_42c3262ad4897cfd.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;Redis data node logs&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;226&#34; data-flex-basis=&#34;543px&#34;&gt;
&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Redis 主从复制</title>
      <link>https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</link>
      <pubDate>Wed, 13 May 2026 15:29:13 +0000</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</guid>
      <description>&lt;h1 id=&#34;redis-主从复制&#34;&gt;
    Redis 主从复制
&lt;/h1&gt;
&lt;h2 id=&#34;概念与结构&#34;&gt;
    概念与结构
&lt;/h2&gt;
&lt;p&gt;Redis 主从复制指的是：让一个 Redis 主节点，也就是 &lt;code&gt;master&lt;/code&gt;，把自己的数据同步给一个或多个从节点，也就是 &lt;code&gt;replica&lt;/code&gt;。以前很多资料会写 &lt;code&gt;slave&lt;/code&gt;，现在更推荐使用 &lt;code&gt;replica&lt;/code&gt; 这个说法，但学习时看到 &lt;code&gt;slave&lt;/code&gt; 也要能对应上。&lt;/p&gt;
&lt;p&gt;主从复制最基本的结构是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;master
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ├── replica 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ├── replica 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  └── replica 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这种结构中，&lt;code&gt;master&lt;/code&gt; 通常负责处理写请求，&lt;code&gt;replica&lt;/code&gt; 负责接收主节点同步过来的数据，并承担一部分读请求。这样做的核心目的有三个：第一是读写分离，第二是提高可用性，第三是扩展系统的读取能力。Redis 官方文档也说明，基础复制模型是 leader-follower，也就是 master-replica 模型，replica 会尽量成为 master 的精确副本。&lt;/p&gt;
&lt;p&gt;实际理解时可以把主从复制想成&lt;u&gt;&lt;strong&gt;主库负责写，从库负责跟随&lt;/strong&gt;&lt;/u&gt;。客户端写入数据时，一般写到主节点；主节点接收到写命令后，再把这些变更同步给从节点。客户端读取数据时，可以从从节点读取，从而减轻主节点压力。&lt;/p&gt;
&lt;p&gt;不过要注意，Redis 默认使用异步复制，主节点不会每次写入都等待所有从节点确认完成后再返回结果，所以主从之间可能存在短暂的数据延迟。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233030-2p0t9uw_hu_584b8c1bc8011807.webp&#34; width=&#34;1600&#34; height=&#34;1185&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233030-2p0t9uw_hu_c7edcecaa2156a59.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233030-2p0t9uw_hu_584b8c1bc8011807.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233030-2p0t9uw_hu_84bdd6cce0c1eb22.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;135&#34; data-flex-basis=&#34;324px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;安全性只读与传输延迟&#34;&gt;
    安全性、只读与传输延迟
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安全性：Redis 主从复制可以提高系统可用性，但它不是严格意义上的“备份方案”。如果主节点发生误删、误写，这些错误操作也可能同步到从节点，导致从节点也会同步主节点，进而删除数据。所以如果数据安全非常重要，不能只依赖主从复制，还要考虑 RDB、AOF、定期备份、权限控制和运维策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;u&gt;&lt;strong&gt;官方文档里也特别提醒过一种情况：如果主节点关闭持久化，并且崩溃后自动重启，那么主节点可能以空数据集启动，从节点继续复制它时，也可能被同步成空数据集。&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;只读：从节点&lt;code&gt;replica&lt;/code&gt;通常配置为只读模式，由 &lt;code&gt;replica-read-only&lt;/code&gt; 控制，它能防止误把写请求打到从节点，降低主从数据不一致的风险。&lt;u&gt;&lt;strong&gt;如果主动尝试在从节点中修改数据，Redis 是会直接返回错误信息的。&lt;/strong&gt;&lt;/u&gt; 毕竟从节点来写数据，那就不算从节点了，那就是翻身做主人了！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输延迟：由于 Redis 默认是异步复制，写命令先在主节点执行，然后再通过复制流发送给从节点。如果网络波动、从节点处理较慢、复制缓冲区压力较大，就可能出现从节点短暂落后主节点的情况。读写分离场景下，如果业务对“刚写完马上读到最新数据”要求非常高，就不能随便把读请求分流到从节点。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;拓扑结构&#34;&gt;
    拓扑结构
&lt;/h2&gt;
&lt;p&gt;主从复制不只有“一主一从”。根据系统规模和用途，常见拓扑可以分成几类。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单主单从：它是最简单的结构，一个 master 对应一个 replica。这个结构容易理解，也适合学习和小规模部署。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234817-3qhpteq_hu_b3e65b6f572b1590.webp&#34; width=&#34;1600&#34; height=&#34;621&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234817-3qhpteq_hu_7ad1c6a6d0679b8a.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234817-3qhpteq_hu_b3e65b6f572b1590.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234817-3qhpteq_hu_a0d1a8551f89d375.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;257&#34; data-flex-basis=&#34;618px&#34;&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一主多从：一个 master 同步给多个 replica，这是比较常见的读扩展结构。多个从节点可以承担读请求，减轻主节点压力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234832-a08lxmz_hu_e2be0ec2aa7133eb.webp&#34; width=&#34;1600&#34; height=&#34;595&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234832-a08lxmz_hu_aa03d4efdf6609ab.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234832-a08lxmz_hu_e2be0ec2aa7133eb.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234832-a08lxmz_hu_9e90e3cace288bfb.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;268&#34; data-flex-basis=&#34;645px&#34;&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;链式或树状复制：Redis 支持 replica 连接到另一个 replica，形成级联复制结构。官方文档也提到，replica 可以接受其他 replica 的连接，从而形成类似级联的复制结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234846-jnk3d41_hu_10b4425fe757eca3.webp&#34; width=&#34;1600&#34; height=&#34;687&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234846-jnk3d41_hu_3cb41a0e76f90ead.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234846-jnk3d41_hu_10b4425fe757eca3.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234846-jnk3d41_hu_bd445a44face7498.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;232&#34; data-flex-basis=&#34;558px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;这种结构的好处是可以减轻 master 的出口压力，&lt;u&gt;&lt;strong&gt;但问题是链路变长后，复制延迟可能变大。越靠后的从节点，越可能落后主节点，具体要实现哪种要根据实际业务要求。&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第四种是在哨兵或集群场景中的复制关系。Sentinel 主要负责监控和故障转移，Cluster 则用于分片和高可用。它们不是主从复制本身，但实际项目中经常和主从复制配合出现。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234855-2r14vs7_hu_52467902c18128bb.webp&#34; width=&#34;1600&#34; height=&#34;658&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234855-2r14vs7_hu_a256a14c8b82be7a.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234855-2r14vs7_hu_52467902c18128bb.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513234855-2r14vs7_hu_da8882b465afb30a.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;243&#34; data-flex-basis=&#34;583px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;总结图片&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233046-92pvyph_hu_c5e6e2583fd6220a.webp&#34; width=&#34;1600&#34; height=&#34;1184&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233046-92pvyph_hu_852e0cc8aa0dd15c.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233046-92pvyph_hu_c5e6e2583fd6220a.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233046-92pvyph_hu_8f843a6cae9046f9.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;135&#34; data-flex-basis=&#34;324px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;基本流程&#34;&gt;
    基本流程
&lt;/h2&gt;
&lt;p&gt;Redis 主从复制的基本流程可以理解成三句话：先建立连接，再同步数据，最后持续跟随。&lt;/p&gt;
&lt;p&gt;当一个 replica 想要复制 master 时，它会先连接 master，并发起复制请求。Redis 使用 &lt;code&gt;PSYNC&lt;/code&gt; 机制进行同步判断。主节点会根据 replica 提供的信息判断：这次可以部分复制，还是必须全量复制。官方文档说明，如果部分重同步不可行，replica 会请求全量重同步；如果可行，就只获取断开期间缺失的那部分命令流。&lt;/p&gt;
&lt;p&gt;复制流程可以拆成下面几步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;replica 连接 master，&lt;u&gt;&lt;strong&gt;主动发起 PSYNC&lt;/strong&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;master 判断同步方式：是选择全量复制或部分复制&lt;/li&gt;
&lt;li&gt;如果需要全量复制，master 生成 RDB 快照&lt;/li&gt;
&lt;li&gt;master 将 RDB 发送给 replica&lt;/li&gt;
&lt;li&gt;replica 加载 RDB 数据&lt;/li&gt;
&lt;li&gt;master 再发送生成 RDB 期间积累的增量命令 &lt;strong&gt;（因为replica在加载RDB文件时 master 可能还会产生新的文件和命令~）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;进入稳定阶段，master 持续把写命令传播给 replica &lt;strong&gt;（建立 TCP 长连接）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;进入稳定阶段后，如果从节点也开启了 AOF，则从节点也要进行响应的 AOF 判断，在必要时执行 &lt;code&gt;bgrewriteaof&lt;/code&gt;命令&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;首次建立主从关系时，通常会走全量复制。因为 replica 没有旧的同步历史，master 只能给它一份完整数据。&lt;/p&gt;
&lt;p&gt;之后如果网络短暂中断再恢复，就有机会走部分复制，只补上中间缺失的命令。如何判断是走部分还是全量复制呢？下面章节会有详细说明~&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513235628-c8qtsx6_hu_1b8e563cc64dbf3.webp&#34; width=&#34;1600&#34; height=&#34;1207&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513235628-c8qtsx6_hu_483bb5460712b273.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513235628-c8qtsx6_hu_1b8e563cc64dbf3.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513235628-c8qtsx6_hu_e50b59e81a6c0b58.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;132&#34; data-flex-basis=&#34;318px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;replid-和-offset-的作用&#34;&gt;
    replid 和 offset 的作用
&lt;/h2&gt;
&lt;p&gt;Redis 主从复制要解决两个判断问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我们是不是同一条复制历史？&lt;/li&gt;
&lt;li&gt;已经同步到哪里了？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一个问题对应着 replid；第二个问题对应 offset&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;replid 可以理解为“复制历史身份”。官方文档说每个 master 都有一个 replication ID，它标记某一段数据集历史。master 和 replica 如果处在同一条复制历史上，就会共享对应的 replication ID。当从节点从属于主节点的话，它的 replication ID 就是主节点的 replication ID。相当于主节点靠 replication ID 来认小弟~&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;offset 可以理解为“复制进度”。master 产生复制流时，offset 会随着复制流字节数不断增长。replica 会记录自己已经处理到哪个 offset。如果从节点的 offset 与主节点的 offset 不一致，说明就有数据没有同步过来了（通常是这样）。官方文档也说明，replication ID + offset 可以标识 master 数据集的一个精确版本。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;举个栗子：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;master replid = abc, offset = 1000；replica replid = abc, offset = 800&lt;/p&gt;
&lt;p&gt;这说明它们属于同一条复制历史，但 replica 落后了 200 的复制流。如果 master 的&lt;u&gt;&lt;strong&gt;复制积压缓冲区&lt;/strong&gt;&lt;/u&gt;里还保留着 offset 800 之后的数据，那么 replica 只需要部分复制，补上缺失的那一段就可以。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果 replid 不一样，或者 offset 太旧，master 已经没有保留那段复制流，那么就只能走全量复制。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此处提到了积压缓冲区，我们来看看它是什么~&lt;/p&gt;
&lt;h3 id=&#34;积压缓冲区&#34;&gt;
    积压缓冲区
&lt;/h3&gt;
&lt;p&gt;积压缓冲区就是当主从复制建立后，master 会持续把写命令传播给 replica，同时也把这些写命令对应的复制流记录到复制积压缓冲区里。里面保存的是最近一段写命令的复制流和offset 开始值与最大值，直到从节点重新连接。&lt;/p&gt;
&lt;p&gt;重新连接后，主节点会检查 replication ID + offset，看看这个从节点还是不是之前的小弟。如果 replication ID 一致，就说明是曾经复制过的小弟，就会检查它的 offset，如果从节点的 offset 太旧了，主节点的 offset 的最小值都比从节点的 offset 大，此时就会丢弃，重新进行全量复制。（因为主节点在积压缓冲区的范围是有限的，若数据比较多，缓冲区中会丢弃更加久的数据，保留最近的数据，offset 会慢慢变大）&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003034-qzz5pul_hu_a1c0012d98a5fb23.webp&#34; width=&#34;1600&#34; height=&#34;1193&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003034-qzz5pul_hu_3b58c6455a7be29.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003034-qzz5pul_hu_a1c0012d98a5fb23.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003034-qzz5pul_hu_f98ffc7f581ab7e1.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;134&#34; data-flex-basis=&#34;321px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;全量复制&#34;&gt;
    全量复制
&lt;/h2&gt;
&lt;p&gt;全量复制，也叫 full resynchronization，意思是从节点需要重新获得一份完整的数据集。&lt;/p&gt;
&lt;p&gt;典型触发场景有三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一次建立主从关系&lt;/li&gt;
&lt;li&gt;replica 落后太多，offset 不在 backlog 范围内&lt;/li&gt;
&lt;li&gt;replid 不匹配，说明不是同一条复制历史（同一个小弟~）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;全量复制流程大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;replica 发起同步请求&lt;/li&gt;
&lt;li&gt;master 判断无法部分复制&lt;/li&gt;
&lt;li&gt;master 生成 RDB 快照&lt;/li&gt;
&lt;li&gt;master 将 RDB 文件发送给 replica&lt;/li&gt;
&lt;li&gt;replica 加载 RDB&lt;/li&gt;
&lt;li&gt;master 补发生成 RDB 期间收到的写命令&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;master 在生成 RDB 的同时，仍然可能继续接收新的写命令。这些新写命令不能丢，所以 master 会把这段时间的增量命令缓冲起来。等 replica 加载完 RDB 后，再把这些增量命令发过去。Redis 官方文档对全量同步的描述也是：master 后台生成 RDB 文件，同时缓冲新的写命令，RDB 传输并加载完成后，再把缓冲命令发送给 replica。&lt;/p&gt;
&lt;p&gt;全量复制的缺点是开销比较大。它涉及 RDB 生成、RDB 传输、replica 加载整个数据集。如果数据量很大，可能带来磁盘、网络、CPU、内存等压力。&lt;/p&gt;
&lt;h2 id=&#34;部分复制&#34;&gt;
    部分复制
&lt;/h2&gt;
&lt;p&gt;部分复制，也叫 partial resynchronization，意思是 replica 不需要重新同步整个数据集，只需要补上自己断线期间缺失的那部分命令。&lt;/p&gt;
&lt;p&gt;部分复制通常发生在 replica 和 master 短暂断开后重新连接时。replica 会向 master 发送自己保存的 &lt;code&gt;replid&lt;/code&gt; 和 &lt;code&gt;offset&lt;/code&gt;，master 根据这些信息判断能不能只补增量。官方文档说明，replica 连接 master 时会使用 &lt;code&gt;PSYNC&lt;/code&gt; 发送旧 master 的 replication ID 和已经处理的 offset；如果 master 缓冲区里还有对应数据，就可以发送增量部分，否则走全量同步。&lt;/p&gt;
&lt;p&gt;部分复制的判断可以简化成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;如果 replid 一样，并且 offset 还在复制积压缓冲区范围内：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    走部分复制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    只补缺失命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;否则：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    走全量复制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    重新同步完整数据
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;部分复制的优点很明显：更快、更轻量、网络开销更小。对于短暂网络抖动、从节点短暂掉线这种情况，部分复制非常重要。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233138-t07v5in_hu_86e47d1b701fe6b1.webp&#34; width=&#34;1600&#34; height=&#34;1188&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233138-t07v5in_hu_94590be88d8aa63f.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233138-t07v5in_hu_86e47d1b701fe6b1.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233138-t07v5in_hu_597e3236f93eada4.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;134&#34; data-flex-basis=&#34;323px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;实时复制&#34;&gt;
    实时复制
&lt;/h2&gt;
&lt;p&gt;当全量复制或部分复制完成后，主从关系进入稳定阶段。这个阶段 master 会继续接收客户端写命令，并把这些写命令传播给 replica。replica 按顺序执行收到的命令，从而让数据尽量跟上 master。这个阶段也可以叫命令传播阶段，或者增量复制阶段。&lt;/p&gt;
&lt;p&gt;实时复制依赖的是主从节点之间的 TCP 长连接传输~&lt;/p&gt;
&lt;p&gt;基本流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户端写入 master&lt;/li&gt;
&lt;li&gt;master 执行写命令&lt;/li&gt;
&lt;li&gt;master 将写命令传播给 replica&lt;/li&gt;
&lt;li&gt;replica 顺序执行写命令&lt;/li&gt;
&lt;li&gt;主从数据继续保持接近一致&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在进行实时复制时，需要保证连接处于持续可用的状态，所以引入了“心跳包”的机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主节点默认每隔一段时间就会给从节点发送一个 ping 命令，从节点收到就回 pong&lt;/li&gt;
&lt;li&gt;从节点默认每个一个时间周期就会给主节点发送一个特定的请求，会上报当前复制主节点数据的进度（offset）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实时复制不代表强一致。因为复制仍然以异步为主，网络和执行时间都会带来延迟。&lt;u&gt;&lt;strong&gt;主从数据持续接近一致，而不是任何时刻都绝对一致。&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;
&lt;h3 id=&#34;主从连接与心跳机制的区别&#34;&gt;
    主从连接与心跳机制的区别
&lt;/h3&gt;
&lt;p&gt;主从连接和心跳机制有联系，但不是一回事。主从连接强调的是 replica 与 master 建立复制通道，完成握手并确认同步方式；&lt;/p&gt;
&lt;p&gt;心跳机制强调的是复制关系建立之后，双方持续保持联系，replica 周期性向 master 汇报同步进度，master 借此判断从节点是否在线、是否落后。如果心跳异常或连接中断，从节点会重新连接 master，并根据 &lt;code&gt;replid + offset&lt;/code&gt; 尝试进行部分复制。&lt;/p&gt;
&lt;h2 id=&#34;全量复制的无硬盘模式优化&#34;&gt;
    全量复制的无硬盘模式优化
&lt;/h2&gt;
&lt;p&gt;无硬盘复制即 diskless replication&lt;/p&gt;
&lt;p&gt;正常全量复制时，master 需要生成 RDB 文件。传统方式是先把 RDB 写到磁盘，然后再从磁盘读取并发送给 replica，流程大概为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;master 生成 RDB 到磁盘&lt;/li&gt;
&lt;li&gt;master 从磁盘读取 RDB&lt;/li&gt;
&lt;li&gt;发送给 replica&lt;/li&gt;
&lt;li&gt;replica 加载 RDB&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;无硬盘复制，也就是 diskless replication，是对全量复制阶段的优化。它的核心思想是：master 不先把 RDB 落盘，而是直接通过 socket 把 RDB 流式发送给 replica。在 diskless replication 中子进程会直接通过网络把 RDB 发给 replicas，而不使用磁盘作为中间存储。&lt;/p&gt;
&lt;p&gt;可以这样对比：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003336-w0e3zdk_hu_8bbcdd39036328cf.webp&#34; width=&#34;1600&#34; height=&#34;782&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003336-w0e3zdk_hu_60c6c8c76a3f40be.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003336-w0e3zdk_hu_8bbcdd39036328cf.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260514003336-w0e3zdk_hu_c190510434c1ea6.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;204&#34; data-flex-basis=&#34;491px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;无硬盘复制的好处是减少磁盘 I/O，尤其适合磁盘压力大、数据集较大、多个 replica 同步的场景。不过它不一定在所有场景都更优。如果网络条件差，或者需要更稳定的落盘中间文件，普通方式也可能更合适。&lt;/p&gt;
&lt;p&gt;另外要注意：无硬盘复制优化的是全量复制阶段，不是部分复制阶段。部分复制本来就是补增量命令，不需要重新传完整 RDB。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233215-802ygu1_hu_667b9ee9cd481486.webp&#34; width=&#34;1600&#34; height=&#34;1187&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233215-802ygu1_hu_1c694c9df5297d50.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233215-802ygu1_hu_667b9ee9cd481486.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233215-802ygu1_hu_6c56cdef2b06d0af.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;134&#34; data-flex-basis=&#34;323px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;runid-与-replid-的区别&#34;&gt;
    runid 与 replid 的区别
&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;runid&lt;/code&gt; 和 &lt;code&gt;replid&lt;/code&gt; 都像“身份标识”，但它们不是一个东西。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;runid&lt;/code&gt; 是 Redis 实例自身的运行时 ID。你可以把它理解成“这个 Redis 进程的身份证”。Redis &lt;code&gt;INFO&lt;/code&gt; 命令文档中，&lt;code&gt;run_id&lt;/code&gt; 被描述为用于识别 Redis server 的随机值，也会被 Sentinel 和 Cluster 使用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;replid&lt;/code&gt; 是复制历史 ID。它不是用来识别 Redis 进程本身，而是用来识别某一段复制历史。主从复制、PSYNC、部分复制判断时，更关键的是 &lt;code&gt;replid + offset&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;二者可以这样区分：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;对比项&lt;/th&gt;
          &lt;th&gt;runid&lt;/th&gt;
          &lt;th&gt;replid&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;关注对象&lt;/td&gt;
          &lt;td&gt;Redis 实例本身&lt;/td&gt;
          &lt;td&gt;复制历史，redis 服务重启后就不一样了&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;用途&lt;/td&gt;
          &lt;td&gt;识别 server 实例&lt;/td&gt;
          &lt;td&gt;判断复制历史、辅助部分复制&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;是否直接决定部分复制&lt;/td&gt;
          &lt;td&gt;不是关键&lt;/td&gt;
          &lt;td&gt;是关键参考&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;常见位置&lt;/td&gt;
          &lt;td&gt;INFO server 里的&lt;code&gt;run_id&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;INFO replication 里的&lt;code&gt;master_replid&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Redis 还可能维护两个 replication ID：当前 &lt;code&gt;master_replid&lt;/code&gt; 和 &lt;code&gt;master_replid2&lt;/code&gt;。官方文档说明，第二个 replication ID 是为了故障转移后的部分重同步服务的；当 replica 被提升为 master 后，它会保留旧 master 的复制 ID 信息，从而尽量让其他 replica 不必全部重新全量复制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233231-axrb9rc_hu_4a5b800dcc84c9e2.webp&#34; width=&#34;1600&#34; height=&#34;1194&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233231-axrb9rc_hu_1ddd954c12f049f0.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233231-axrb9rc_hu_4a5b800dcc84c9e2.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/assets/image-20260513233231-axrb9rc_hu_41a96c73fb9d32fb.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;133&#34; data-flex-basis=&#34;321px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;最小实践配置&#34;&gt;
    最小实践配置
&lt;/h2&gt;
&lt;p&gt;如果只是做学习 demo，可以启动两个 Redis 实例。假设主节点端口是 &lt;code&gt;6379&lt;/code&gt;，从节点端口是 &lt;code&gt;6380&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;从节点配置中可以写：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;replicaof 127.0.0.1 6379
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者在从节点运行时执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;REPLICAOF 127.0.0.1 6379
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Redis 官方文档也说明，配置基础复制可以在 replica 配置文件里添加 &lt;code&gt;replicaof &amp;lt;master-ip&amp;gt; &amp;lt;master-port&amp;gt;&lt;/code&gt;，也可以通过 &lt;code&gt;REPLICAOF&lt;/code&gt; 命令让实例开始同步 master。&lt;/p&gt;
&lt;p&gt;常用观察命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INFO replication
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ROLE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;INFO replication&lt;/code&gt; 可以看到当前实例的复制角色、复制 ID、复制偏移量、连接的从节点数量等信息。&lt;code&gt;ROLE&lt;/code&gt; 可以直接查看当前节点是 master 还是 replica，以及复制状态。Redis 官方文档也提到，&lt;code&gt;INFO replication&lt;/code&gt; 和 &lt;code&gt;ROLE&lt;/code&gt; 都能提供当前复制相关参数。&lt;/p&gt;
&lt;h2 id=&#34;从节点晋升主节点&#34;&gt;
    从节点晋升主节点
&lt;/h2&gt;
&lt;p&gt;从节点断开主节点有两种情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从节点主动断开：使用&lt;code&gt;slaveof no one&lt;/code&gt;，这时候从节点就能晋升为主节点，这意味着我们主动干预了 Redis 的结构&lt;/li&gt;
&lt;li&gt;主节点挂了：这个时候从节点不会主动晋升为主节点，它必须通过人工干预的方式，将主节点重新启动&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;复习总结&#34;&gt;
    复习总结
&lt;/h2&gt;
&lt;p&gt;Redis 主从复制的核心，是 master 持续把自己的数据变化同步给 replica。它常用于读写分离、提高可用性和扩展读能力，但 Redis 默认是异步复制，所以主从之间可能有短暂延迟。&lt;/p&gt;
&lt;p&gt;复制流程可以理解为：replica 先连接 master，然后通过 PSYNC 请求同步。master 根据 &lt;code&gt;replid&lt;/code&gt; 和 &lt;code&gt;offset&lt;/code&gt; 判断是全量复制还是部分复制。全量复制会发送完整 RDB，再补发期间的增量命令；部分复制只补断开期间缺失的命令。稳定后，master 持续把写命令传播给 replica，形成实时复制。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;replid&lt;/code&gt; 表示复制历史，&lt;code&gt;offset&lt;/code&gt; 表示同步进度。&lt;code&gt;runid&lt;/code&gt; 表示 Redis 实例自身身份，不要和 &lt;code&gt;replid&lt;/code&gt; 混淆。无硬盘复制是全量复制阶段的优化，它通过 socket 直接发送 RDB，减少磁盘 I/O。&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Reids 事务</title>
      <link>https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/</link>
      <pubDate>Tue, 12 May 2026 07:48:34 +0000</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/</guid>
      <description>&lt;h1 id=&#34;reids-事务&#34;&gt;
    Reids 事务
&lt;/h1&gt;
&lt;h2 id=&#34;核心意义&#34;&gt;
    核心意义
&lt;/h2&gt;
&lt;p&gt;Redis 事务的主要作用，是把多条命令“打包”为一组，然后按照顺序执行。它解决的核心问题不是像 MySQL 那样提供完整的强事务能力，而是在执行这一组命令时，尽量避免其他客户端的命令插入到这组操作中间。&lt;/p&gt;
&lt;p&gt;可以先用一个生活例子理解。&lt;/p&gt;
&lt;p&gt;你和朋友约好晚上去吃烧烤。你先到了烧烤店，点了牛肉串、羊肉串、五花肉等，但是你告诉服务员：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“我人还没齐，你先把单子记下来，先别急着烤。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;过了一会儿，朋友到了，又加了一些主菜和烤腰子。最后你说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“好了，开始烤吧。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个过程里，前面点的和后面追加的菜，会被当成同一组订单一起处理。重点是：这组订单中间不会被别人插队。&lt;/p&gt;
&lt;p&gt;对应到 Redis 事务里也是类似的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI        开启事务
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;命令1         进入队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;命令2         进入队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;命令3         进入队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXEC         执行事务
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;MULTI&lt;/code&gt; 之后、&lt;code&gt;EXEC&lt;/code&gt; 之前，客户端发送的命令不会立刻执行，而是先进入事务队列。只有当 Redis 收到 &lt;code&gt;EXEC&lt;/code&gt; 命令时，才会把队列里的命令按顺序执行。&lt;/p&gt;
&lt;p&gt;对应图片：&lt;br&gt;
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512224943-2vftui1_hu_ccdec4a13c02d68c.webp&#34; width=&#34;1600&#34; height=&#34;1133&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512224943-2vftui1_hu_19a5d7e9d45aa479.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512224943-2vftui1_hu_ccdec4a13c02d68c.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512224943-2vftui1_hu_b05763630f54b252.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;141&#34; data-flex-basis=&#34;338px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;执行机制&#34;&gt;
    执行机制
&lt;/h2&gt;
&lt;p&gt;再说说它的执行机制，Redis 事务的基本流程是：&lt;/p&gt;
&lt;p&gt;客户端发送 MULTI -&amp;gt; Redis 开启事务状态 -&amp;gt; 后续命令进入队列，返回 QUEUED -&amp;gt; 客户端发送 EXEC -&amp;gt; Redis 按顺序执行队列中的命令 -&amp;gt; 返回执行结果&lt;/p&gt;
&lt;p&gt;执行过程可以理解为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI：告诉 Redis，我要开始打包命令了
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SET name lin：先别执行，放进队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INCR count：先别执行，放进队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXPIRE name 60：先别执行，放进队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXEC：现在开始按顺序执行队列里的命令
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在事务执行期间，Redis 会连续执行这组命令，中间不会穿插其他客户端的命令。这个特性和 Redis 的单线程命令执行模型有关。但是要注意，Redis 事务不是 MySQL 那种完整强事务。它更像是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;命令队列 + 顺序提交。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对应图片：&lt;br&gt;
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512225249-y395qsd_hu_bdf8c84484dce3bf.webp&#34; width=&#34;1600&#34; height=&#34;1137&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512225249-y395qsd_hu_d8986a76ed043dce.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512225249-y395qsd_hu_bdf8c84484dce3bf.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512225249-y395qsd_hu_f312b6cb743ec9bd.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;140&#34; data-flex-basis=&#34;337px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;常用命令&#34;&gt;
    常用命令
&lt;/h2&gt;
&lt;p&gt;Redis 事务相关的核心命令主要有 5 个&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;命令&lt;/th&gt;
          &lt;th&gt;作用&lt;/th&gt;
          &lt;th&gt;理解&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;MULTI&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;开启事务&lt;/td&gt;
          &lt;td&gt;后续命令不立即执行，而是进入队列&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;EXEC&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;执行事务&lt;/td&gt;
          &lt;td&gt;按顺序执行队列里的所有命令&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;DISCARD&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;取消事务&lt;/td&gt;
          &lt;td&gt;清空事务队列，不执行&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;WATCH&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;监视 key&lt;/td&gt;
          &lt;td&gt;用于实现乐观锁&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;UNWATCH&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;取消监视&lt;/td&gt;
          &lt;td&gt;取消对 key 的监控&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;MULTI：开启事务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示开启一个事务。&lt;/p&gt;
&lt;p&gt;执行 &lt;code&gt;MULTI&lt;/code&gt; 后，客户端再发送的命令会进入事务队列，而不是立刻执行。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SET k1 v1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SET k2 v2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候 Redis 通常会返回：QUEUED，表示命令已经入队啦！没等到 &lt;code&gt;EXEC&lt;/code&gt; 我是不会执行的！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EXEC：提交并执行事务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示提交事务。&lt;/p&gt;
&lt;p&gt;执行 &lt;code&gt;EXEC&lt;/code&gt; 后，Redis 会把事务队列中的命令按照进入队列的顺序依次执行。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SET name tom
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INCR count
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXEC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;真正修改数据的时间点不是 &lt;code&gt;SET&lt;/code&gt; 和 &lt;code&gt;INCR&lt;/code&gt; 发出时，而是 &lt;code&gt;EXEC&lt;/code&gt; 发出之后。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DISCARD：取消事务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示取消当前事务，并清空事务队列。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SET name tom
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INCR count
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DISCARD
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行 &lt;code&gt;DISCARD&lt;/code&gt; 后，前面入队的 &lt;code&gt;SET name tom&lt;/code&gt; 和 &lt;code&gt;INCR count&lt;/code&gt; 都不会执行。同时要注意，如果开启事务后，服务器突然挂了，重新启动事务就不存在咯，也相当于discard的效果！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WATCH：监视 key&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用于监视一个或多个 key，常用来实现乐观锁。&lt;/p&gt;
&lt;p&gt;基本思想是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我先看一下这个 key 的值，然后准备修改它。如果在我提交事务之前，这个 key 被别人改过了，那我的事务就提交失败。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;具体如何使用呢？在开启事务前watch一下key即可~&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WATCH stock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET stock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DECR stock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXEC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果在 &lt;code&gt;WATCH stock&lt;/code&gt; 之后、&lt;code&gt;EXEC&lt;/code&gt; 之前，有其他客户端修改了 &lt;code&gt;stock&lt;/code&gt;，那么当前客户端的 &lt;code&gt;EXEC&lt;/code&gt; 会失败。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UNWATCH：取消监视&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用于取消对 key 的监视。通常当你不想继续执行当前事务逻辑时，可以使用它取消监控。&lt;/p&gt;
&lt;h2 id=&#34;与-mysql-事务的区别&#34;&gt;
    与 MySQL 事务的区别
&lt;/h2&gt;
&lt;p&gt;它们不是一个级别的东西，Redis 事务更轻量、更简单；MySQL 事务更完整、更严格。&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;对比项&lt;/th&gt;
          &lt;th&gt;Redis 事务&lt;/th&gt;
          &lt;th&gt;MySQL 事务&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;定位&lt;/td&gt;
          &lt;td&gt;命令打包 + 顺序执行&lt;/td&gt;
          &lt;td&gt;完整数据库事务&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;原子性&lt;/td&gt;
          &lt;td&gt;更像“整体提交，不被插队”，只强调全部执行&lt;/td&gt;
          &lt;td&gt;强调真正的 all-or-nothing，确保全部都可以正确执行&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;回滚&lt;/td&gt;
          &lt;td&gt;不支持 MySQL 那样的自动回滚&lt;/td&gt;
          &lt;td&gt;支持回滚&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;隔离性&lt;/td&gt;
          &lt;td&gt;依赖 Redis 单线程顺序执行，只是事务执行期间不被插队&lt;/td&gt;
          &lt;td&gt;有完整隔离级别，如读已提交、可重复读等&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;一致性&lt;/td&gt;
          &lt;td&gt;通常不作为强一致事务理解&lt;/td&gt;
          &lt;td&gt;ACID 语义更完整&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;适用场景&lt;/td&gt;
          &lt;td&gt;缓存、计数器、轻量批量更新&lt;/td&gt;
          &lt;td&gt;订单、支付、转账等强事务业务&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对应图片：&lt;br&gt;
&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512230310-1ozjs43_hu_f7d4d4911c0a6908.webp&#34; width=&#34;1600&#34; height=&#34;1126&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512230310-1ozjs43_hu_bcf4b9b1b6adefc6.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512230310-1ozjs43_hu_f7d4d4911c0a6908.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512230310-1ozjs43_hu_7ebc8fbe9cb06259.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;142&#34; data-flex-basis=&#34;340px&#34;&gt;
&lt;/p&gt;
&lt;h2 id=&#34;原子性&#34;&gt;
    原子性
&lt;/h2&gt;
&lt;p&gt;这个地方很容易混乱，也是课堂板书里重点强调的地方。&lt;/p&gt;
&lt;h3 id=&#34;单条-redis-命令通常具有原子性&#34;&gt;
    单条 Redis 命令通常具有原子性
&lt;/h3&gt;
&lt;p&gt;Redis 本身是单线程执行命令的，同一时刻只会处理一个命令。&lt;/p&gt;
&lt;p&gt;所以像下面这种单条命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INCR count
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它本身通常可以理解为原子操作。不会出现加到一半被其他命令插进来的情况。&lt;/p&gt;
&lt;h3 id=&#34;redis-事务的原子性比较弱&#34;&gt;
    Redis 事务的“原子性”比较弱
&lt;/h3&gt;
&lt;p&gt;Redis 事务的原子性，不能完全按照 MySQL 的事务原子性理解。&lt;/p&gt;
&lt;p&gt;Redis 事务可以做到一组命令按顺序执行，执行过程中不会被其他客户端命令插队&lt;/p&gt;
&lt;p&gt;但是它做不到 MySQL 那种要么全部成功、要么失败后全部回滚，它只确认命令能全部执行，但不保证完全对~&lt;/p&gt;
&lt;p&gt;这就是 Redis 事务和 MySQL 事务非常大的区别。&lt;/p&gt;
&lt;h3 id=&#34;mysql-的原子性更严格&#34;&gt;
    MySQL 的原子性更严格
&lt;/h3&gt;
&lt;p&gt;MySQL 事务强调的是要么全部成功、要么全部失败，而且支持失败后可以回滚的功能&lt;/p&gt;
&lt;p&gt;Redis 并没有实现这种功能，虽然这种功能强大，但也是需要一定的性能开销，所以 Redis 没有实现这种功能开发者可能也有一定的考虑~&lt;/p&gt;
&lt;h2 id=&#34;watch-实现思想乐观锁&#34;&gt;
    WATCH 实现思想：乐观锁
&lt;/h2&gt;
&lt;p&gt;详细来说，Redis 的 watch 是基于版本号&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;这样的机制实现了乐观锁&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;版本号这个概念在 CAS&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; 中的 ABA 问题&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;也涉及过，其思想方法和实现方式上是十分相似的~&lt;/p&gt;
&lt;p&gt;虽然说我之前的博客也有对乐观锁、CAS 和 ABA 问题有详细的讲解，但不影响阅读体验，就在这简略介绍下&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234646-cgzlkhb_hu_7a587c5d83239bab.webp&#34; width=&#34;1600&#34; height=&#34;1116&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234646-cgzlkhb_hu_f56b93dbc40a235d.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234646-cgzlkhb_hu_7a587c5d83239bab.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234646-cgzlkhb_hu_b96e33dc4a4e5a92.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;143&#34; data-flex-basis=&#34;344px&#34;&gt;
&lt;/p&gt;
&lt;h3 id=&#34;什么是乐观锁&#34;&gt;
    什么是乐观锁？
&lt;/h3&gt;
&lt;p&gt;乐观锁的想法是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我先假设冲突不会发生，所以不提前把资源锁死；等真正提交时，再检查有没有被别人改过。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;悲观锁是：我觉得一定会有人抢，所以我先加锁。别人想操作，必须等我释放锁。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;乐观锁是：我觉得大概率不会冲突，所以大家都可以先操作，提交时再检查有没有冲突，如果冲突了，我就失败重试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;版本号&#34;&gt;
    版本号
&lt;/h3&gt;
&lt;p&gt;当执行&lt;code&gt;watch key&lt;/code&gt;时，这时就会给 key 分配一个版本号，此处的版本号可以理解为“一个整数”，key 在每次修改后，版本号就会+1，此处假设 watch 之后 key 的版本号默认为1。&lt;/p&gt;
&lt;p&gt;然后有两个客户端，客户端1执行了watch key，然后开启了事务，客户端2对key进行了更新操作，此时版本号+1。客户端1在队列中也安排了key的更新操作，然后客户端1 执行 exec，（exec 执行时间在客户端2对 key 更新操作之后）。此时 exec 在执行事务命令之后就会做出判定，判定watch时候的版本号与现在的版本号是否一致：如果一致，说明当前key在事务开启到最终执行的这个过程中都没有别的客户端进行修改，就能正常执行；反之，如果不一致，说明 key 在其他客户端就改过了，因此就丢弃了这个事务的操作，返回 nil ~&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234621-c3hytfo_hu_d515ece130abd106.webp&#34; width=&#34;1600&#34; height=&#34;1125&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234621-c3hytfo_hu_dbb9cc4ae0fefc76.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234621-c3hytfo_hu_d515ece130abd106.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512234621-c3hytfo_hu_ceb34395ea1b760c.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;142&#34; data-flex-basis=&#34;341px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;watch&lt;/code&gt; 本质上不是给 key 上了一层字面意义上的 “锁”，而是观察 key 是否被改过！&lt;/p&gt;
&lt;p&gt;它能解决一部分问题，但不能自动解决所有问题。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MULTI/EXEC&lt;/code&gt; 能保证多条命令作为一组提交且按照顺序执行，执行过程中不被其他客户端命令插队&lt;/p&gt;
&lt;p&gt;但是库存问题的关键通常不是简单地“几条命令一起执行”，而是先判断库存是否足够再决定要不要扣减&lt;/p&gt;
&lt;p&gt;而 Redis 事务有一个限制：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;事务中的命令是先入队，EXEC 时才执行。客户端不能在事务执行过程中，根据上一条命令的结果临时决定下一条命令是否执行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说，下面这种思路在 Redis 事务里不够安全&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET stock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;如果 stock &amp;gt; 0:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    DECR stock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EXEC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为 &lt;code&gt;GET stock&lt;/code&gt; 在 &lt;code&gt;EXEC&lt;/code&gt; 前只是进入队列，并没有真正返回可用于客户端判断的结果。&lt;/p&gt;
&lt;p&gt;所以，单靠 &lt;code&gt;MULTI/EXEC&lt;/code&gt; 不适合处理复杂的“先读结果，再根据结果决定是否写”的业务。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512232618-w3cyzvl_hu_7d05acef560f9a08.webp&#34; width=&#34;1600&#34; height=&#34;1127&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512232618-w3cyzvl_hu_128924a2d90dfd70.webp 800w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512232618-w3cyzvl_hu_7d05acef560f9a08.webp 1600w, https://Jul1en-Lin.github.io/p/reids-%E4%BA%8B%E5%8A%A1/assets/image-20260512232618-w3cyzvl_hu_c7ddcb632d61a3d6.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;142&#34; data-flex-basis=&#34;340px&#34;&gt;
&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;ABA的核心是：&lt;br&gt;
在通过A的值相同判定是否有插队，由于次数的修改有加也有减，就可能会出现ABA的问题，那么有一些解决方案：限制此处的操作（只能加或者只能减）、或者引入“版本号”概念，每次修改都让“版本号”+1，再次使用判定的时候就不是用值来判定了，而是看版本号&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;h1 id=&#34;乐观锁--悲观锁&#34;&gt;
    乐观锁 &amp;amp; 悲观锁
&lt;/h1&gt;
&lt;p&gt;加锁的时候预测这个锁出现竞争性的可能性大还是小？&lt;/p&gt;
&lt;p&gt;预测这个锁出现竞争可能性小 —— 乐观锁&lt;/p&gt;
&lt;p&gt;预测这个锁出现竞争可能性大 —— 悲观锁&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;CAS是什么？&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;CAS的ABA问题是怎么样的&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    <item>
      <title>Redis 进阶</title>
      <link>https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/</link>
      <pubDate>Tue, 21 Apr 2026 09:38:54 +0000</pubDate>
      <guid>https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/</guid>
      <description>&lt;h1 id=&#34;redis-进阶&#34;&gt;
    Redis 进阶
&lt;/h1&gt;
&lt;h1 id=&#34;持久化&#34;&gt;
    持久化
&lt;/h1&gt;
&lt;p&gt;Redis 的持久化有两个策略&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RDB -&amp;gt; Redis DataBase&lt;/li&gt;
&lt;li&gt;AOF -&amp;gt; Append Only File&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rdb&#34;&gt;
    RDB
&lt;/h2&gt;
&lt;p&gt;RDB 的触发时机有两种，一种是手动存储，一种是定时存储。将数据备份到数据库中，通常存在一个后缀名为 .rdb的文件&lt;/p&gt;
&lt;p&gt;定时存储通过配置文件修改&lt;/p&gt;
&lt;p&gt;主要讲手动存储，它有两个命令，&lt;code&gt;save&lt;/code&gt; 和 &lt;code&gt;bgsave&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;save：执行&lt;code&gt;save&lt;/code&gt;操作，Redis 会全力以赴的进行快照&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;生成的工作，此时就会阻塞 Redis 客户端的其他命令，达到类似 &lt;code&gt;keys *&lt;/code&gt; 的效果&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bgsave：bgsave 就是background save，在后台生成一个&lt;u&gt;&lt;strong&gt;新的进程&lt;/strong&gt;&lt;/u&gt;，来进行并发的编程。新的进程会 fork 一份父进程的完整数据（包括 pcb，内存中的虚拟地址，文件描述符表等&amp;hellip;..），将完整数据存入到 .rdb 文件中，当bgsave执行过程中，若有其他的数据插入，则可能会有迟滞性，因为新的数据不同步到子进程。&lt;/p&gt;
&lt;p&gt;注意：由于子进程有着跟父类一样的文件描述符表，故子进程也可以对文件进行读写操作。&lt;/p&gt;
&lt;p&gt;执行逻辑为：判定是否存在其他的子进程，若存在则将当前的bgsave返回，否则新建一个子进程。&lt;/p&gt;
&lt;p&gt;此处的 fork 拷贝操作是“写时拷贝”的机制实现的——即如果父进程与子进程里的数据是一模一样的，父进程与子进程会共用同一份内存空间，当对内存数据做出修改后，才会触发真正的物理内存的拷贝。新的数据会插入到父进程中，子进程数据保持原有的数据不更新。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260421181344-uy0eg7i_hu_eb9540132bba30b6.webp&#34; width=&#34;1600&#34; height=&#34;1193&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260421181344-uy0eg7i_hu_782708db10f96272.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260421181344-uy0eg7i_hu_eb9540132bba30b6.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260421181344-uy0eg7i_hu_fac2cd78bee8f5df.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;134&#34; data-flex-basis=&#34;321px&#34;&gt;
&lt;/p&gt;
&lt;p&gt;RDB 这个二进制文件默认通过二进制的方式将内存中的数据以压缩的形式保存&lt;/p&gt;
&lt;p&gt;后续 Redis 重启，会重新加载这个 RDB 文件，若 RDB 损坏则可能启动失败。针对 RDB 损坏的问题，自带了一个 RDB 的检查工具&lt;code&gt;redis-check-rdb*&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;RDB 的持久化操作是可以重复执行的，此时会生成一个 RDB 镜像文件，将快照数据先保存至一个临时的文件中，当快照生成完毕后，将旧的 RDB 文件删除，将临时的文件夹改名为&lt;code&gt;dump.rdb&lt;/code&gt;（默认文件名）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;RDB 的优缺点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RDB 是紧凑压缩过的二进制文件，代表了 Redis 中某个时间点上的数据快照，非常适用于备份&lt;/li&gt;
&lt;li&gt;Redis 加载 RDB 恢复数据远远快于 AOP&lt;/li&gt;
&lt;li&gt;RDB 的这种方式存储就决定了它的数据备份无法达到数据的实时持久化，因为每次的 bgsave 操作都要 fork 一个子进程出来，这是一个重量级的操作&lt;/li&gt;
&lt;li&gt;RDB 使用的是特定的二进制格式保存，且随着时间迁移，Redis 会有多个 RDB 版本，可能会有兼容性问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;aof&#34;&gt;
    AOF
&lt;/h2&gt;
&lt;p&gt;AOF 以日志形式记录 Redis 的&lt;strong&gt;写操作命令&lt;/strong&gt;，重启时重新执行这些命令恢复数据，默认是后缀为 .aof的文件。&lt;/p&gt;
&lt;p&gt;写入策略通过配置文件设置，有三种模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;always&lt;/code&gt;：每次写命令都立即刷盘，数据最安全，但性能开销最大&lt;/li&gt;
&lt;li&gt;&lt;code&gt;everysec&lt;/code&gt;：每秒刷盘一次（默认），最多丢失 1 秒数据，兼顾性能与安全&lt;/li&gt;
&lt;li&gt;&lt;code&gt;no&lt;/code&gt;：由操作系统决定刷盘时机，性能最高，但数据安全性最低&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;AOF 重写&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着写操作增多，AOF 文件会持续膨胀。Redis 提供重写机制压缩文件体积，命令为 &lt;code&gt;bgrewriteaof&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260501173736-zvzy0py_hu_53f1568812e10966.webp&#34; width=&#34;1600&#34; height=&#34;1109&#34; srcset=&#34;https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260501173736-zvzy0py_hu_451fcfd967d32230.webp 800w, https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260501173736-zvzy0py_hu_53f1568812e10966.webp 1600w, https://Jul1en-Lin.github.io/p/redis-%E8%BF%9B%E9%98%B6/assets/image-20260501173736-zvzy0py_hu_a6269818dfb7ed41.webp 2400w&#34; sizes=&#34;(max-width: 860px) calc(100vw - 40px), 1060px&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; alt=&#34;image&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;144&#34; data-flex-basis=&#34;346px&#34;&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类似 &lt;code&gt;bgsave&lt;/code&gt;，fork 出一个子进程，基于&lt;strong&gt;当前内存数据&lt;/strong&gt;生成最新且最精简的命令集&lt;/li&gt;
&lt;li&gt;重写期间的新写入命令会同时写入旧的 AOF 文件和 AOF 重写缓冲区&lt;/li&gt;
&lt;li&gt;子进程完成重写后，将缓冲区的增量命令追加到新文件，最后用新文件替换旧文件&lt;/li&gt;
&lt;li&gt;同样利用&amp;quot;写时拷贝&amp;quot;机制，避免全量内存复制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AOF 文件以&lt;strong&gt;文本协议&lt;/strong&gt;存储，具备可读性，但体积通常比 RDB 大。若文件损坏，可使用自带的 &lt;code&gt;redis-check-aof&lt;/code&gt; 工具修复。&lt;/p&gt;
&lt;p&gt;Redis 重启时若同时存在 AOF 和 RDB，&lt;strong&gt;默认优先加载 AOF。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AOF 的优缺点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据安全性更高，通过合理的 &lt;code&gt;appendfsync&lt;/code&gt; 策略可实现近实时持久化&lt;/li&gt;
&lt;li&gt;文件为文本格式，易读且兼容性好，没有 RDB 的版本兼容问题&lt;/li&gt;
&lt;li&gt;文件体积通常大于 RDB，恢复速度比 RDB 慢（需逐条重放命令）&lt;/li&gt;
&lt;li&gt;在高并发写入场景下，&lt;code&gt;always&lt;/code&gt; 策略会显著影响性能；&lt;code&gt;everysec&lt;/code&gt; 模式下若发生故障仍可能丢失 1 秒数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;h1 id=&#34;快照&#34;&gt;
    快照
&lt;/h1&gt;
&lt;p&gt;快照（Snapshot）是指系统在某一特定时刻的完整逻辑状态记录。它类似于对运行中的数据进行“拍照”，保留该瞬间的所有信息，即便后续原始数据发生变化，快照内容依然停留在抓拍的那一刻。&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
  </channel>
</rss>
