<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Aron-Blog</title><description>No description</description><link>https://aronblake.cloud/</link><templateTheme>Firefly</templateTheme><templateThemeVersion>6.13.5</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>2026年7月31日 17:25:50</lastBuildDate><item><title>Redis 多级缓存与JVM进程缓存</title><link>https://aronblake.cloud/posts/redis/%E5%A4%9A%E7%BA%A7%E7%BC%93%E5%AD%98-%E8%BF%9B%E7%A8%8B%E7%BC%93%E5%AD%98%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/%E5%A4%9A%E7%BA%A7%E7%BC%93%E5%AD%98-%E8%BF%9B%E7%A8%8B%E7%BC%93%E5%AD%98%E6%95%B4%E7%90%86/</guid><description>Redis多级缓存与JVM进程缓存</description><pubDate>Fri, 31 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;1. 为什么需要多级缓存&lt;a href=&quot;#1-为什么需要多级缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1.1 传统缓存方案&lt;a href=&quot;#11-传统缓存方案&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;传统查询链路通常是：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;flowchart LR
    A[客户端] --&amp;gt; B[Tomcat]
    B --&amp;gt; C{Redis 命中?}
    C -- 是 --&amp;gt; B
    C -- 否 --&amp;gt; D[(数据库)]
    D --&amp;gt; C
    B --&amp;gt; A&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这种方案虽然已经通过 Redis 减少了数据库访问，但仍然存在两个突出问题：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;所有动态请求都必须经过 Tomcat&lt;/strong&gt;&lt;br /&gt;
当并发持续升高时，Tomcat 的线程、CPU、连接池等资源可能成为系统瓶颈。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redis 未命中会把压力继续传给数据库&lt;/strong&gt;&lt;br /&gt;
缓存过期、冷启动或热点 Key 失效时，大量请求可能同时访问数据库。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.2 多级缓存方案&lt;a href=&quot;#12-多级缓存方案&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;多级缓存会充分利用请求链路中的各层存储能力：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;flowchart LR
    A[浏览器缓存] --&amp;gt; B[反向代理 Nginx]
    B --&amp;gt; C[业务 Nginx 本地缓存]
    C --&amp;gt;|未命中| D[(Redis)]
    D --&amp;gt;|未命中| E[Tomcat]
    E --&amp;gt; F[JVM 进程缓存]
    F --&amp;gt;|未命中| G[(数据库)]&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;典型查询顺序如下：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;浏览器访问静态资源时，优先读取浏览器缓存；&lt;/li&gt;
&lt;li&gt;动态请求到达 Nginx 后，优先查询 Nginx 本地缓存；&lt;/li&gt;
&lt;li&gt;Nginx 本地缓存未命中时，查询 Redis；&lt;/li&gt;
&lt;li&gt;Redis 未命中时，请求 Tomcat；&lt;/li&gt;
&lt;li&gt;Tomcat 优先查询 JVM 进程缓存；&lt;/li&gt;
&lt;li&gt;JVM 进程缓存未命中时，最后查询数据库。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;这样可以逐层拦截请求，减少对后端服务和数据库的访问。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.3 各层缓存的职责&lt;a href=&quot;#13-各层缓存的职责&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;th&gt;主要限制&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;浏览器缓存&lt;/td&gt;&lt;td&gt;HTML、CSS、JS、图片等静态资源&lt;/td&gt;&lt;td&gt;距离用户最近，命中后不访问服务端&lt;/td&gt;&lt;td&gt;受浏览器缓存策略控制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nginx 本地缓存&lt;/td&gt;&lt;td&gt;热点接口结果&lt;/td&gt;&lt;td&gt;延迟低，可在进入 Java 服务前返回&lt;/td&gt;&lt;td&gt;多节点之间需要处理数据一致性&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Redis&lt;/td&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;JVM 进程缓存&lt;/td&gt;&lt;td&gt;单个 Java 实例中的高频小数据&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;持久化、查询能力完整&lt;/td&gt;&lt;td&gt;承载高并发读的成本较高&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;在课程架构中，承担业务查询和缓存逻辑的 Nginx 已不只是反向代理服务器，而是一个可通过 OpenResty 与 Lua 编写业务逻辑的 Web 服务。因此通常会把它部署成集群，并在前面再设置专门的反向代理 Nginx。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. JVM 进程缓存&lt;a href=&quot;#2-jvm-进程缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;2.1 什么是进程缓存&lt;a href=&quot;#21-什么是进程缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;JVM 进程缓存是保存在当前 Java 进程堆内存中的数据。常见实现包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HashMap&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ConcurrentHashMap&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;Guava Cache；&lt;/li&gt;
&lt;li&gt;Caffeine。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;与普通 &lt;code&gt;Map&lt;/code&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;li&gt;并发访问控制；&lt;/li&gt;
&lt;li&gt;驱逐策略；&lt;/li&gt;
&lt;li&gt;命中率、加载耗时等统计；&lt;/li&gt;
&lt;li&gt;移除监听、异步刷新等扩展能力。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.2 进程缓存与 Redis 的区别&lt;a href=&quot;#22-进程缓存与-redis-的区别&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;












































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对比维度&lt;/th&gt;&lt;th&gt;JVM 进程缓存&lt;/th&gt;&lt;th&gt;Redis 分布式缓存&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;独立 Redis 服务&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;不同应用实例之间不共享&lt;/td&gt;&lt;td&gt;多个实例可以共享&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;容量&lt;/td&gt;&lt;td&gt;受 JVM 堆大小限制&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;每个实例可能保存不同版本&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;/tbody&gt;&lt;/table&gt;&lt;p&gt;二者不是互相替代的关系。常见做法是把 Caffeine 作为一级缓存（L1），把 Redis 作为二级缓存（L2）。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.3 进程缓存的边界&lt;a href=&quot;#23-进程缓存的边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;使用 JVM 进程缓存时要明确：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;每个 Tomcat 实例都有自己的缓存副本&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;请求被负载均衡到不同实例时，可能连续发生多次未命中；&lt;/li&gt;
&lt;li&gt;实例扩容后，新实例的缓存是空的；&lt;/li&gt;
&lt;li&gt;应用重启后，缓存会全部丢失；&lt;/li&gt;
&lt;li&gt;数据更新后，需要考虑所有实例中旧值的失效问题；&lt;/li&gt;
&lt;li&gt;缓存对象会占用 JVM 堆，容量失控可能增加 GC 压力，甚至导致 OOM。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此，进程缓存适合保存“体积较小、访问频繁、可重新加载”的数据，不应充当可靠的最终数据源。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 初识 Caffeine&lt;a href=&quot;#3-初识-caffeine&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;3.1 Caffeine 的定位&lt;a href=&quot;#31-caffeine-的定位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Caffeine 是 Java 平台上的高性能本地缓存库，提供手动缓存、同步加载缓存和异步缓存等模式。&lt;/p&gt;&lt;p&gt;Spring Framework 提供了对 Caffeine 的适配，可以通过 &lt;code&gt;CaffeineCache&lt;/code&gt;、&lt;code&gt;CaffeineCacheManager&lt;/code&gt; 或 Spring Cache 注解使用它。需要注意：&lt;strong&gt;Spring 的缓存模块是一层抽象，Caffeine 是它支持的具体缓存实现之一，不能简单理解为“Spring 内部默认缓存就是 Caffeine”。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;官方资料：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine&quot; target=&quot;_blank&quot;&gt;Caffeine GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Population&quot; target=&quot;_blank&quot;&gt;Caffeine Population：缓存加载方式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Eviction&quot; target=&quot;_blank&quot;&gt;Caffeine Eviction：驱逐策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/caffeine/CaffeineCache.html&quot; target=&quot;_blank&quot;&gt;Spring Framework CaffeineCache API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h4&gt;项目依赖&lt;a href=&quot;#项目依赖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;使用 Spring Boot &lt;code&gt;2.3.9.RELEASE&lt;/code&gt; 和 Java 8，并直接引入 Caffeine：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;com.github.ben-manes.caffeine&amp;lt;/&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;caffeine&amp;lt;/&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;该工程继承 Spring Boot 父 POM，因此依赖没有单独声明版本。若脱离这个父 POM 使用，需要在自己的依赖管理中明确一个与当前 Java 版本兼容的 Caffeine 版本。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 基本 API&lt;a href=&quot;#32-基本-api&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testBasicOps&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 1. 创建手动缓存。未配置过期或容量时，缓存可能持续增长。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 2. 写入或覆盖&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;name&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;Caffeine&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 3. 只查询缓存；未命中返回 null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; value &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getIfPresent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;name&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 4. 查询缓存；未命中时执行加载函数，并把非 null 结果写入缓存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; loaded &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;language&quot;&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 实际业务中可以在这里查询数据库或调用下一级缓存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Java&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 5. 删除单个 Key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;invalidate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;name&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6. 清空缓存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;invalidateAll&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;getIfPresent(key)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只查询缓存，未命中时返回 &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;get(key, mappingFunction)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;未命中时计算并写入，然后返回结果&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;put(key, value)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;新增或覆盖缓存&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;invalidate(key)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;使指定 Key 失效&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;invalidateAll()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;使全部缓存失效&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;estimatedSize()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;返回缓存条目数的估算值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;stats()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;获取命中率、加载耗时、驱逐次数等统计信息&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;同一个测试类的容量驱逐案例使用 &lt;code&gt;Thread.sleep(10L)&lt;/code&gt; 等待维护任务，这会让测试依赖机器调度。需要稳定断言时，可在写入后调用 &lt;code&gt;cache.cleanUp()&lt;/code&gt; 触发待执行的维护，再检查条目或统计信息。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 为什么优先使用 &lt;code&gt;cache.get&lt;/code&gt;&lt;a href=&quot;#33-为什么优先使用-cacheget&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;不要把“先判断，再加载，再写入”拆成三个独立步骤：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 不推荐：并发请求可能同时发现缓存未命中，然后重复查询数据库&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt; item &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getIfPresent&lt;/span&gt;&lt;span&gt;(id);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (item &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;item &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;(id);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;(id, item);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; item&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;更推荐：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(id, itemService&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getById);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;cache.get(key, mappingFunction)&lt;/code&gt; 会以原子方式完成“未命中时计算并写入”。同一个 JVM 内并发访问同一 Key 时，它能减少重复加载，缓解本机范围内的缓存击穿。&lt;/p&gt;&lt;p&gt;但它只能协调&lt;strong&gt;当前进程&lt;/strong&gt;中的线程，不能阻止其他 Tomcat 实例同时回源。如果需要跨实例控制热点 Key 的并发回源，还需要 Redis 锁、逻辑过期、请求合并等分布式方案。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.4 空值与异常&lt;a href=&quot;#34-空值与异常&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;加载函数可能查询不到数据，也可能抛出异常：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt; item &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(id, key &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;(key));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;需要注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;加载函数返回 &lt;code&gt;null&lt;/code&gt; 时，不会形成一个正常的 Caffeine 缓存条目；&lt;/li&gt;
&lt;li&gt;如果热点请求持续查询一个不存在的 ID，仍可能反复访问数据库，这就是缓存穿透；&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheValue&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt;&lt;span&gt; found&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt; data) &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CacheValue&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;hit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheValue&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;, data);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CacheValue&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;notFound&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheValue&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. Caffeine 的驱逐与过期策略&lt;a href=&quot;#4-caffeine-的驱逐与过期策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;缓存必须有边界，否则可能不断占用内存。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;4.1 基于容量&lt;a href=&quot;#41-基于容量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialCapacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;initialCapacity(100)&lt;/code&gt;：初始容量提示，用于减少早期扩容，不是最小容量，也不是上限；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maximumSize(10_000)&lt;/code&gt;：最多保留约 10,000 个条目；&lt;/li&gt;
&lt;li&gt;达到上限后，Caffeine 会根据访问频率与近期访问情况选择条目驱逐；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maximumSize&lt;/code&gt; 限制的是&lt;strong&gt;条目数量&lt;/strong&gt;，不是内存字节数。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果不同条目的内存大小差异很大，可以考虑 &lt;code&gt;maximumWeight&lt;/code&gt; 与 &lt;code&gt;weigher&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;byte&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumWeight&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1024&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1024&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;weigher&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; key, &lt;/span&gt;&lt;span&gt;byte&lt;/span&gt;&lt;span&gt;[] value) &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这里的权重由业务定义，不等同于 JVM 对象的精确内存占用。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 基于时间&lt;a href=&quot;#42-基于时间&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;写入后过期&lt;a href=&quot;#写入后过期&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;expireAfterWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Duration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofMinutes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;expireAfterWrite&lt;/code&gt; 从条目创建或最近一次值替换开始计时，适合“写入一段时间后数据可能变旧”的场景。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;访问后过期&lt;a href=&quot;#访问后过期&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;expireAfterAccess&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Duration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofMinutes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;expireAfterAccess&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;计时起点&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;expireAfterWrite&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;expireAfterAccess&lt;/code&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;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.3 基于引用&lt;a href=&quot;#43-基于引用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Caffeine 支持弱引用 Key、弱引用 Value 和软引用 Value，但这类策略依赖 GC，回收时间和容量都不够可预测。通常更推荐使用明确的 &lt;code&gt;maximumSize&lt;/code&gt; 或 &lt;code&gt;maximumWeight&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.4 过期不等于立即删除&lt;a href=&quot;#44-过期不等于立即删除&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;默认情况下，条目到达过期时间后，不一定会在那个时间点被后台线程立即物理删除。清理通常在写操作、部分读操作或维护任务中完成。&lt;/p&gt;&lt;p&gt;因此应这样理解：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;过期条目不会再作为有效命中返回；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;estimatedSize()&lt;/code&gt; 在维护完成前可能仍包含等待清理的条目；&lt;/li&gt;
&lt;li&gt;不要用缓存内部条目是否已物理删除，替代业务上的过期判断。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果业务要求更及时地执行过期维护，可按所用 Java 与 Caffeine 版本评估 &lt;code&gt;scheduler&lt;/code&gt; 配置。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.5 刷新与过期的区别&lt;a href=&quot;#45-刷新与过期的区别&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;refreshAfterWrite&lt;/code&gt; 和 &lt;code&gt;expireAfterWrite&lt;/code&gt; 语义不同：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;过期&lt;/strong&gt;：旧值失效，后续请求通常要等待新值加载；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;刷新&lt;/strong&gt;：条目达到刷新条件后，在被访问时异步加载新值，刷新期间仍可返回旧值。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;刷新适合允许短时间旧数据、但希望降低重新加载等待时间的场景。它通常用于 &lt;code&gt;LoadingCache&lt;/code&gt;，并需要谨慎设计加载线程池、失败回退和数据一致性。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 使用 Caffeine 实现商品进程缓存&lt;a href=&quot;#5-使用-caffeine-实现商品进程缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;5.1 需求&lt;a href=&quot;#51-需求&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;给商品服务增加两组 JVM 进程缓存：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;根据 ID 查询商品，未命中时查询数据库；&lt;/li&gt;
&lt;li&gt;根据 ID 查询库存，未命中时查询数据库；&lt;/li&gt;
&lt;li&gt;初始容量为 100；&lt;/li&gt;
&lt;li&gt;最大条目数为 10,000。&lt;/li&gt;
&lt;/ul&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;li&gt;需要分别统计命中率和执行失效操作。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 定义缓存 Bean&lt;a href=&quot;#52-定义缓存-bean&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CaffeineConfig&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialCapacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ItemStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stockCache&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialCapacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&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;code&gt;recordStats()&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;是否添加 &lt;code&gt;removalListener&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;最大条目数是否适合对象体积和 JVM 堆大小。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Item&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialCapacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;expireAfterWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Duration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofMinutes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;recordStats&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 在 Controller 中查询缓存&lt;a href=&quot;#53-在-controller-中查询缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;RestController&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;RequestMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;item&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemController&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IItemService&lt;/span&gt;&lt;span&gt; itemService&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IItemStockService&lt;/span&gt;&lt;span&gt; stockService&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; itemCache&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ItemStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; stockCache&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemController&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;IItemService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;IItemStockService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stockService&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;ItemStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;stockCache&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; itemService;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stockService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stockService;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; itemCache;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stockCache&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stockCache;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;GetMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/{id}&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;findById&lt;/span&gt;&lt;span&gt;(@&lt;/span&gt;&lt;span&gt;PathVariable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(id, key &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ne&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;status&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;, key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;one&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;GetMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/stock/{id}&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemStock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;findStockById&lt;/span&gt;&lt;span&gt;(@&lt;/span&gt;&lt;span&gt;PathVariable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stockCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(id, stockService&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getById);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里改用构造器注入，依赖关系更明确，也更方便测试。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.4 查询流程&lt;a href=&quot;#54-查询流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;flowchart TD
    A[收到商品查询请求] --&amp;gt; B{Caffeine 是否命中?}
    B -- 是 --&amp;gt; C[直接返回缓存值]
    B -- 否 --&amp;gt; D[执行加载函数]
    D --&amp;gt; E[查询数据库]
    E --&amp;gt; F{查询结果是否为 null?}
    F -- 否 --&amp;gt; G[写入 Caffeine]
    G --&amp;gt; H[返回商品]
    F -- 是 --&amp;gt; I[返回未找到]&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;第一次请求某个 ID 时：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Caffeine 未命中；&lt;/li&gt;
&lt;li&gt;执行加载函数；&lt;/li&gt;
&lt;li&gt;查询数据库；&lt;/li&gt;
&lt;li&gt;将非空结果写入当前 JVM 的缓存；&lt;/li&gt;
&lt;li&gt;返回结果。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;后续请求命中同一 Tomcat 实例时，可以直接从内存返回。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.5 Tomcat 集群中的命中率&lt;a href=&quot;#55-tomcat-集群中的命中率&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;课程后续会启动两个 Tomcat 实例，例如 &lt;code&gt;8081&lt;/code&gt; 和 &lt;code&gt;8082&lt;/code&gt;。如果 OpenResty 对它们使用轮询：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;第一次查询 /item/10001 → 8081，建立 8081 的本地缓存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;第二次查询 /item/10001 → 8082，8082 仍需查询数据库&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;第三次查询 /item/10001 → 8081，命中&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此课程使用请求 URI 做哈希，让同一商品尽量落到同一实例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;upstream&lt;/span&gt;&lt;span&gt; tomcat-cluster {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;hash &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;request_uri&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt; 192.168.150.1:8081;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt; 192.168.150.1:8082;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt; /item {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;proxy_pass &lt;/span&gt;&lt;span&gt;http://tomcat-cluster;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;其目标是提高 JVM 进程缓存命中率：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;flowchart LR
    A[&quot;/item/10001&quot;] --&amp;gt; B[&quot;hash(request_uri)&quot;]
    B --&amp;gt; C[Tomcat 8081]
    C --&amp;gt; D[&quot;8081 的 Caffeine&quot;]&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;但需要区分两个问题：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;固定路由解决的是命中率问题&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存同步解决的是数据一致性问题&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;哈希路由不会让两个 JVM 共享缓存，也不会自动删除其他实例中的旧值。Tomcat 节点数量变化时，映射还可能重新分布，新节点仍会经历冷缓存。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 数据更新与缓存一致性&lt;a href=&quot;#6-数据更新与缓存一致性&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;只实现查询缓存还不完整。商品或库存发生修改时，旧缓存可能继续被读取。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;6.1 常用处理策略&lt;a href=&quot;#61-常用处理策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;/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;时效性强，但并发和失败处理复杂&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;修改成功后发布事件，各实例删除或更新本地缓存&lt;/td&gt;&lt;td&gt;适合集群，但要处理消息丢失与重试&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;当前服务是单实例时，可以在数据库更新成功后删除对应 Key：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;updateItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt; item) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;itemService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;updateById&lt;/span&gt;&lt;span&gt;(item);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;invalidate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;集群部署时，只删除当前实例的 Caffeine 缓存还不够。其他实例仍可能保留旧值，需要借助：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Redis Pub/Sub；&lt;/li&gt;
&lt;li&gt;消息队列；&lt;/li&gt;
&lt;li&gt;Canal 或数据库变更事件；&lt;/li&gt;
&lt;li&gt;配置中心或专门的缓存失效通道；&lt;/li&gt;
&lt;li&gt;较短 TTL 作为最终兜底。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 商品与库存应区别对待&lt;a href=&quot;#62-商品与库存应区别对待&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;库存更新通常比商品基本信息更频繁，对时效性要求也更高。因此可以考虑：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;商品信息采用较长 TTL；&lt;/li&gt;
&lt;li&gt;库存采用较短 TTL；&lt;/li&gt;
&lt;li&gt;对库存变更主动发送失效通知；&lt;/li&gt;
&lt;li&gt;对强一致性库存扣减，不把本地缓存值当作最终扣减依据。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 Canal 同步实现&lt;a href=&quot;#63-canal-同步实现&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;采用 Canal 监听 MySQL binlog，再更新 Caffeine 与 Redis。核心逻辑如下：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;CanalTable&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;tb_item&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemHandler&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EntryHandler&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Autowired&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisHandler&lt;/span&gt;&lt;span&gt; redisHandler&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Autowired&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; itemCache&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;(), item);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;saveItem&lt;/span&gt;&lt;span&gt;(item);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;(), after);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;saveItem&lt;/span&gt;&lt;span&gt;(after);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;invalidate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;deleteItemById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;对应配置位于完成版 &lt;code&gt;application.yml&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;canal&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;destination&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;aron&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;192.168.150.101:11111&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;处理链路是：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;flowchart LR
    A[(MySQL)] --&amp;gt;|binlog| B[Canal]
    B --&amp;gt; C[ItemHandler]
    C --&amp;gt; D[Caffeine itemCache]
    C --&amp;gt; E[(Redis)]&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这种方案降低了业务写接口与缓存维护代码之间的耦合，但属于异步同步，数据库提交与缓存更新之间仍可能存在短暂时间窗。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 监控、测试与调优&lt;a href=&quot;#7-监控测试与调优&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;7.1 开启统计&lt;a href=&quot;#71-开启统计&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Item&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; itemCache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;recordStats&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;hitRate&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;evictionCount&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;itemCache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;averageLoadPenalty&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;建议重点观察：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hitRate()&lt;/code&gt;：命中率；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;missRate()&lt;/code&gt;：未命中率；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loadSuccessCount()&lt;/code&gt;：成功加载次数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loadFailureCount()&lt;/code&gt;：加载失败次数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;averageLoadPenalty()&lt;/code&gt;：平均加载耗时；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;evictionCount()&lt;/code&gt;：容量等原因导致的驱逐次数。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;命中率不是越高越好。如果为了命中率缓存大量低价值对象，导致堆占用和 GC 压力上升，整体性能反而可能下降。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.2 基本验证步骤&lt;a href=&quot;#72-基本验证步骤&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;启动商品服务；&lt;/li&gt;
&lt;li&gt;打开数据库 SQL 日志；&lt;/li&gt;
&lt;li&gt;第一次请求某商品 ID，确认执行了 SQL；&lt;/li&gt;
&lt;li&gt;再次请求相同 ID，确认不再执行 SQL；&lt;/li&gt;
&lt;li&gt;请求另一个 ID，确认会执行新的 SQL；&lt;/li&gt;
&lt;li&gt;使指定 Key 失效后再次请求，确认重新查询数据库；&lt;/li&gt;
&lt;li&gt;启动两个 Tomcat 实例，分别请求同一 ID，观察两个实例会各自建立缓存；&lt;/li&gt;
&lt;li&gt;修改数据库数据，验证失效策略是否能避免长期读取旧值。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.3 示例单元测试&lt;a href=&quot;#73-示例单元测试&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shouldLoadOnlyOnceForSameKey&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;AtomicInteger&lt;/span&gt;&lt;span&gt; loadCount &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AtomicInteger&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Cache&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Caffeine&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximumSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; first &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1L&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;loadCount&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;incrementAndGet&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; second &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1L&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;loadCount&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;incrementAndGet&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;item-1-new&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; first)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; second)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;loadCount&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;测试时间过期时，优先使用 Caffeine 提供的可控时间源思路，而不是让测试线程真实等待数秒，这样测试会更快、更稳定。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 本章小结&lt;a href=&quot;#8-本章小结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;JVM 进程缓存的核心价值是利用本机内存降低延迟和下游访问压力。Caffeine 在普通 &lt;code&gt;Map&lt;/code&gt; 的基础上补齐了容量控制、过期、并发加载、统计等能力，适合实现 Java 服务内部的一级缓存。&lt;/p&gt;&lt;p&gt;落地时应同时回答五个问题：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓存什么&lt;/strong&gt;：是否为高频、可重建、体积可控的数据？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如何加载&lt;/strong&gt;：是否使用原子加载避免同一进程内重复回源？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;保存多久&lt;/strong&gt;：容量和过期策略如何设置？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如何更新&lt;/strong&gt;：数据变化时怎样删除或刷新各实例缓存？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如何观测&lt;/strong&gt;：命中率、加载失败、驱逐次数和 JVM 内存是否健康？&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;只有把读取、失效、一致性和监控一起设计，进程缓存才能稳定地成为多级缓存体系中的一层，而不是新的数据风险来源。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine&quot; target=&quot;_blank&quot;&gt;Caffeine 官方仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Population&quot; target=&quot;_blank&quot;&gt;Caffeine：缓存加载&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Eviction&quot; target=&quot;_blank&quot;&gt;Caffeine：缓存驱逐&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Statistics&quot; target=&quot;_blank&quot;&gt;Caffeine：缓存统计&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-manes/caffeine/wiki/Refresh&quot; target=&quot;_blank&quot;&gt;Caffeine：缓存刷新&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/caffeine/CaffeineCache.html&quot; target=&quot;_blank&quot;&gt;Spring Framework：CaffeineCache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis Cluster 分片集群原理、部署与实践</title><link>https://aronblake.cloud/posts/redis/redis%E5%88%86%E7%89%87%E9%9B%86%E7%BE%A4-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis%E5%88%86%E7%89%87%E9%9B%86%E7%BE%A4-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</guid><description>Redis Cluster 分片集群原理、部署与实践</description><pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;讲义实验环境使用 Redis 6.2.4；本文同时说明 Redis 7.x/8.x 中仍适用的核心机制。具体命令和配置应以生产版本的官方文档为准。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. 为什么需要 Redis Cluster&lt;a href=&quot;#1-为什么需要-redis-cluster&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;普通主从复制和 Sentinel 可以解决：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;master 故障后的自动切换。&lt;/li&gt;
&lt;li&gt;通过 replica 扩展部分读取能力。&lt;/li&gt;
&lt;li&gt;提供在线数据副本。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;但它们仍然只有一个逻辑写 master，存在两个主要瓶颈：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;容量瓶颈&lt;/strong&gt;：所有数据必须能放入单个 master 的内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写入瓶颈&lt;/strong&gt;：所有写请求仍由单个 master 处理。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Redis Cluster 将完整键空间拆分给多个 master：&lt;/p&gt;&lt;ul&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;master 故障后，其 replica 可以自动提升。&lt;/li&gt;
&lt;li&gt;增加 master 并迁移一部分槽位后，可以水平扩展容量和吞吐。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;一句话概括：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Redis Cluster 通过固定的 16384 个 Hash Slot 对数据进行分片，并通过主从复制、Gossip 和多数派选举提供分片级高可用。&lt;/p&gt;&lt;/blockquote&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. Sentinel 与 Redis Cluster 的区别&lt;a href=&quot;#2-sentinel-与-redis-cluster-的区别&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;






















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对比项&lt;/th&gt;&lt;th&gt;Sentinel 主从架构&lt;/th&gt;&lt;th&gt;Redis Cluster&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;数据分布&lt;/td&gt;&lt;td&gt;所有 master/replica 保存同一份数据&lt;/td&gt;&lt;td&gt;不同 master 保存不同槽位的数据&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;写 master 数量&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;支持&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;支持&lt;/td&gt;&lt;td&gt;支持&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;服务发现&lt;/td&gt;&lt;td&gt;Sentinel 提供当前 master 地址&lt;/td&gt;&lt;td&gt;Cluster 客户端维护槽位到节点映射&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;多 key 命令&lt;/td&gt;&lt;td&gt;单机语义&lt;/td&gt;&lt;td&gt;所有 key 通常必须属于同一槽位&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数据库&lt;/td&gt;&lt;td&gt;支持多个逻辑 DB&lt;/td&gt;&lt;td&gt;只支持 DB 0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;适用场景&lt;/td&gt;&lt;td&gt;单 master 容量和写吞吐足够&lt;/td&gt;&lt;td&gt;数据量或写吞吐需要多 master 分担&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Redis Cluster 不是“多个互为主节点、每个节点都有全部数据”的多主复制系统。每个 master 只负责部分槽位。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 集群基本结构&lt;a href=&quot;#3-集群基本结构&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;一个常见的六节点集群：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Redis Cluster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Shard A          Shard B          Shard C&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────────────┐   ┌────────────┐   ┌────────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ Master A   │   │ Master B   │   │ Master C   │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ slots      │   │ slots      │   │ slots      │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 0-5460     │   │ 5461-10922 │   │10923-16383 │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└─────┬──────┘   └─────┬──────┘   └─────┬──────┘&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│复制              │复制              │复制&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌─────▼──────┐   ┌─────▼──────┐   ┌─────▼──────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ Replica A1 │   │ Replica B1 │   │ Replica C1 │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└────────────┘   └────────────┘   └────────────┘&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;所有节点通过 Cluster Bus 组成全连接拓扑，&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;交换心跳、Gossip、槽位配置和故障转移消息。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;3.1 Shard 的含义&lt;a href=&quot;#31-shard-的含义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一个逻辑分片通常由：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;一个负责槽位和读写的 master。&lt;/li&gt;
&lt;li&gt;零个、一个或多个保存该 master 数据副本的 replica。&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Shard = Master + Replicas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;replica 默认不负责该分片的业务写入。master 故障后，合格 replica 可以通过集群选举被提升。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 最小与推荐节点数&lt;a href=&quot;#32-最小与推荐节点数&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 官方文档指出：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;正常工作的最小集群需要至少 3 个 master。&lt;/li&gt;
&lt;li&gt;生产通常至少使用 3 master + 3 replica。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;三个 master 的原因：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;故障确认和 replica 提升需要 master 多数派参与。&lt;/li&gt;
&lt;li&gt;两个 master 无法形成稳健的多数派容错结构。&lt;/li&gt;
&lt;/ul&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;li&gt;内存成本。&lt;/li&gt;
&lt;li&gt;跨可用区网络质量。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 故障域部署&lt;a href=&quot;#33-故障域部署&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;生产建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;同一 shard 的 master 与 replica 不部署在同一宿主机。&lt;/li&gt;
&lt;li&gt;replica 尽量位于不同机架或可用区。&lt;/li&gt;
&lt;li&gt;不要把三个 master 全部放在同一故障域。&lt;/li&gt;
&lt;li&gt;节点之间的客户端端口和 Cluster Bus 端口都必须互通。&lt;/li&gt;
&lt;li&gt;客户端必须能访问集群通告出来的所有节点地址。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. Hash Slot 数据分片模型&lt;a href=&quot;#4-hash-slot-数据分片模型&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 不使用传统的一致性哈希环，而是把键空间划分为固定的 16384 个槽位：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;slot 范围：0 ～ 16383&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;槽位总数：16384&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每个槽位在同一时刻由一个 master 负责。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─提取有效哈希内容&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─CRC16&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─对 16384 取模&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Hash Slot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;负责该槽位的 Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;基本计算公式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;slot = CRC16(key) mod 16384&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也可以写成：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;slot = CRC16(key) &amp;amp; 16383&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;4.1 Key 绑定的是槽位，不是物理节点&lt;a href=&quot;#41-key-绑定的是槽位不是物理节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;需要理解：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;key 经过哈希计算后属于某个 slot。&lt;/li&gt;
&lt;li&gt;slot 当前归某个 master 管理。&lt;/li&gt;
&lt;li&gt;扩缩容时迁移的是 slot 及其 key。&lt;/li&gt;
&lt;li&gt;key 的 slot 通常不会变化，但 slot 的负责节点可以变化。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此客户端维护的是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;slot → master 地址&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;而不是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;key → 永久固定节点&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 查看 key 的槽位&lt;a href=&quot;#42-查看-key-的槽位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER KEYSLOT user:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER KEYSLOT foo{order:1001}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER KEYSLOT bar{order:1001}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;两者使用相同 Hash Tag，返回相同 slot。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. Hash Tag：让相关 key 落在同一槽位&lt;a href=&quot;#5-hash-tag让相关-key-落在同一槽位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;如果 key 中存在第一个有效的 &lt;code&gt;{...}&lt;/code&gt; 结构，Redis 只对大括号中的非空内容计算哈希。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;普通 key：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:1001:name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;有效哈希内容 = user:1001:name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Hash Tag key：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:{1001}:name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:{1001}:orders&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;有效哈希内容都为 1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这两个 key 会落在同一槽位：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:{1001}:profile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;order:{1001}:recent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;5.1 精确规则&lt;a href=&quot;#51-精确规则&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;只有同时满足以下条件才使用 Hash Tag：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;key 包含 &lt;code&gt;{&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在该 &lt;code&gt;{&lt;/code&gt; 右侧存在 &lt;code&gt;}&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;第一个匹配的 &lt;code&gt;{&lt;/code&gt; 和其右侧第一个 &lt;code&gt;}&lt;/code&gt; 之间至少有一个字符。&lt;/li&gt;
&lt;/ol&gt;
































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Key&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;user:1001&lt;/code&gt;&lt;/td&gt;&lt;td&gt;整个 &lt;code&gt;user:1001&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;{user1001}.name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;user1001&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;{user1001}.orders&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;user1001&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;foo{}{bar}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;整个 key，因为第一个 &lt;code&gt;{}&lt;/code&gt; 为空&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;foo{{bar}}zap&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{bar&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;foo{bar}{zap}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bar&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 Hash Tag 的用途&lt;a href=&quot;#52-hash-tag-的用途&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Hash Tag 主要用于：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;让多 key 命令中的所有 key 位于同一槽位。&lt;/li&gt;
&lt;li&gt;让 Lua 脚本或事务涉及的 key 位于同一槽位。&lt;/li&gt;
&lt;li&gt;将同一业务聚合的相关数据放入同一个 shard。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MSET order:{1001}:status paid order:{1001}:amount 99&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MGET order:{1001}:status order:{1001}:amount&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 Hash Tag 的风险&lt;a href=&quot;#53-hash-tag-的风险&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Hash Tag 不是越多越好。设计不当会产生热点：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;所有商品 key 都使用 {product}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;所有商品落入同一个 slot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;一个 master 承担绝大多数流量和内存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Tag 颗粒度使用租户 ID、用户 ID、订单 ID 等业务聚合标识。&lt;/li&gt;
&lt;li&gt;不要让所有业务 key 共享同一个 Tag。&lt;/li&gt;
&lt;li&gt;在保证多 key 原子操作的同时保持槽位分布均衡。&lt;/li&gt;
&lt;li&gt;监控 hot key、big key 和各 master 的内存、QPS 差异。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 多 Key 命令与 CROSSSLOT&lt;a href=&quot;#6-多-key-命令与-crossslot&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 的服务器端多 key 操作通常要求所有 key 属于同一槽位。&lt;/p&gt;&lt;p&gt;错误示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MGET user:1 user:2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果两个 key 不在同一槽位，可能返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CROSSSLOT Keys in request don&apos;t hash to the same slot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 Hash Tag：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MGET {user}:1 {user}:2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;两个 key 对 &lt;code&gt;{user}&lt;/code&gt; 哈希，可以在同一槽位执行。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;6.1 受影响的操作&lt;a href=&quot;#61-受影响的操作&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;需要特别检查：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MGET&lt;/code&gt;、&lt;code&gt;MSET&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;集合的交、并、差运算&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RENAME&lt;/code&gt;、&lt;code&gt;RENAMENX&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;事务 &lt;code&gt;MULTI/EXEC&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Lua 脚本和 Redis Functions&lt;/li&gt;
&lt;li&gt;涉及多个 key 的阻塞命令&lt;/li&gt;
&lt;li&gt;pipeline 中要求服务端原子或同节点执行的业务&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;有些客户端会把部分跨槽操作拆成多次单 key 请求并在客户端合并结果，但这会改变：&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;li&gt;返回时延。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不能因为客户端“能够执行”就假定它仍等同于单机上的一个原子命令。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 Lua 脚本和事务&lt;a href=&quot;#62-lua-脚本和事务&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;脚本或事务所访问的 key 应：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;在调用时显式声明。&lt;/li&gt;
&lt;li&gt;全部属于同一槽位。&lt;/li&gt;
&lt;li&gt;不要在脚本内部动态拼接并访问未知跨槽 key。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;典型分布式锁的锁 key、状态 key 和 fencing token 如需同一脚本操作，应使用相同 Hash Tag。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 节点通信与 Cluster Bus&lt;a href=&quot;#7-节点通信与-cluster-bus&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 节点之间不通过普通客户端协议完成所有集群协作，而是使用专门的二进制 Cluster Bus。&lt;/p&gt;&lt;p&gt;默认情况下：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端端口：6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cluster Bus：16379，即客户端端口 + 10000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果节点客户端端口为 7001：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端端口：7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Cluster Bus：17001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也可以通过配置显式指定 Bus 端口：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-port 17001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;7.1 Cluster Bus 用途&lt;a href=&quot;#71-cluster-bus-用途&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;节点握手和自动发现。&lt;/li&gt;
&lt;li&gt;PING/PONG 心跳。&lt;/li&gt;
&lt;li&gt;Gossip 故障信息传播。&lt;/li&gt;
&lt;li&gt;槽位映射和配置纪元传播。&lt;/li&gt;
&lt;li&gt;master 故障确认。&lt;/li&gt;
&lt;li&gt;replica 选举与提升。&lt;/li&gt;
&lt;li&gt;Pub/Sub 和其他集群内部消息。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.2 全连接拓扑&lt;a href=&quot;#72-全连接拓扑&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;集群节点之间维持全连接关系：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;N 个节点中，每个节点维护到其他节点的连接。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;业务客户端不应直接使用 Cluster Bus 协议；客户端只连接普通 Redis 数据端口。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.3 防火墙要求&lt;a href=&quot;#73-防火墙要求&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;每个节点至少需要：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;客户端数据端口对客户端和集群节点开放。&lt;/li&gt;
&lt;li&gt;Cluster Bus 端口对其他集群节点开放。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果只开放数据端口、不开放 Bus 端口：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;单节点可能仍能被 &lt;code&gt;redis-cli&lt;/code&gt; 连接。&lt;/li&gt;
&lt;li&gt;但节点无法正常交换集群消息。&lt;/li&gt;
&lt;li&gt;故障检测、槽位传播和故障转移会异常。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Cluster Bus 端口不应暴露到不可信公网。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 节点标识、拓扑与配置纪元&lt;a href=&quot;#8-节点标识拓扑与配置纪元&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;8.1 Node ID&lt;a href=&quot;#81-node-id&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;每个 Cluster 节点都有持久化 Node ID，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;07c37dfeb235213a872192d90877d0cd55635b91&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Node ID：&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;li&gt;用于复制关系、槽位归属和集群命令。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;8.2 nodes.conf&lt;a href=&quot;#82-nodesconf&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;配置示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-config-file nodes-7001.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;该文件由 Redis 自动维护，保存：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Node ID。&lt;/li&gt;
&lt;li&gt;已知节点。&lt;/li&gt;
&lt;li&gt;master/replica 关系。&lt;/li&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;code&gt;nodes.conf&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;每个 Redis 进程必须使用独立文件。&lt;/li&gt;
&lt;li&gt;文件所在目录必须可写。&lt;/li&gt;
&lt;li&gt;同一主机多个实例不能共用一个 &lt;code&gt;nodes.conf&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;删除或错误复制该文件可能改变节点身份并破坏拓扑。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;8.3 configEpoch&lt;a href=&quot;#83-configepoch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;configEpoch&lt;/code&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;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 请求路由：MOVED 与 ASK&lt;a href=&quot;#9-请求路由moved-与-ask&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;讲义中“访问任意节点，最终会被转发到正确节点”的说法需要更精确地理解：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Redis Cluster 节点通常不会像代理一样替客户端转发业务请求，而是返回重定向错误；Cluster 客户端根据错误重新连接正确节点。&lt;/p&gt;&lt;/blockquote&gt;&lt;section&gt;&lt;h3&gt;9.1 MOVED：永久槽位归属重定向&lt;a href=&quot;#91-moved永久槽位归属重定向&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;客户端向错误节点发送：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GET order:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;节点可能返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;-MOVED 3999 192.168.150.102:7002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;key 属于 slot 3999。&lt;/li&gt;
&lt;li&gt;slot 3999 当前由 &lt;code&gt;192.168.150.102:7002&lt;/code&gt; 负责。&lt;/li&gt;
&lt;li&gt;客户端应向该节点重新发送命令。&lt;/li&gt;
&lt;li&gt;客户端应更新本地槽位映射。&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──GET key──→ Node A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ←─MOVED──── Node A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──GET key──→ Node B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ←─value──── Node B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.2 ASK：迁槽期间的一次性重定向&lt;a href=&quot;#92-ask迁槽期间的一次性重定向&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;槽位正在从 A 迁移到 B 时，部分 key 已在 B，部分仍在 A。&lt;/p&gt;&lt;p&gt;源节点可能返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;-ASK 3999 192.168.150.102:7002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;客户端应：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;只把当前这一次命令发送到 B。&lt;/li&gt;
&lt;li&gt;先向 B 发送 &lt;code&gt;ASKING&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;再发送原命令。&lt;/li&gt;
&lt;li&gt;不要立即永久修改本地 slot 映射。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──GET key──→ Node A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ←──ASK───── Node A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──ASKING──→ Node B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──GET key──→ Node B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ←─value──── Node B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.3 MOVED 与 ASK 对比&lt;a href=&quot;#93-moved-与-ask-对比&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对比项&lt;/th&gt;&lt;th&gt;MOVED&lt;/th&gt;&lt;th&gt;ASK&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;否&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;是否先发送 &lt;code&gt;ASKING&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;/td&gt;&lt;td&gt;正常路由错误、故障转移后&lt;/td&gt;&lt;td&gt;在线 reshard 期间&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.4 redis-cli 的 &lt;code&gt;-c&lt;/code&gt;&lt;a href=&quot;#94-redis-cli-的--c&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;普通连接：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;收到 &lt;code&gt;MOVED&lt;/code&gt; 后只会显示错误。&lt;/p&gt;&lt;p&gt;Cluster 跟随重定向模式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-c&lt;/code&gt; 会帮助命令行客户端处理重定向。生产应用仍应使用真正支持 Redis Cluster 的客户端。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. Cluster 客户端应如何工作&lt;a href=&quot;#10-cluster-客户端应如何工作&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Cluster 客户端通常维护：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;16384 个槽位 → 当前 master 地址&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;启动流程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;连接任意一个可用的 seed 节点。&lt;/li&gt;
&lt;li&gt;获取当前 shard 和槽位映射。&lt;/li&gt;
&lt;li&gt;根据 key 在客户端计算 slot。&lt;/li&gt;
&lt;li&gt;直接把命令发送到负责该 slot 的节点。&lt;/li&gt;
&lt;li&gt;收到 &lt;code&gt;MOVED&lt;/code&gt; 时刷新槽位映射。&lt;/li&gt;
&lt;li&gt;收到 &lt;code&gt;ASK&lt;/code&gt; 时完成一次性重定向。&lt;/li&gt;
&lt;li&gt;节点故障或拓扑变化后重新建立连接。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;较新客户端和运维工具应优先使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SHARDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;CLUSTER SLOTS&lt;/code&gt; 已被标记为弃用，但为了兼容旧客户端仍广泛存在。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;10.1 Seed 节点&lt;a href=&quot;#101-seed-节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;客户端配置中的节点列表是启动入口，不是静态完整拓扑。&lt;/p&gt;&lt;p&gt;建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;配置多个位于不同故障域的 seed 节点。&lt;/li&gt;
&lt;li&gt;不必在所有客户端中列出每一个节点，但不能只依赖一个节点。&lt;/li&gt;
&lt;li&gt;客户端发现的节点地址必须从客户端网络可达。&lt;/li&gt;
&lt;li&gt;故障转移和扩容后允许客户端刷新拓扑。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;11. 核心配置&lt;a href=&quot;#11-核心配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;实验节点的基本配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;port 7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-enabled yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-config-file nodes-7001.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-node-timeout 5000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dir /var/lib/redis/7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;11.1 配置项说明&lt;a href=&quot;#111-配置项说明&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;cluster-enabled yes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;开启 Cluster 模式&lt;/td&gt;&lt;td&gt;每个集群节点都要配置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster-config-file&lt;/code&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;code&gt;cluster-node-timeout&lt;/code&gt;&lt;/td&gt;&lt;td&gt;节点不可达和故障处理的基础超时&lt;/td&gt;&lt;td&gt;应明显大于正常网络 RTT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster-port&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显式指定 Cluster Bus 端口&lt;/td&gt;&lt;td&gt;不指定时通常为数据端口 + 10000&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster-require-full-coverage&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;cluster-replica-validity-factor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;控制断链过久的 replica 是否仍可自动提升&lt;/td&gt;&lt;td&gt;设为 0 会放宽新鲜度限制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster-migration-barrier&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica 自动迁移后原 master 至少保留的健康副本数&lt;/td&gt;&lt;td&gt;常见默认值为 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster-replica-no-failover&lt;/code&gt;&lt;/td&gt;&lt;td&gt;禁止该 replica 自动参与故障转移&lt;/td&gt;&lt;td&gt;灾备拓扑中可能使用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;11.2 不要照搬实验安全配置&lt;a href=&quot;#112-不要照搬实验安全配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;讲义实验中使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bind 0.0.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;protected-mode no&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;配置 ACL 和强密码。&lt;/li&gt;
&lt;li&gt;使用防火墙限制客户端端口。&lt;/li&gt;
&lt;li&gt;Cluster Bus 只允许集群节点访问。&lt;/li&gt;
&lt;li&gt;跨不可信网络时启用 TLS。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;12. NAT、容器与地址通告&lt;a href=&quot;#12-nat容器与地址通告&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 客户端会根据节点通告的地址直连所有 master。容器内部地址或 NAT 后错误地址会导致：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;客户端能连接 seed，但无法连接其他节点。&lt;/li&gt;
&lt;li&gt;不断收到 &lt;code&gt;MOVED&lt;/code&gt; 后连接失败。&lt;/li&gt;
&lt;li&gt;节点之间 Cluster Bus 无法建立连接。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;常见配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-announce-ip 192.168.150.101&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-announce-port 7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-announce-bus-port 17001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;与端口映射一致的数据端口和 Bus 端口。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;讲义中的 &lt;code&gt;replica-announce-ip&lt;/code&gt; 主要属于复制地址通告；Redis Cluster 的客户端和 Bus 地址应重点检查 &lt;code&gt;cluster-announce-*&lt;/code&gt; 配置。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;13. 创建一个六节点集群&lt;a href=&quot;#13-创建一个六节点集群&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;初始角色&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;192.168.150.101:7001&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master&lt;/td&gt;&lt;td&gt;Shard A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;192.168.150.101:7002&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master&lt;/td&gt;&lt;td&gt;Shard B&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;192.168.150.101:7003&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master&lt;/td&gt;&lt;td&gt;Shard C&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;192.168.150.101:8001&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica&lt;/td&gt;&lt;td&gt;复制某个 master&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;192.168.150.101:8002&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica&lt;/td&gt;&lt;td&gt;复制某个 master&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;192.168.150.101:8003&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica&lt;/td&gt;&lt;td&gt;复制某个 master&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;创建前要求：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;所有节点为空。&lt;/li&gt;
&lt;li&gt;所有节点已开启 Cluster 模式。&lt;/li&gt;
&lt;li&gt;节点之间的数据端口和 Bus 端口互通。&lt;/li&gt;
&lt;li&gt;使用独立工作目录和 &lt;code&gt;nodes.conf&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;节点的通告地址正确。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Redis 5.0 及以后：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7002&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7003&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:8001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:8002&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:8003&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;--cluster-replicas&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--cluster-replicas 1&lt;/code&gt; 表示希望每个 master 配置一个 replica。&lt;/p&gt;&lt;p&gt;创建后检查：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CLUSTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CLUSTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CLUSTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SHARDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;健康集群应满足：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cluster_state:ok&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;0～16383 所有槽位均已分配。&lt;/li&gt;
&lt;li&gt;三个 master 分别持有槽位。&lt;/li&gt;
&lt;li&gt;每个 master 至少有预期 replica。&lt;/li&gt;
&lt;li&gt;所有节点的 &lt;code&gt;link-state&lt;/code&gt; 正常。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;14. 查看集群状态&lt;a href=&quot;#14-查看集群状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;14.1 CLUSTER INFO&lt;a href=&quot;#141-cluster-info&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER INFO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_state&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前节点看到的集群总体状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_slots_assigned&lt;/code&gt;&lt;/td&gt;&lt;td&gt;已分配槽位数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_slots_ok&lt;/code&gt;&lt;/td&gt;&lt;td&gt;正常槽位数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_slots_pfail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;关联 PFAIL 节点的槽位数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_slots_fail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;关联 FAIL 节点的槽位数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_known_nodes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前已知节点数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_size&lt;/code&gt;&lt;/td&gt;&lt;td&gt;至少负责一个槽位的 master 数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_current_epoch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前集群配置纪元&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_my_epoch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前节点的配置纪元&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cluster_stats_messages_*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cluster Bus 消息统计&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;14.2 CLUSTER NODES&lt;a href=&quot;#142-cluster-nodes&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每行包含：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;node-id endpoint flags master-id ping-sent pong-recv config-epoch link-state slots&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;常见 flags：&lt;/p&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;flag&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;myself&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前查询节点&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;master&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;slave&lt;/code&gt;&lt;/td&gt;&lt;td&gt;协议兼容字段，表示 replica&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;fail?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;PFAIL，当前节点怀疑其故障&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;fail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;FAIL，故障已被足够 master 确认&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;handshake&lt;/code&gt;&lt;/td&gt;&lt;td&gt;正在进行节点握手&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;noaddr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;地址未知&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;nofailover&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica 不参与自动提升&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;14.3 CLUSTER SHARDS&lt;a href=&quot;#143-cluster-shards&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SHARDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;用于查看：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;shard 的槽位范围。&lt;/li&gt;
&lt;li&gt;master 节点。&lt;/li&gt;
&lt;li&gt;replica 节点。&lt;/li&gt;
&lt;li&gt;节点 endpoint、角色和健康状态。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;它比手工解析 &lt;code&gt;CLUSTER NODES&lt;/code&gt; 更适合新客户端获取拓扑。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;15. 在线扩容：添加 master 并迁移槽位&lt;a href=&quot;#15-在线扩容添加-master-并迁移槽位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;新 master 加入集群后默认没有槽位，因此也不会承载普通 key。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;15.1 添加空节点&lt;a href=&quot;#151-添加空节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7004&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CLUSTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;此时 7004 通常是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;master，0 slots&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;15.2 迁移槽位&lt;a href=&quot;#152-迁移槽位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;交互式 reshard：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reshard&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;需要指定：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;迁移多少个槽位。&lt;/li&gt;
&lt;li&gt;接收槽位的新 master Node ID。&lt;/li&gt;
&lt;li&gt;从哪些源 master 迁移。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;也可以在自动化中提供对应 &lt;code&gt;--cluster-*&lt;/code&gt; 参数，但生产迁移前应先在目标版本的 &lt;code&gt;redis-cli --cluster help&lt;/code&gt; 中确认语法。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;15.3 槽位迁移的内部状态&lt;a href=&quot;#153-槽位迁移的内部状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;假设 slot 2765 从 A 迁移到 B：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1. B 将 2765 标记为 IMPORTING，来源 A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2. A 将 2765 标记为 MIGRATING，目标 B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;3. 从 A 获取该槽位中的 key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;4. 使用 MIGRATE 将 key 原子地移动到 B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;5. B 成为 2765 的正式 owner&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;6. A 和其他 master 更新 slot 2765 的归属&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;底层涉及：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SETSLOT 2765 IMPORTING &amp;lt;source-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SETSLOT 2765 MIGRATING &amp;lt;target-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER GETKEYSINSLOT 2765 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MIGRATE ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SETSLOT 2765 NODE &amp;lt;target-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;通常应使用 &lt;code&gt;redis-cli --cluster reshard&lt;/code&gt;，避免人工执行底层命令时顺序错误。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;15.4 迁移期间的请求行为&lt;a href=&quot;#154-迁移期间的请求行为&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;源节点 A：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;key 仍在 A：直接处理。&lt;/li&gt;
&lt;li&gt;key 已经迁走或新 key 不在 A：返回 &lt;code&gt;ASK&lt;/code&gt; 到 B。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;目标节点 B：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;收到普通请求但尚未正式拥有槽位：通常返回 &lt;code&gt;MOVED&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;收到 &lt;code&gt;ASKING&lt;/code&gt; 后的请求：允许处理该导入槽位的当前命令。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;15.5 迁槽风险&lt;a href=&quot;#155-迁槽风险&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;big key 会延长单次迁移阻塞和网络传输时间。&lt;/li&gt;
&lt;li&gt;热点槽位迁移时重定向和延迟可能增加。&lt;/li&gt;
&lt;li&gt;多 key 命令在相关槽位迁移时可能返回 &lt;code&gt;TRYAGAIN&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;源和目标节点的内存峰值需要预留。&lt;/li&gt;
&lt;li&gt;客户端必须正确支持 &lt;code&gt;ASK&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;迁移中断可能留下 &lt;code&gt;MIGRATING&lt;/code&gt;/&lt;code&gt;IMPORTING&lt;/code&gt; 状态。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;迁移前应治理 big key，并在低峰期分批执行。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;16. 添加 replica&lt;a href=&quot;#16-添加-replica&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;添加新的 replica：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:8004&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;--cluster-slave&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果要指定复制某个 master：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:8004&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;--cluster-slave&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;--cluster-master-id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也可以先把节点作为空 master 加入，再在新节点执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER REPLICATE &amp;lt;master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;添加后确认：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER REPLICAS &amp;lt;master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INFO REPLICATION&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;17. 缩容与删除节点&lt;a href=&quot;#17-缩容与删除节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;17.1 删除 replica&lt;a href=&quot;#171-删除-replica&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;del-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&amp;lt;replica-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;17.2 删除 master&lt;a href=&quot;#172-删除-master&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;master 必须先清空其槽位：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;将该 master 的所有槽位 reshard 到其他 master。&lt;/li&gt;
&lt;li&gt;确认它不再负责任何 slot。&lt;/li&gt;
&lt;li&gt;确认业务客户端拓扑已经刷新。&lt;/li&gt;
&lt;li&gt;再执行 &lt;code&gt;del-node&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;del-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&amp;lt;empty-master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不能直接删除仍持有槽位的 master。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;17.3 删除不可达故障节点&lt;a href=&quot;#173-删除不可达故障节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;故障节点不可连接时，普通 &lt;code&gt;del-node&lt;/code&gt; 可能失败。可以根据实际版本和场景对每个节点执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER FORGET &amp;lt;node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;或使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;CLUSTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FORGET&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;执行前必须确认：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;故障节点不会带着旧配置重新加入。&lt;/li&gt;
&lt;li&gt;其槽位已经由新 master 正式接管。&lt;/li&gt;
&lt;li&gt;集群中所有节点最终都忘记了该 Node ID。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;18. 负载均衡与 Rebalance&lt;a href=&quot;#18-负载均衡与-rebalance&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;增加 master 后只“加入节点”不会自动平均迁移全部槽位。&lt;/p&gt;&lt;p&gt;可使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rebalance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Rebalance 的目标通常是按节点权重重新分配槽位数量。&lt;/p&gt;&lt;p&gt;但槽位数量均衡不等于负载均衡：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;每个 Master 槽位数相同&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;≠&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;每个 Master 的 key 数、内存、QPS 和网络流量相同&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;原因：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;不同 slot 的 key 数量不同。&lt;/li&gt;
&lt;li&gt;key 大小差异巨大。&lt;/li&gt;
&lt;li&gt;某些 key 或 Tag 是热点。&lt;/li&gt;
&lt;li&gt;不同数据结构的 CPU 成本不同。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;真正的均衡应同时观察：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;槽位数。&lt;/li&gt;
&lt;li&gt;key 数。&lt;/li&gt;
&lt;li&gt;内存使用量。&lt;/li&gt;
&lt;li&gt;QPS。&lt;/li&gt;
&lt;li&gt;CPU。&lt;/li&gt;
&lt;li&gt;网络带宽。&lt;/li&gt;
&lt;li&gt;命令延迟。&lt;/li&gt;
&lt;li&gt;hot key 和 big key。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;19. 自动故障检测：PFAIL 与 FAIL&lt;a href=&quot;#19-自动故障检测pfail-与-fail&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 不依赖 Sentinel。所有 Cluster 节点通过 Cluster Bus 自行完成故障检测。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;19.1 PFAIL&lt;a href=&quot;#191-pfail&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;PFAIL 表示 Possible Failure：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;某个节点根据自己的本地观察，认为另一个节点超过 &lt;code&gt;cluster-node-timeout&lt;/code&gt; 没有正常响应。&lt;/p&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;单个节点的本地主观判断 → PFAIL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;master 和 replica 都可以把其他节点标记为 PFAIL。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;19.2 FAIL&lt;a href=&quot;#192-fail&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;PFAIL 不足以触发 replica 提升。故障报告通过 Gossip 传播，当足够多的 master 在有效时间窗口内确认目标不可达时，目标进入 FAIL。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;多数 master 的有效故障报告 → FAIL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;19.3 与 Sentinel 的类比&lt;a href=&quot;#193-与-sentinel-的类比&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sentinel&lt;/th&gt;&lt;th&gt;Redis Cluster&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;SDOWN&lt;/td&gt;&lt;td&gt;PFAIL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ODOWN&lt;/td&gt;&lt;td&gt;FAIL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel 多数派授权&lt;/td&gt;&lt;td&gt;master 多数派参与 replica 选举&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;二者概念相似，但协议、角色和实现并不相同。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;20. 自动故障转移&lt;a href=&quot;#20-自动故障转移&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;假设 Master B 故障，它负责一部分槽位并拥有 Replica B1。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master B 失联&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;部分节点标记 PFAIL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;多数 master 确认 FAIL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Replica B1 发起选举&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;获得 master 多数派授权&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;B1 提升为新 Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;新 configEpoch 和槽位归属传播&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;20.1 replica 参与提升的基本条件&lt;a href=&quot;#201-replica-参与提升的基本条件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;它的 master 已处于 FAIL。&lt;/li&gt;
&lt;li&gt;原 master 负责至少一个槽位。&lt;/li&gt;
&lt;li&gt;replica 与 master 断链没有久到超过允许的新鲜度范围。&lt;/li&gt;
&lt;li&gt;replica 未被配置为禁止故障转移。&lt;/li&gt;
&lt;li&gt;它能联系到足够 master 并获得选票。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;20.2 数据更新程度与选举延迟&lt;a href=&quot;#202-数据更新程度与选举延迟&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;同一 master 的多个 replica 会根据复制进度形成不同的选举延迟：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;offset 越新，通常越早尝试选举。&lt;/li&gt;
&lt;li&gt;offset 较旧，延迟更长。&lt;/li&gt;
&lt;li&gt;最终只有一个 replica 获得多数 master 授权。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这与 Sentinel 中按 &lt;code&gt;replica-priority → offset → run ID&lt;/code&gt; 选择候选节点的流程不同。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;20.3 configEpoch 的作用&lt;a href=&quot;#203-configepoch-的作用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;新 master 获得新的配置纪元并广播：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;自己现在负责原 master 的槽位。&lt;/li&gt;
&lt;li&gt;其他节点采用更新的槽位配置。&lt;/li&gt;
&lt;li&gt;旧 master 恢复后不能用旧配置夺回槽位。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;21. 集群何时不可用&lt;a href=&quot;#21-集群何时不可用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;默认安全取向下，常见不可用条件包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;大多数 master 不可达，集群处于少数派分区。&lt;/li&gt;
&lt;li&gt;某个 master 和它的所有可提升 replica 同时不可用。&lt;/li&gt;
&lt;li&gt;存在未覆盖槽位，并要求 full coverage。&lt;/li&gt;
&lt;li&gt;节点之间 Cluster Bus 被阻断。&lt;/li&gt;
&lt;li&gt;槽位配置冲突或迁移状态异常。&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h3&gt;21.1 cluster-require-full-coverage&lt;a href=&quot;#211-cluster-require-full-coverage&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-require-full-coverage yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;当任意槽位没有可用 owner 时，集群倾向停止接受查询，避免向客户端呈现不完整键空间。&lt;/p&gt;&lt;p&gt;设置为 &lt;code&gt;no&lt;/code&gt; 时，仍有 owner 的槽位可以继续服务，但应用会得到“部分 key 可用、部分 key 不可用”的状态。&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;优点&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;yes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;语义明确，不返回不完整键空间&lt;/td&gt;&lt;td&gt;单个 shard 丢失可能使整个集群不可用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;no&lt;/code&gt;&lt;/td&gt;&lt;td&gt;健康 shard 可继续服务&lt;/td&gt;&lt;td&gt;应用必须能处理部分可用和跨槽操作失败&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;不能只为了“高可用”就盲目改为 &lt;code&gt;no&lt;/code&gt;，应根据业务是否能接受部分数据不可用来决定。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;22. 手动故障转移&lt;a href=&quot;#22-手动故障转移&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在准备提升的 replica 上执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER FAILOVER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;li&gt;将业务平滑迁离某个 master。&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h3&gt;22.1 默认模式&lt;a href=&quot;#221-默认模式&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER FAILOVER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;简化流程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;replica 请求 master 暂停处理客户端写入。&lt;/li&gt;
&lt;li&gt;master 把当前复制 offset 告诉 replica。&lt;/li&gt;
&lt;li&gt;replica 等待自己追平该 offset。&lt;/li&gt;
&lt;li&gt;replica 向其他 master 请求故障转移授权和新配置纪元。&lt;/li&gt;
&lt;li&gt;replica 提升为 master 并广播配置。&lt;/li&gt;
&lt;li&gt;原 master 接受新配置并成为 replica。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;默认模式最重视数据一致性，适合计划内切换。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;22.2 FORCE&lt;a href=&quot;#222-force&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER FAILOVER FORCE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;不与原 master 协调。&lt;/li&gt;
&lt;li&gt;适用于原 master 无法访问，但集群仍可形成故障转移授权的情况。&lt;/li&gt;
&lt;li&gt;仍需要 Cluster 的多数派授权。&lt;/li&gt;
&lt;li&gt;可能丢失 replica 尚未收到的写入。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;22.3 TAKEOVER&lt;a href=&quot;#223-takeover&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER FAILOVER TAKEOVER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;跳过与原 master 的协调。&lt;/li&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;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;模式&lt;/th&gt;&lt;th&gt;原 master 协调&lt;/th&gt;&lt;th&gt;offset 追平&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;/td&gt;&lt;td&gt;是&lt;/td&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;code&gt;FORCE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;否&lt;/td&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;code&gt;TAKEOVER&lt;/code&gt;&lt;/td&gt;&lt;td&gt;否&lt;/td&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;code&gt;OK&lt;/code&gt; 只表示故障转移已被调度，不等于已经成功。之后必须检查：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ROLE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INFO REPLICATION&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SHARDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;23. Replica Migration&lt;a href=&quot;#23-replica-migration&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 可以把 replica 从“副本过多的 master”迁移给“没有健康副本的 master”，提高后续故障的可恢复性。&lt;/p&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master A：0 个 Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master B：1 个 Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master C：2 个 Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;在满足迁移屏障条件时，&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master C 的一个 Replica 可自动改为复制 Master A。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;相关配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cluster-migration-barrier 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;值为 &lt;code&gt;1&lt;/code&gt; 通常表示只有当原 master 在迁走一个 replica 后仍至少保留一个健康 replica，迁移才会发生。&lt;/p&gt;&lt;p&gt;Replica Migration 改变的是副本归属，不是业务槽位归属。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;24. 数据一致性与丢失窗口&lt;a href=&quot;#24-数据一致性与丢失窗口&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Cluster 的 shard 内仍使用异步主从复制。&lt;/p&gt;&lt;p&gt;可能丢数据的基本场景：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ──写入──→ Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Client ←─OK──── Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 尚未复制到 Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;× Master 故障&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Replica 被提升，但缺少刚才的写入。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;24.1 少数派分区中的旧 master&lt;a href=&quot;#241-少数派分区中的旧-master&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果客户端仍能访问处于少数派网络中的旧 master，它可能在一段时间内接受写入。多数派一侧完成故障转移后，旧 master 恢复连接并采用新配置，少数派期间的独有写入可能丢失。&lt;/p&gt;&lt;p&gt;可以在所有可能成为 master 的节点配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-to-write 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-max-lag 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;以限制无法连接足够 replica 的 master 继续写入的时间窗口。&lt;/p&gt;&lt;p&gt;代价是 replica 或网络异常时 master 可能拒绝写入。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;24.2 WAIT&lt;a href=&quot;#242-wait&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;关键写入可以评估：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET order:{1001}:status paid&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;WAIT 1 1000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;WAIT&lt;/code&gt; 能提高写入已经到达 replica 的概率，但不能：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;将 Redis 变成强一致数据库。&lt;/li&gt;
&lt;li&gt;保证写入已经按要求落盘。&lt;/li&gt;
&lt;li&gt;替代 RDB、AOF 和独立备份。&lt;/li&gt;
&lt;li&gt;消除网络分区中的全部数据丢失风险。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;25. 持久化与备份&lt;a href=&quot;#25-持久化与备份&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;每个 master 只保存一部分数据，因此每个 shard 都必须有独立的数据保护。&lt;/p&gt;&lt;p&gt;建议所有可能成为 master 的节点启用合适的持久化，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;并根据 RPO/RTO 配置 RDB 和集群外备份。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;25.1 Cluster 不等于备份&lt;a href=&quot;#251-cluster-不等于备份&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;误删 key 会通过复制传播给 replica。&lt;/li&gt;
&lt;li&gt;程序错误可以同时污染所有 shard。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FLUSHALL&lt;/code&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;每个 shard 的备份时间点。&lt;/li&gt;
&lt;li&gt;槽位映射和 Node ID。&lt;/li&gt;
&lt;li&gt;恢复到新集群还是原集群。&lt;/li&gt;
&lt;li&gt;跨 shard 数据的一致时间点。&lt;/li&gt;
&lt;li&gt;恢复后的重新分片和客户端切换。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;26. Spring Boot 与 RedisTemplate&lt;a href=&quot;#26-spring-boot-与-redistemplate&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Spring Boot 3.x：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;spring&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;app-user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;app-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;cluster&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.102:7002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.103:7003&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;max-redirects&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;connect-timeout&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;较早 Spring Boot 版本常使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;spring&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cluster&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:7001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:7002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:7003&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;具体属性以前端项目实际 Spring Boot 版本为准。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;26.1 Seed 节点不必列出全部节点&lt;a href=&quot;#261-seed-节点不必列出全部节点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;cluster.nodes&lt;/code&gt; 用于启动拓扑发现。客户端连接成功后会获取完整槽位和节点信息。&lt;/p&gt;&lt;p&gt;但建议至少配置多个不同故障域的可用入口。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;26.2 Topology Refresh&lt;a href=&quot;#262-topology-refresh&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Lettuce 客户端应具备拓扑刷新能力：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;启动时加载拓扑。&lt;/li&gt;
&lt;li&gt;收到 &lt;code&gt;MOVED&lt;/code&gt; 时刷新。&lt;/li&gt;
&lt;li&gt;在故障转移和伸缩后更新连接。&lt;/li&gt;
&lt;li&gt;可根据客户端版本配置周期刷新或自适应刷新。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;具体属性名称和默认值随 Spring Boot / Lettuce 版本变化，应以项目依赖版本文档为准。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;26.3 Replica 读取&lt;a href=&quot;#263-replica-读取&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Lettuce 支持把部分读取路由到 replica，但要注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;主从复制异步，可能读到旧数据。&lt;/li&gt;
&lt;li&gt;写后立即读、锁、余额、库存等强时效业务应读 master。&lt;/li&gt;
&lt;li&gt;Cluster 的副本读取需要客户端支持并正确发送只读连接语义。&lt;/li&gt;
&lt;li&gt;replica 故障或提升后客户端必须刷新拓扑。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;26.4 RedisTemplate 的集群操作&lt;a href=&quot;#264-redistemplate-的集群操作&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ClusterOperations&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; clusterOps &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForCluster&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;集群级操作与普通 key 操作不同：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;普通 key 命令由客户端按槽位路由。&lt;/li&gt;
&lt;li&gt;查看所有节点、在指定节点执行命令等需要 Cluster API。&lt;/li&gt;
&lt;li&gt;对单个节点执行 &lt;code&gt;KEYS&lt;/code&gt; 只能看到该节点负责的数据。&lt;/li&gt;
&lt;li&gt;Spring Data Redis 的聚合集群操作可能向多个 master 并行发送命令，成本远高于单机命令。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;27. 命令和功能限制&lt;a href=&quot;#27-命令和功能限制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;27.1 只支持 DB 0&lt;a href=&quot;#271-只支持-db-0&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis Cluster 不支持多个逻辑数据库：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SELECT 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不可用于 Cluster。&lt;/p&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;不同 Redis 实例或托管数据库。&lt;/li&gt;
&lt;li&gt;ACL 权限。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;27.2 KEYS 与 SCAN&lt;a href=&quot;#272-keys-与-scan&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在某个节点执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;KEYS *&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;只能看到该节点当前保存的 key，不等于整个集群。&lt;/p&gt;&lt;p&gt;全集群扫描需要：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;获取所有 master。&lt;/li&gt;
&lt;li&gt;分别对每个 master 使用 &lt;code&gt;SCAN&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;聚合结果并处理拓扑变化。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;生产中不要使用 &lt;code&gt;KEYS *&lt;/code&gt; 扫描大型节点。&lt;/p&gt;&lt;p&gt;Redis 8.0 起，某些明确包含单槽 Hash Tag 的 glob pattern 可以只扫描对应槽位，但仍需以客户端和服务端实际版本行为为准。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;27.3 Keyspace Notification&lt;a href=&quot;#273-keyspace-notification&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;keyspace notification 是节点本地事件，不会自动汇总整个 Cluster。监听随机单节点会漏掉其他 shard 的事件。&lt;/p&gt;&lt;p&gt;需要全集群事件时：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;在所有 master 上建立订阅。&lt;/li&gt;
&lt;li&gt;处理故障转移和拓扑刷新。&lt;/li&gt;
&lt;li&gt;或使用更适合可靠事件传递的 Stream / 消息队列方案。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;27.4 Pub/Sub&lt;a href=&quot;#274-pubsub&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;传统 Pub/Sub 和分片 Pub/Sub 的传播范围及路由不同。高规模 Cluster 应根据 Redis 版本评估 Sharded Pub/Sub：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SSUBSCRIBE channel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SPUBLISH channel message&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不要把普通 Pub/Sub 当作可靠消息队列。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;28. 常用运维命令&lt;a href=&quot;#28-常用运维命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;集群状态&lt;a href=&quot;#集群状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER INFO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER NODES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER SHARDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER LINKS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER MYID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;槽位与 key&lt;a href=&quot;#槽位与-key&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER KEYSLOT &amp;lt;key&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER COUNTKEYSINSLOT &amp;lt;slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER GETKEYSINSLOT &amp;lt;slot&amp;gt; &amp;lt;count&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;节点与复制&lt;a href=&quot;#节点与复制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER REPLICAS &amp;lt;master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;CLUSTER REPLICATE &amp;lt;master-node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ROLE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INFO REPLICATION&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;redis-cli 集群管理&lt;a href=&quot;#redis-cli-集群管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;help&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;host:port&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;host:port&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;new&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;existing&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;del-node&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;existing&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;node-id&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reshard&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;host:port&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rebalance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;host:port&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--cluster&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fix&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;host:port&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--cluster fix&lt;/code&gt; 可能修改槽位状态和数据位置，执行前必须：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;备份。&lt;/li&gt;
&lt;li&gt;明确故障原因。&lt;/li&gt;
&lt;li&gt;保存 &lt;code&gt;CLUSTER NODES&lt;/code&gt;、&lt;code&gt;CLUSTER INFO&lt;/code&gt; 和日志。&lt;/li&gt;
&lt;li&gt;在可控窗口操作。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;29. 常见故障排查&lt;a href=&quot;#29-常见故障排查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;MOVED&lt;/code&gt; 被直接返回给应用&lt;/td&gt;&lt;td&gt;客户端不支持 Cluster 或未开启重定向&lt;/td&gt;&lt;td&gt;使用 Cluster-aware 客户端；命令行加 &lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CROSSSLOT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;多个 key 不在同一 slot&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;CLUSTER KEYSLOT&lt;/code&gt; 检查，设计 Hash Tag&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CLUSTERDOWN Hash slot not served&lt;/code&gt;&lt;/td&gt;&lt;td&gt;槽位无 owner 或关联节点故障&lt;/td&gt;&lt;td&gt;&lt;code&gt;CLUSTER INFO&lt;/code&gt;、&lt;code&gt;CLUSTER NODES&lt;/code&gt;、迁槽状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CLUSTERDOWN The cluster is down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;丢失多数 master、全覆盖失败或 Bus 异常&lt;/td&gt;&lt;td&gt;检查 master 多数派、槽位覆盖和 Bus 端口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;TRYAGAIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;迁槽中的多 key 请求部分 key 已移动&lt;/td&gt;&lt;td&gt;等待迁移完成并重试&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;客户端能连 seed 但其他命令失败&lt;/td&gt;&lt;td&gt;节点通告了客户端不可达地址&lt;/td&gt;&lt;td&gt;检查 &lt;code&gt;cluster-announce-*&lt;/code&gt;、NAT 和 DNS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;节点都能连接但不能组成集群&lt;/td&gt;&lt;td&gt;Bus 端口被拦截或 Node ID/配置冲突&lt;/td&gt;&lt;td&gt;检查 Bus、防火墙和 &lt;code&gt;nodes.conf&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;新 master 加入后没有流量&lt;/td&gt;&lt;td&gt;新节点没有 slot&lt;/td&gt;&lt;td&gt;执行 reshard/rebalance&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;无法删除 master&lt;/td&gt;&lt;td&gt;master 仍持有槽位或 key&lt;/td&gt;&lt;td&gt;先迁空所有 slot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;master 故障但 replica 未提升&lt;/td&gt;&lt;td&gt;无多数派、replica 过旧或被禁止 failover&lt;/td&gt;&lt;td&gt;查看 flags、复制状态、有效性配置&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;code&gt;MOVED&lt;/code&gt; 处理和 topology refresh&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;各节点内存严重不均&lt;/td&gt;&lt;td&gt;槽位 key 分布不均、big key 或 Hash Tag 热点&lt;/td&gt;&lt;td&gt;比较 key/内存/QPS，不只看 slot 数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;迁槽速度很慢&lt;/td&gt;&lt;td&gt;big key、网络慢、目标内存压力&lt;/td&gt;&lt;td&gt;检查 key 大小、延迟和资源峰值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;节点重启后变成陌生节点&lt;/td&gt;&lt;td&gt;&lt;code&gt;nodes.conf&lt;/code&gt; 丢失或复用了错误文件&lt;/td&gt;&lt;td&gt;恢复正确集群配置文件，检查 Node ID&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/reference/cluster-spec/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：Redis Cluster specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：Scale with Redis Cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/cluster-failover/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：CLUSTER FAILOVER&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/cluster-setslot/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：CLUSTER SETSLOT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/cluster-keyslot/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：CLUSTER KEYSLOT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/using-commands/multi-key-operations/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：Multi-key operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/redis/redis/blob/unstable/redis.conf&quot; target=&quot;_blank&quot;&gt;Redis 官方配置示例：redis.conf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/&quot; target=&quot;_blank&quot;&gt;Spring Boot 官方文档：Common Application Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/redis/reference/redis/cluster.html&quot; target=&quot;_blank&quot;&gt;Spring Data Redis 官方文档：Redis Cluster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis Sentinel（哨兵）原理、部署与实践</title><link>https://aronblake.cloud/posts/redis/redis%E5%93%A8%E5%85%B5-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis%E5%93%A8%E5%85%B5-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</guid><description>Redis Sentinel（哨兵）原理、部署与实践</description><pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;1. Sentinel 解决什么问题&lt;a href=&quot;#1-sentinel-解决什么问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis 主从复制可以提供数据副本，但单纯的主从复制不能自动处理 master 故障：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;客户端通常只向 master 写入。&lt;/li&gt;
&lt;li&gt;master 宕机后，replica 不会仅凭普通主从配置自动成为 master。&lt;/li&gt;
&lt;li&gt;运维人员需要判断故障、选择 replica、提升节点并通知客户端。&lt;/li&gt;
&lt;li&gt;整个过程如果依靠人工处理，恢复时间长且容易配置错误。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Redis Sentinel 在主从复制之上增加高可用能力，主要提供四项功能：&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;监控 Monitoring&lt;/td&gt;&lt;td&gt;持续检查 master、replica 和其他 Sentinel 是否可达&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;通知 Notification&lt;/td&gt;&lt;td&gt;通过日志、Pub/Sub 事件或脚本报告实例状态变化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;自动故障转移 Automatic failover&lt;/td&gt;&lt;td&gt;master 故障后选择一个合适的 replica，将其提升为新 master&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;配置提供 Configuration provider&lt;/td&gt;&lt;td&gt;向客户端提供当前 master 的地址，实现服务发现&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;一句话概括：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;主从复制负责复制数据，Sentinel 负责监控主从拓扑并在 master 故障时完成自动切换。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Sentinel 本身：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;不保存业务数据。&lt;/li&gt;
&lt;li&gt;不代理业务读写流量。&lt;/li&gt;
&lt;li&gt;不能代替 RDB、AOF 和独立备份。&lt;/li&gt;
&lt;li&gt;不提供数据分片。&lt;/li&gt;
&lt;li&gt;不能把异步主从复制变成强一致复制。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. Sentinel、主从复制、持久化与 Cluster 的区别&lt;a href=&quot;#2-sentinel主从复制持久化与-cluster-的区别&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;是否自动切换 master&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;RDB/AOF&lt;/td&gt;&lt;td&gt;单节点重启后的数据恢复&lt;/td&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;否&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;否，默认异步复制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel&lt;/td&gt;&lt;td&gt;非分片主从架构的高可用&lt;/td&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;Redis Cluster&lt;/td&gt;&lt;td&gt;分片、扩容和分片级高可用&lt;/td&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;适合 Sentinel 的场景：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;数据量可以由单个 master 承载。&lt;/li&gt;
&lt;li&gt;需要一个写主节点和若干只读副本。&lt;/li&gt;
&lt;li&gt;需要 master 故障后的自动切换。&lt;/li&gt;
&lt;li&gt;客户端支持 Sentinel 服务发现。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不适合仅使用 Sentinel 的场景：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;数据量或写吞吐已经超过单个 master 的容量。&lt;/li&gt;
&lt;li&gt;需要多个节点共同承担读流量和写流量。&lt;/li&gt;
&lt;li&gt;需要跨分片水平扩容。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这些场景通常应考虑 Redis Cluster 或托管 Redis 服务。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 推荐架构&lt;a href=&quot;#3-推荐架构&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;生产环境通常至少部署：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;1 个 master。&lt;/li&gt;
&lt;li&gt;2 个或更多 replica。&lt;/li&gt;
&lt;li&gt;3 个或更多 Sentinel，数量一般使用奇数。&lt;/li&gt;
&lt;li&gt;支持 Sentinel 的客户端。&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;业务写入&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────────────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ Redis Master M │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└───────┬────────┘&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 异步复制&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────────┴────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓                 ↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────────────────┐ ┌────────────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ Redis Replica 1│ │ Redis Replica 2│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└────────────────┘ └────────────────┘&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────────────┐ ┌────────────┐ ┌────────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ Sentinel S1│ │ Sentinel S2│ │ Sentinel S3│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└────────────┘ └────────────┘ └────────────┘&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;               &lt;/span&gt;&lt;/span&gt;&lt;span&gt;\             |             /&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;\──监控所有 Redis 节点────/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1. 连接多个 Sentinel 地址。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2. 询问逻辑主节点 mymaster 当前对应的 IP 和端口。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;3. 连接返回的 master 执行业务写入。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;4. 故障转移后重新发现并连接新 master。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;3.1 为什么至少部署三个 Sentinel&lt;a href=&quot;#31-为什么至少部署三个-sentinel&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Sentinel 是分布式系统。多个 Sentinel 共同判断故障，可以降低单点故障和误判风险。&lt;/p&gt;&lt;p&gt;两个 Sentinel 并不是稳健部署：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;若一台机器同时运行 master 和 Sentinel，机器故障后只剩一个 Sentinel。&lt;/li&gt;
&lt;li&gt;执行故障转移需要 Sentinel 多数派授权。&lt;/li&gt;
&lt;li&gt;两个 Sentinel 的多数派是两个，剩余一个 Sentinel 无法授权切换。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;三个 Sentinel 的多数派是两个，只要仍有两个 Sentinel 互相通信，就有机会完成故障转移。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 Sentinel 应放在不同故障域&lt;a href=&quot;#32-sentinel-应放在不同故障域&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;把三个 Sentinel 全部运行在同一台主机，只适合本地实验，不能消除单点故障。&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;Sentinel 的网络视角尽量接近业务客户端。&lt;/li&gt;
&lt;li&gt;Sentinel 与 Redis 数据节点之间、Sentinel 彼此之间都要能双向通信。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. Sentinel 如何发现拓扑&lt;a href=&quot;#4-sentinel-如何发现拓扑&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;每个 Sentinel 初始只需要配置要监控的 master：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel monitor mymaster 192.168.150.101 7001 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不需要在每个 &lt;code&gt;sentinel.conf&lt;/code&gt; 中手动列出所有 replica 和其他 Sentinel。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;4.1 发现 replica&lt;a href=&quot;#41-发现-replica&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Sentinel 定期向 master 获取复制信息，从 master 报告的拓扑中发现 replica，并继续监控这些 replica。&lt;/p&gt;&lt;p&gt;因此必须保证：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 已正确执行 &lt;code&gt;replicaof&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;master 能报告 replica 的可访问地址。&lt;/li&gt;
&lt;li&gt;Sentinel 能访问 replica 对外通告的 IP 和端口。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 发现其他 Sentinel&lt;a href=&quot;#42-发现其他-sentinel&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;监控同一 master 的 Sentinel 会通过 Redis 实例的 Pub/Sub 频道交换 hello 消息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__sentinel__:hello&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;hello 消息包含 Sentinel 的地址、端口、运行 ID 和已知 master 配置版本等信息。&lt;/p&gt;&lt;p&gt;这使 Sentinel 能够：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;自动发现监控同一 master 的其他 Sentinel。&lt;/li&gt;
&lt;li&gt;交换主节点配置和版本信息。&lt;/li&gt;
&lt;li&gt;在故障时询问其他 Sentinel 对 master 状态的判断。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.3 自动改写配置&lt;a href=&quot;#43-自动改写配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Sentinel 会把发现的拓扑、运行 ID、配置纪元和故障转移结果写回 &lt;code&gt;sentinel.conf&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;启动 Sentinel 必须提供配置文件。&lt;/li&gt;
&lt;li&gt;Sentinel 对配置文件所在路径必须具有写权限。&lt;/li&gt;
&lt;li&gt;不应把 &lt;code&gt;sentinel.conf&lt;/code&gt; 挂载为只读文件。&lt;/li&gt;
&lt;li&gt;配置管理系统不应持续用旧模板覆盖 Sentinel 自动写入的运行状态。&lt;/li&gt;
&lt;li&gt;可以用 &lt;code&gt;SENTINEL FLUSHCONFIG&lt;/code&gt; 强制写回当前状态。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 健康监控：PING、SDOWN 与 ODOWN&lt;a href=&quot;#5-健康监控pingsdown-与-odown&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sentinel 会周期性向 master、replica 和其他 Sentinel 发送命令并检查响应。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;5.1 主观下线 SDOWN&lt;a href=&quot;#51-主观下线-sdown&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;SDOWN 是 Subjectively Down，表示：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;某一个 Sentinel 根据自己的观察，认为目标实例不可达。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel down-after-milliseconds mymaster 5000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果某 Sentinel 在完整的 &lt;code&gt;down-after-milliseconds&lt;/code&gt; 时间内没有收到可接受的 PING 响应，就会把目标标记为 SDOWN。&lt;/p&gt;&lt;p&gt;可接受的 PING 响应包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+PONG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-LOADING&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-MASTERDOWN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;SDOWN 是单个 Sentinel 的本地判断，可能由以下问题引发：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Redis 进程真的宕机。&lt;/li&gt;
&lt;li&gt;Sentinel 到 Redis 的网络中断。&lt;/li&gt;
&lt;li&gt;Redis 阻塞或负载过高，无法及时响应。&lt;/li&gt;
&lt;li&gt;DNS、NAT、防火墙或路由配置错误。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;单个 Sentinel 的 SDOWN 不足以触发自动故障转移。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 客观下线 ODOWN&lt;a href=&quot;#52-客观下线-odown&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;ODOWN 是 Objectively Down，表示：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;至少达到配置的 quorum 数量的 Sentinel 都认为 master 已经下线。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Sentinel 之间会使用内部询问命令交换对 master 的判断。当达到 quorum 后，master 从 SDOWN 进入 ODOWN。&lt;/p&gt;&lt;p&gt;需要注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;ODOWN 只针对 master。&lt;/li&gt;
&lt;li&gt;replica 和其他 Sentinel 只会被标记为 SDOWN，不会进入 ODOWN。&lt;/li&gt;
&lt;li&gt;replica 处于 SDOWN 时不会被选为新 master。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 状态变化流程&lt;a href=&quot;#53-状态变化流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Redis 正常&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 某 Sentinel 在 down-after-milliseconds 内&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 没有收到有效响应&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;该 Sentinel 判定 SDOWN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 询问其他 Sentinel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 达到 quorum 个 Sentinel 同意&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master 被判定 ODOWN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 获得多数派授权并选出故障转移领导者&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;开始自动故障转移&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. quorum 与多数派：最容易混淆的概念&lt;a href=&quot;#6-quorum-与多数派最容易混淆的概念&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;配置示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel monitor mymaster 192.168.150.101 7001 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;最后一个参数 &lt;code&gt;2&lt;/code&gt; 是 quorum。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;6.1 quorum 的作用&lt;a href=&quot;#61-quorum-的作用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;quorum 表示：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;至少多少个 Sentinel 同意 master 不可达，才能将 master 标记为 ODOWN。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;它用于故障检测，不是 replica 竞选新 master 的票数。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 多数派的作用&lt;a href=&quot;#62-多数派的作用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;进入 ODOWN 后，还需要选出一个负责本次故障转移的 Sentinel 领导者。真正执行故障转移必须获得 Sentinel 多数派授权。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Sentinel 总数 N&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;多数派 = floor(N / 2) + 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sentinel 总数&lt;/th&gt;&lt;th&gt;多数派&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;执行故障转移需要同时满足：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;达到 quorum，master 被判定为 ODOWN。&lt;/li&gt;
&lt;li&gt;某 Sentinel 获得执行故障转移所需的多数派授权；如果 quorum 高于多数派，还必须满足更高的 quorum。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 五个 Sentinel、quorum 为 2 的例子&lt;a href=&quot;#63-五个-sentinelquorum-为-2-的例子&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Sentinel 总数：5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;quorum：2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;多数派：3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;只要 2 个 Sentinel 认为 master 下线，就可触发 ODOWN。&lt;/li&gt;
&lt;li&gt;但实际执行故障转移时，领导者仍至少需要 3 个 Sentinel 的授权。&lt;/li&gt;
&lt;li&gt;如果只有 2 个 Sentinel 能相互通信，可能判定 ODOWN，但不能真正完成自动切换。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.4 quorum 如何选择&lt;a href=&quot;#64-quorum-如何选择&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;三个 Sentinel 常用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel monitor mymaster 192.168.150.101 7001 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;建议原则：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;通常使用奇数个 Sentinel。&lt;/li&gt;
&lt;li&gt;三个 Sentinel 常将 quorum 设为 2。&lt;/li&gt;
&lt;li&gt;quorum 越小，故障检测越敏感，也越容易受局部网络问题影响。&lt;/li&gt;
&lt;li&gt;quorum 越大，误切换概率较低，但自动切换所需的可达 Sentinel 更多。&lt;/li&gt;
&lt;li&gt;上线前应运行 &lt;code&gt;SENTINEL CKQUORUM&lt;/code&gt; 检查 quorum 和多数派条件。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. Sentinel 领导者选举&lt;a href=&quot;#7-sentinel-领导者选举&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;ODOWN 只说明多个 Sentinel 同意 master 下线。为了避免多个 Sentinel 同时发起相互冲突的切换，每次故障转移还要选出一个领导者。&lt;/p&gt;&lt;p&gt;简化过程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Sentinel 发现 master 进入 ODOWN。&lt;/li&gt;
&lt;li&gt;发起一次新的故障转移尝试，并为本次尝试使用新的配置纪元。&lt;/li&gt;
&lt;li&gt;向其他 Sentinel 请求授权。&lt;/li&gt;
&lt;li&gt;每个 Sentinel 在一个配置纪元中只会投出符合协议的一票。&lt;/li&gt;
&lt;li&gt;获得所需授权的 Sentinel 成为本次故障转移领导者。&lt;/li&gt;
&lt;li&gt;只有该领导者负责选择 replica 和执行切换。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;配置纪元可以理解为 Sentinel 配置的递增版本号：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;每次有效故障转移都拥有唯一的配置纪元。&lt;/li&gt;
&lt;li&gt;其他 Sentinel 收到更新的配置后采用较新的版本。&lt;/li&gt;
&lt;li&gt;网络恢复后，不同分区中的 Sentinel 最终会收敛到最新逻辑配置。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 如何选择新的 master&lt;a href=&quot;#8-如何选择新的-master&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;领导者会从可用 replica 中选择一个提升为新 master。&lt;/p&gt;&lt;p&gt;选择前先排除不合格 replica，例如：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;已被 Sentinel 判定 SDOWN。&lt;/li&gt;
&lt;li&gt;长时间与原 master 断开。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replica-priority&lt;/code&gt; 配置为 &lt;code&gt;0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;状态异常或当前不适合提升。&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h3&gt;8.1 断线时间筛选&lt;a href=&quot;#81-断线时间筛选&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果 replica 与 master 断开的时间超过以下范围，会被认为不可靠：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;(down-after-milliseconds × 10)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;+ 当前 master 已处于 SDOWN 的持续时间&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;讲义中常简写成 &lt;code&gt;down-after-milliseconds × 10&lt;/code&gt;，完整判断还包含 master 已处于 SDOWN 的时间。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;8.2 候选 replica 排序规则&lt;a href=&quot;#82-候选-replica-排序规则&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;合格候选者按照以下顺序比较：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;replica-priority&lt;/code&gt;：数值越小，优先级越高。&lt;/li&gt;
&lt;li&gt;复制 offset：越大说明接收的数据通常越新，优先级越高。&lt;/li&gt;
&lt;li&gt;run ID：前两项相同则选择字典序更小的 run ID，用于得到确定性结果。&lt;/li&gt;
&lt;/ol&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;与 master 的断线时间&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;replica-priority&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;复制 offset&lt;/td&gt;&lt;td&gt;越大越优先&lt;/td&gt;&lt;td&gt;尽量选择数据更新的副本&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;run ID&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;/section&gt;&lt;section&gt;&lt;h3&gt;8.3 replica-priority&lt;a href=&quot;#83-replica-priority&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 节点配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-priority 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;特殊值：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-priority 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;表示该 replica 永远不被 Sentinel 提升为 master，但它仍会继续作为 replica 接收数据，并可在故障转移后改为复制新的 master。&lt;/p&gt;&lt;p&gt;常见使用场景：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;专门承担备份任务、性能较差的 replica 设置为 &lt;code&gt;0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;同机房副本优先级设为 &lt;code&gt;10&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;异地灾备副本优先级设为 &lt;code&gt;100&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果一个节点未来可能从 master 变为 replica，建议所有 Redis 实例都配置符合其故障域定位的 &lt;code&gt;replica-priority&lt;/code&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 自动故障转移完整流程&lt;a href=&quot;#9-自动故障转移完整流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;假设原拓扑：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master M1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── Replica R1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;└── Replica R2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;完整流程如下：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;一个或多个 Sentinel 发现 M1 无法正常响应，分别将其标记为 SDOWN。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;达到 quorum 后，M1 被标记为 ODOWN。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sentinel 通过投票选出本次故障转移的领导者。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;领导者筛选合格 replica。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按优先级、复制 offset 和 run ID 选择 R1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;领导者向 R1 发送：&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;REPLICAOF NO ONE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sentinel 通过 &lt;code&gt;INFO&lt;/code&gt; 观察到 R1 已成为 master。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sentinel 发布新的主节点配置，其他 Sentinel 和客户端开始获知 R1 的地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sentinel 向 R2 发送：&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;REPLICAOF &amp;lt;R1-IP&amp;gt; &amp;lt;R1-PORT&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;R2 开始复制新 master R1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;原 master M1 恢复后，Sentinel 将其改为 R1 的 replica。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;角色变化：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;故障前：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;M1：Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R1：Replica of M1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R2：Replica of M1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;M1 故障后：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;M1：不可用&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R1：New Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R2：Replica of R1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;M1 恢复后：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R1：Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;R2：Replica of R1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;M1：Replica of R1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;原 master 恢复并不自动夺回 master 身份。&lt;/li&gt;
&lt;li&gt;Sentinel 会持续把最新逻辑配置施加到恢复或重新连通的节点。&lt;/li&gt;
&lt;li&gt;故障转移成功的关键点是候选 replica 已收到 &lt;code&gt;REPLICAOF NO ONE&lt;/code&gt;，且 Sentinel 从 &lt;code&gt;INFO&lt;/code&gt; 中确认它已经切换为 master。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. Sentinel 核心配置&lt;a href=&quot;#10-sentinel-核心配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;10.1 最小配置示例&lt;a href=&quot;#101-最小配置示例&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;port 26379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bind 0.0.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;protected-mode yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dir &quot;/var/lib/redis-sentinel&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel monitor mymaster 192.168.150.101 7001 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel down-after-milliseconds mymaster 5000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel failover-timeout mymaster 180000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel parallel-syncs mymaster 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10.2 配置项说明&lt;a href=&quot;#102-配置项说明&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;port&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sentinel 监听端口，默认 26379&lt;/td&gt;&lt;td&gt;每个实例必须可被其他 Sentinel 和客户端访问&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;dir&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;sentinel monitor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;逻辑 master 名称、初始地址和 quorum&lt;/td&gt;&lt;td&gt;master 名称必须与客户端配置一致&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;down-after-milliseconds&lt;/code&gt;&lt;/td&gt;&lt;td&gt;判定 SDOWN 所需的连续无有效响应时间&lt;/td&gt;&lt;td&gt;太小容易误判，太大则恢复较慢&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;failover-timeout&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;parallel-syncs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;故障转移后允许同时改为复制新 master 的 replica 数量&lt;/td&gt;&lt;td&gt;数值越大恢复快，但同步压力和同时不可读副本数可能增加&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10.3 parallel-syncs&lt;a href=&quot;#103-parallel-syncs&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel parallel-syncs mymaster 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;设置为 &lt;code&gt;1&lt;/code&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;每次只让一个 replica 与新 master 重新同步。&lt;/li&gt;
&lt;li&gt;减少多个 replica 同时加载全量数据造成的服务影响。&lt;/li&gt;
&lt;li&gt;整体完成时间可能更长。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;设置为较大值：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;可以更快完成所有 replica 的重新配置。&lt;/li&gt;
&lt;li&gt;可能同时触发多个复制同步，增加 CPU、内存、磁盘和网络压力。&lt;/li&gt;
&lt;li&gt;如果 replica 在同步加载数据时暂时不可读，可用读副本数量会同时减少。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10.4 failover-timeout&lt;a href=&quot;#104-failover-timeout&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;failover-timeout&lt;/code&gt; 参与多种故障转移内部时间控制，包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;一次故障转移尝试的时间边界。&lt;/li&gt;
&lt;li&gt;失败后再次尝试故障转移的间隔。&lt;/li&gt;
&lt;li&gt;replica 改为复制新 master 时的重配置节奏。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不应把它误解为 master 多久没有响应后才判定故障；后者由 &lt;code&gt;down-after-milliseconds&lt;/code&gt; 控制。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;11. 示例：三节点 Sentinel 实验环境&lt;a href=&quot;#11-示例三节点-sentinel-实验环境&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;讲义中的实验结构：&lt;/p&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sentinel&lt;/th&gt;&lt;th&gt;IP&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;S1&lt;/td&gt;&lt;td&gt;192.168.150.101&lt;/td&gt;&lt;td&gt;27001&lt;/td&gt;&lt;td&gt;&lt;code&gt;/tmp/s1&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;S2&lt;/td&gt;&lt;td&gt;192.168.150.101&lt;/td&gt;&lt;td&gt;27002&lt;/td&gt;&lt;td&gt;&lt;code&gt;/tmp/s2&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;S3&lt;/td&gt;&lt;td&gt;192.168.150.101&lt;/td&gt;&lt;td&gt;27003&lt;/td&gt;&lt;td&gt;&lt;code&gt;/tmp/s3&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;S1：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;port 27001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel announce-ip 192.168.150.101&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel monitor mymaster 192.168.150.101 7001 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel down-after-milliseconds mymaster 5000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel failover-timeout mymaster 60000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel parallel-syncs mymaster 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dir &quot;/tmp/s1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;S2、S3 分别使用不同端口和目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;S2：port 27002，dir &quot;/tmp/s2&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;S3：port 27003，dir &quot;/tmp/s3&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;启动方式一：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-sentinel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/tmp/s1/sentinel.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-sentinel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/tmp/s2/sentinel.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-sentinel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/tmp/s3/sentinel.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;启动方式二：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-server&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/tmp/s1/sentinel.conf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--sentinel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;说明：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;同一台机器运行三个 Sentinel 只能验证功能。&lt;/li&gt;
&lt;li&gt;生产环境必须将 Sentinel 分散到独立故障域。&lt;/li&gt;
&lt;li&gt;启动前应确保端口、防火墙、配置文件写权限和数据节点认证正确。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;12. 认证与安全&lt;a href=&quot;#12-认证与安全&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sentinel 环境包含三类连接：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Sentinel 连接 Redis master 和 replica。&lt;/li&gt;
&lt;li&gt;Sentinel 连接其他 Sentinel。&lt;/li&gt;
&lt;li&gt;业务客户端连接 Sentinel，并连接 Redis 数据节点。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;三类连接的认证不能混为一谈。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;12.1 Redis 数据节点要求密码&lt;a href=&quot;#121-redis-数据节点要求密码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;密码模式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel auth-pass mymaster redis-data-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;ACL 模式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel auth-user mymaster sentinel-monitor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel auth-pass mymaster redis-data-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这个凭证供 Sentinel 访问 &lt;code&gt;mymaster&lt;/code&gt; 对应的 master 和 replica。该组 Redis 数据节点应使用兼容的认证配置。&lt;/p&gt;&lt;p&gt;replica 自己连接 master 时也需要配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;masteruser replication-user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;masterauth replication-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.2 保护 Sentinel 自身&lt;a href=&quot;#122-保护-sentinel-自身&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Sentinel 本身也暴露 Redis 协议端口，不能直接暴露到不可信网络。&lt;/p&gt;&lt;p&gt;密码模式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;requirepass &quot;sentinel-password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用密码模式时，各 Sentinel 通常要使用相同密码，以便彼此认证。还要确认客户端库支持连接 Sentinel 时发送认证信息。&lt;/p&gt;&lt;p&gt;ACL 模式可以分别配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel sentinel-user sentinel-admin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel sentinel-pass sentinel-admin-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这组凭证用于 Sentinel 之间的连接。业务客户端访问 Sentinel 时也应使用权限受限的专用用户。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.3 安全建议&lt;a href=&quot;#123-安全建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;使用 ACL 创建最小权限用户，避免业务客户端使用默认超级用户。&lt;/li&gt;
&lt;li&gt;Sentinel 端口只允许应用服务器、运维网络和其他 Sentinel 访问。&lt;/li&gt;
&lt;li&gt;Redis 数据端口只允许应用、Sentinel 和复制节点访问。&lt;/li&gt;
&lt;li&gt;跨主机或跨可用区连接考虑启用 TLS。&lt;/li&gt;
&lt;li&gt;密码不要直接硬编码在代码仓库和公开配置模板中。&lt;/li&gt;
&lt;li&gt;定期轮换凭证，并验证所有 Sentinel、replica 和客户端均已同步更新。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;13. NAT、Docker、主机名与地址通告&lt;a href=&quot;#13-natdocker主机名与地址通告&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sentinel 自动发现依赖节点通告的 IP 和端口。容器端口映射或 NAT 可能导致节点通告内部地址，使其他 Sentinel 或客户端无法访问。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;13.1 Sentinel 地址通告&lt;a href=&quot;#131-sentinel-地址通告&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel announce-ip 192.168.150.101&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel announce-port 27001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每个 Sentinel 都应通告其他 Sentinel 和客户端实际可达的地址。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;13.2 Redis replica 地址通告&lt;a href=&quot;#132-redis-replica-地址通告&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-announce-ip 192.168.150.102&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-announce-port 7002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;否则 master 报告给 Sentinel 的 replica 地址可能是容器内部地址。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;13.3 使用主机名&lt;a href=&quot;#133-使用主机名&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;较新 Redis 版本可以配置 Sentinel 解析和通告主机名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel resolve-hostnames yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sentinel announce-hostnames yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;DNS 必须稳定且解析迅速。&lt;/li&gt;
&lt;li&gt;应统一使用主机名或统一使用 IP，避免混用。&lt;/li&gt;
&lt;li&gt;部分旧客户端可能只接受 IP 地址。&lt;/li&gt;
&lt;li&gt;TLS 证书校验依赖主机名时，通告主机名通常更合适。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;14. 客户端如何接入 Sentinel&lt;a href=&quot;#14-客户端如何接入-sentinel&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sentinel 不代理业务命令。客户端必须显式支持 Sentinel。&lt;/p&gt;&lt;p&gt;典型写连接流程：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端启动&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─连接任意可用 Sentinel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─执行 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─获得当前 master 地址&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├─连接 master 并验证其角色&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└─连接断开或发生切换后，再次进行服务发现&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;客户端配置应包含：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;逻辑 master 名称，例如 &lt;code&gt;mymaster&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;多个 Sentinel 地址，而不是只配置一个。&lt;/li&gt;
&lt;li&gt;Sentinel 的认证信息。&lt;/li&gt;
&lt;li&gt;Redis 数据节点的认证信息。&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;在业务代码中永久写死原 master 的 IP。&lt;/li&gt;
&lt;li&gt;只配置一个 Sentinel 地址。&lt;/li&gt;
&lt;li&gt;把 Sentinel 地址当成 Redis 数据地址直接执行 &lt;code&gt;GET&lt;/code&gt;、&lt;code&gt;SET&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在非幂等写入上进行无边界自动重试。&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h3&gt;14.1 常用服务发现命令&lt;a href=&quot;#141-常用服务发现命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL GET-MASTER-ADDR-BY-NAME mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回当前 master 的 IP 和端口。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL REPLICAS mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看 Sentinel 已知的 replica。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL SENTINELS mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看 Sentinel 已知的其他 Sentinel。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;15. Spring Boot 与 RedisTemplate&lt;a href=&quot;#15-spring-boot-与-redistemplate&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Spring Boot 3.x 使用 &lt;code&gt;spring.data.redis&lt;/code&gt; 配置前缀：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;spring&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;app-user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;app-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;sentinel&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;master&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:27001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.102:27002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.103:27003&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;username&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;sentinel-client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;sentinel-client-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;connect-timeout&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;较早的 Spring Boot 版本常使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;spring&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;sentinel&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;master&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.101:27001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.102:27002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;192.168.150.103:27003&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;具体前缀和认证属性应以项目实际 Spring Boot / Spring Data Redis 版本为准。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;15.1 Lettuce 读策略&lt;a href=&quot;#151-lettuce-读策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;现代 Spring Boot 可使用属性控制 Lettuce 读来源，具体可用值取决于当前版本：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;spring&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;lettuce&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;read-from&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;replica-preferred&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也可以通过代码定制：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;LettuceClientConfigurationBuilderCustomizer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redisReadFromCustomizer&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; builder &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ReadFrom&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;REPLICA_PREFERRED&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;读取位置&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;MASTER&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只读 master&lt;/td&gt;&lt;td&gt;一致性相对更好，读压力集中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;MASTER_PREFERRED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;优先 master&lt;/td&gt;&lt;td&gt;master 不可用时尝试 replica&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;REPLICA&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只读 replica&lt;/td&gt;&lt;td&gt;可能读到旧数据，副本不可用时可能失败&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;REPLICA_PREFERRED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;优先 replica&lt;/td&gt;&lt;td&gt;适合允许短暂陈旧读的业务&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;主从复制是异步的。即使写入 master 已返回成功，立即从 replica 读取也可能读取不到新值。&lt;/p&gt;&lt;p&gt;以下场景通常应从 master 读取：&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;li&gt;依赖最新数据进行后续写入的逻辑。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;16. Sentinel 与数据一致性&lt;a href=&quot;#16-sentinel-与数据一致性&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;16.1 为什么故障转移仍可能丢数据&lt;a href=&quot;#161-为什么故障转移仍可能丢数据&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 主从复制默认异步：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端 ──写入──→ 旧 Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端 ←─OK──── 旧 Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 写命令尚未复制到 Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;× 旧 Master 故障&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Replica 被提升为新 Master，但缺少刚才的写入。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此 Sentinel 可以缩短故障恢复时间，但不能保证已确认写入一定保留。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;16.2 网络分区与旧 master&lt;a href=&quot;#162-网络分区与旧-master&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;网络分区时可能出现：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;旧 master 与多数 Sentinel、replica 失联。&lt;/li&gt;
&lt;li&gt;多数派一侧把 replica 提升为新 master。&lt;/li&gt;
&lt;li&gt;旧 master 所在分区仍可能被部分旧客户端访问并接受写入。&lt;/li&gt;
&lt;li&gt;网络恢复后，旧 master 被改为新 master 的 replica。&lt;/li&gt;
&lt;li&gt;旧 master 分区期间独有的写入会被新主线覆盖。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;16.3 限制旧 master 的孤立写入&lt;a href=&quot;#163-限制旧-master-的孤立写入&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在所有可能成为 master 的 Redis 节点配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-to-write 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-max-lag 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;master 至少要有 1 个延迟不超过要求的 replica。&lt;/li&gt;
&lt;li&gt;如果在 10 秒内无法获得足够 replica 的进度确认，master 停止接受写入。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;作用：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;缩短网络分区中旧 master 继续产生孤立写入的时间窗口。&lt;/li&gt;
&lt;li&gt;降低故障恢复后被覆盖的数据量。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;代价：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 故障或网络抖动时，master 可能拒绝写入。&lt;/li&gt;
&lt;li&gt;系统可用性下降。&lt;/li&gt;
&lt;li&gt;仍然不是严格同步复制，也不是绝对零丢失保证。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;16.4 关键写入使用 WAIT&lt;a href=&quot;#164-关键写入使用-wait&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET order:1001 paid&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;WAIT 1 1000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;表示最多等待 1000 毫秒，希望至少一个 replica 确认已接收到当前连接之前的写入。&lt;/p&gt;&lt;p&gt;应用必须检查 &lt;code&gt;WAIT&lt;/code&gt; 的返回值。&lt;code&gt;WAIT&lt;/code&gt; 可以提高写入到达 replica 的概率，但：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;不能把 Redis 变为强一致系统。&lt;/li&gt;
&lt;li&gt;不等于写入已按业务要求持久化到磁盘。&lt;/li&gt;
&lt;li&gt;不能替代 AOF、RDB 和独立备份。&lt;/li&gt;
&lt;li&gt;不能消除客户端重试造成的重复写风险。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;17. Sentinel 与持久化&lt;a href=&quot;#17-sentinel-与持久化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sentinel 依赖 replica 提升为新 master，因此所有可能被提升的节点都应有适当的持久化配置。&lt;/p&gt;&lt;p&gt;建议：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;并根据恢复目标配置 RDB 快照和独立备份。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;17.1 危险组合&lt;a href=&quot;#171-危险组合&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;以下组合风险极高：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master 关闭 RDB&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;+ Master 关闭 AOF&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;+ 进程崩溃后自动重启&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;可能过程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;master 崩溃。&lt;/li&gt;
&lt;li&gt;进程管理器迅速把它自动重启。&lt;/li&gt;
&lt;li&gt;因无持久化文件，master 以空数据集启动。&lt;/li&gt;
&lt;li&gt;Sentinel 可能尚未完成故障转移。&lt;/li&gt;
&lt;li&gt;replica 继续把空 master 当作复制源。&lt;/li&gt;
&lt;li&gt;空数据集被同步给 replica，整个复制组的数据一起丢失。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;不要把 Sentinel 当作持久化和备份。&lt;/li&gt;
&lt;li&gt;master 关闭持久化时，不应允许它在故障后未经控制地空数据自动重启。&lt;/li&gt;
&lt;li&gt;所有可能成为 master 的节点都应具备符合业务 RPO 的恢复能力。&lt;/li&gt;
&lt;li&gt;备份应放在复制组之外，防止误删命令和逻辑错误同步到所有副本。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;18. 常用运维命令&lt;a href=&quot;#18-常用运维命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;连接 Sentinel：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.150.101&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;27001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;若需要认证：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.150.101&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;27001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--user&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sentinel-client&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--pass&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;password&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;18.1 查询状态&lt;a href=&quot;#181-查询状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PING&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INFO sentinel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ROLE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL MASTERS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL MASTER mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL REPLICAS mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL SENTINELS mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL GET-MASTER-ADDR-BY-NAME mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL CKQUORUM mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;18.2 动态配置&lt;a href=&quot;#182-动态配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;修改 master 专属配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL SET mymaster down-after-milliseconds 10000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL SET mymaster parallel-syncs 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;修改 Sentinel 全局配置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL CONFIG GET *&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL CONFIG SET resolve-hostnames yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;动态修改应在所有 Sentinel 上保持一致。只修改一个 Sentinel，不会自动把该项运行时配置传播给所有 Sentinel。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;18.3 手动触发故障转移&lt;a href=&quot;#183-手动触发故障转移&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SENTINEL FAILOVER mymaster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;该命令会强制 Sentinel 为指定 master 发起故障转移，不需要先把 master 判定为 ODOWN。&lt;/p&gt;&lt;p&gt;使用前必须确认：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;存在健康且复制进度合适的 replica。&lt;/li&gt;
&lt;li&gt;客户端具备重连能力。&lt;/li&gt;
&lt;li&gt;监控和回滚方案已经准备。&lt;/li&gt;
&lt;li&gt;不会与正在进行的自动故障转移冲突。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;18.4 订阅事件&lt;a href=&quot;#184-订阅事件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PSUBSCRIBE *&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;常见 Sentinel 日志和 Pub/Sub 事件：&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+sdown&lt;/code&gt;&lt;/td&gt;&lt;td&gt;实例进入主观下线&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-sdown&lt;/code&gt;&lt;/td&gt;&lt;td&gt;实例退出主观下线&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+odown&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master 进入客观下线&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-odown&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master 退出客观下线&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+try-failover&lt;/code&gt;&lt;/td&gt;&lt;td&gt;开始尝试故障转移&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+elected-leader&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前 Sentinel 当选故障转移领导者&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+selected-slave&lt;/code&gt;&lt;/td&gt;&lt;td&gt;已选中待提升 replica&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+failover-state-send-slaveof-noone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;正在提升 replica&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+slave-reconf-sent&lt;/code&gt;&lt;/td&gt;&lt;td&gt;已发送重新复制新 master 的命令&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+slave-reconf-done&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica 已完成对新 master 的同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+switch-master&lt;/code&gt;&lt;/td&gt;&lt;td&gt;master 地址已经切换&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+failover-end&lt;/code&gt;&lt;/td&gt;&lt;td&gt;故障转移结束&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+tilt&lt;/code&gt; / &lt;code&gt;-tilt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;进入或退出 TILT 保护模式&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;19. 故障排查表&lt;a href=&quot;#19-故障排查表&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;master 已宕机但未自动切换&lt;/td&gt;&lt;td&gt;未达到 quorum 或多数派；无合格 replica&lt;/td&gt;&lt;td&gt;&lt;code&gt;SENTINEL CKQUORUM&lt;/code&gt;、&lt;code&gt;SENTINEL REPLICAS&lt;/code&gt;、Sentinel 日志&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;只有 SDOWN，没有 ODOWN&lt;/td&gt;&lt;td&gt;其他 Sentinel 不同意或彼此无法通信&lt;/td&gt;&lt;td&gt;检查 Sentinel 数量、端口、防火墙、认证&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;达到 ODOWN 但不切换&lt;/td&gt;&lt;td&gt;无法获得多数派授权&lt;/td&gt;&lt;td&gt;检查 Sentinel 网络分区和已知 Sentinel 数量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;日志出现 &lt;code&gt;no-good-slave&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replica 断线过久、SDOWN、优先级为 0 或状态异常&lt;/td&gt;&lt;td&gt;检查 &lt;code&gt;INFO replication&lt;/code&gt; 和 &lt;code&gt;replica-priority&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;新 master 已产生但客户端仍报错&lt;/td&gt;&lt;td&gt;客户端不支持 Sentinel、只配置一个 Sentinel 或连接池未刷新&lt;/td&gt;&lt;td&gt;检查客户端服务发现和重连日志&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel 无法启动&lt;/td&gt;&lt;td&gt;未提供配置文件或文件不可写&lt;/td&gt;&lt;td&gt;检查启动参数、目录和文件权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel 发现错误 IP&lt;/td&gt;&lt;td&gt;Docker/NAT/主机名通告错误&lt;/td&gt;&lt;td&gt;配置 announce IP/port 和 replica announce&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel 无法认证 Redis&lt;/td&gt;&lt;td&gt;&lt;code&gt;auth-user&lt;/code&gt;/&lt;code&gt;auth-pass&lt;/code&gt; 错误或 ACL 权限不足&lt;/td&gt;&lt;td&gt;分别检查数据节点和 Sentinel 的认证&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;故障转移后多个 replica 同时卡顿&lt;/td&gt;&lt;td&gt;&lt;code&gt;parallel-syncs&lt;/code&gt; 过大或触发全量同步&lt;/td&gt;&lt;td&gt;调低并发同步，检查 backlog 与资源&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;读到旧数据&lt;/td&gt;&lt;td&gt;从 replica 读取且复制存在延迟&lt;/td&gt;&lt;td&gt;强时效读走 master，监控复制延迟&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;旧 master 恢复后变成 replica&lt;/td&gt;&lt;td&gt;Sentinel 的正常行为&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;code&gt;WAIT&lt;/code&gt;、min-replicas、持久化和业务补偿&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：High availability with Redis Sentinel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/replication/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/info/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：INFO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/wait/&quot; target=&quot;_blank&quot;&gt;Redis 官方文档：WAIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/redis/redis/blob/unstable/redis.conf&quot; target=&quot;_blank&quot;&gt;Redis 官方配置示例：redis.conf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/&quot; target=&quot;_blank&quot;&gt;Spring Boot 官方文档：Common Application Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/redis/reference/redis/connection-modes.html&quot; target=&quot;_blank&quot;&gt;Spring Data Redis 官方文档：Connection Modes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis 持久化：RDB、AOF 与混合持久化</title><link>https://aronblake.cloud/posts/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96-rdb%E4%B8%8Eaof-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96-rdb%E4%B8%8Eaof-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</guid><description>Redis 持久化：RDB、AOF 与混合持久化</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;适用范围：Redis Open Source 7.x/8.x。旧版本的 AOF 文件结构与 Redis 7+ 存在明显差异。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. 先理解持久化要解决什么&lt;a href=&quot;#1-先理解持久化要解决什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis 的主要数据在内存中。持久化用于把可恢复的数据写入磁盘，以便进程重启、机器故障或数据迁移后恢复。&lt;/p&gt;&lt;p&gt;设计持久化方案前先明确两个指标：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RPO（Recovery Point Objective）&lt;/strong&gt;：最多允许丢失多长时间的数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RTO（Recovery Time Objective）&lt;/strong&gt;：故障后允许多长时间恢复服务。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Redis 提供四种常见选择：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;不持久化：适合可完全重建的纯缓存。&lt;/li&gt;
&lt;li&gt;只使用 RDB：周期性保存数据快照。&lt;/li&gt;
&lt;li&gt;只使用 AOF：持续记录写命令。&lt;/li&gt;
&lt;li&gt;同时使用 RDB 与 AOF：兼顾备份、恢复速度和较小的数据丢失窗口。&lt;/li&gt;
&lt;/ol&gt;&lt;blockquote&gt;&lt;p&gt;持久化不等于备份，也不等于高可用。误执行 &lt;code&gt;FLUSHALL&lt;/code&gt;、磁盘损坏或整机丢失都可能同时影响在线数据和本地持久化文件，因此仍需要异机备份、复制、哨兵或集群以及恢复演练。&lt;/p&gt;&lt;/blockquote&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. RDB：某一时刻的数据集快照&lt;a href=&quot;#2-rdb某一时刻的数据集快照&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;RDB 把当前内存数据保存为紧凑的二进制快照，默认文件名通常为 &lt;code&gt;dump.rdb&lt;/code&gt;。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;2.1 执行方式&lt;a href=&quot;#21-执行方式&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;SAVE&lt;a href=&quot;#save&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SAVE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;由 Redis 主线程同步执行。&lt;/li&gt;
&lt;li&gt;生成快照期间会阻塞其他请求。&lt;/li&gt;
&lt;li&gt;在线生产实例通常不应主动使用。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;BGSAVE&lt;a href=&quot;#bgsave&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BGSAVE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Redis 先 &lt;code&gt;fork&lt;/code&gt; 子进程。&lt;/li&gt;
&lt;li&gt;子进程在后台生成 RDB。&lt;/li&gt;
&lt;li&gt;父进程继续处理客户端请求。&lt;/li&gt;
&lt;li&gt;新快照完成后通过原子替换取代旧 RDB 文件。&lt;/li&gt;
&lt;/ul&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;执行进程&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;SAVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Redis 主线程&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;BGSAVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;fork&lt;/code&gt; 出的子进程&lt;/td&gt;&lt;td&gt;&lt;code&gt;fork&lt;/code&gt; 阶段可能短暂停顿，写文件期间不持续阻塞&lt;/td&gt;&lt;td&gt;生产环境生成 RDB 的常用方式&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;自动快照规则&lt;a href=&quot;#自动快照规则&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 示例：60 秒内至少发生 1000 次数据变更，则触发后台快照&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;save 60 1000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 禁用自动快照&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;save &quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;save N M&lt;/code&gt; 表示：在 N 秒内至少发生 M 次会改变数据集的操作后，触发一次后台保存。&lt;/p&gt;&lt;p&gt;不要依赖“Redis 正常停机一定会保存 RDB”这一假设。停机参数、当前持久化配置和进程退出方式都会影响结果，恢复能力必须通过实际配置和演练验证。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.2 核心配置&lt;a href=&quot;#22-核心配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# RDB 所在目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dir /var/lib/redis&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# RDB 文件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dbfilename dump.rdb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 是否压缩 RDB&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rdbcompression yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 是否写入并检查校验和&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rdbchecksum yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 最近一次后台保存失败后是否拒绝继续写入&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;stop-writes-on-bgsave-error yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不应简单地认为“磁盘便宜，所以一定关闭压缩”。是否压缩需要结合 CPU、磁盘吞吐、快照耗时和文件大小进行压测。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.3 BGSAVE 与 Copy-on-Write&lt;a href=&quot;#23-bgsave-与-copy-on-write&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;执行 &lt;code&gt;BGSAVE&lt;/code&gt; 时：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;父进程执行 &lt;code&gt;fork&lt;/code&gt;，创建子进程。&lt;/li&gt;
&lt;li&gt;父子进程最初共享相同的物理内存页。&lt;/li&gt;
&lt;li&gt;子进程读取快照时刻的数据并写入临时 RDB。&lt;/li&gt;
&lt;li&gt;父进程继续处理请求。&lt;/li&gt;
&lt;li&gt;父进程修改某个共享页时，操作系统复制该页，这就是 Copy-on-Write。&lt;/li&gt;
&lt;li&gt;子进程完成写入后，Redis 原子替换旧 RDB。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;需要注意的开销：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;大数据集会增加 &lt;code&gt;fork&lt;/code&gt; 和页表复制时间，造成短暂停顿。&lt;/li&gt;
&lt;li&gt;快照期间写入越多，COW 复制的内存页越多，峰值内存越高。&lt;/li&gt;
&lt;li&gt;快照写盘可能与业务 I/O、AOF 重写或主从全量同步争抢资源。&lt;/li&gt;
&lt;li&gt;内存不足时可能发生 OOM，不能只按 &lt;code&gt;used_memory&lt;/code&gt; 配置机器容量。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.4 RDB 的优缺点&lt;a href=&quot;#24-rdb-的优缺点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;优点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;文件紧凑，适合归档和异地备份。&lt;/li&gt;
&lt;li&gt;大数据集下，启动恢复通常快于回放 AOF。&lt;/li&gt;
&lt;li&gt;生成完成的 RDB 文件不会被继续修改，便于复制。&lt;/li&gt;
&lt;li&gt;对正常请求的持续写盘影响较小。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;缺点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;RPO 取决于快照间隔，故障时可能丢失最近数分钟数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fork&lt;/code&gt;、COW 和磁盘写入可能造成延迟和内存放大。&lt;/li&gt;
&lt;li&gt;快照只能表示某个时间点，不能反映之后的增量写入。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. AOF：记录写命令并在启动时回放&lt;a href=&quot;#3-aof记录写命令并在启动时回放&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;AOF（Append Only File）记录所有会改变数据集的写命令。Redis 重启时按顺序回放这些命令，重新构造内存状态。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;3.1 写入路径&lt;a href=&quot;#31-写入路径&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一次写命令大致经过：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端写命令&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Redis 执行命令并修改内存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;AOF 缓冲区&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓ write&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;操作系统页缓存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓ fsync&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;稳定存储&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;write&lt;/code&gt; 成功不代表数据已经进入稳定存储；真正的耐久性主要由 &lt;code&gt;fsync&lt;/code&gt; 策略决定。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 基础配置&lt;a href=&quot;#32-基础配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfilename &quot;appendonly.aof&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# Redis 7+ 的多文件 AOF 目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appenddirname &quot;appendonlydir&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# AOF 重写时允许 base 文件采用 RDB 前导&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;aof-use-rdb-preamble yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 appendfsync 三种策略&lt;a href=&quot;#33-appendfsync-三种策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 每批写命令都执行 fsync&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync always&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 大约每秒执行一次 fsync，常用且推荐的折中方案&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 不主动执行 fsync，由操作系统决定刷盘时间&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync no&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;th&gt;性能与适用场景&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;always&lt;/code&gt;&lt;/td&gt;&lt;td&gt;每批写命令执行 &lt;code&gt;fsync&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;everysec&lt;/code&gt;&lt;/td&gt;&lt;td&gt;后台线程约每秒 &lt;code&gt;fsync&lt;/code&gt;&lt;/td&gt;&lt;td&gt;通常约 1 秒&lt;/td&gt;&lt;td&gt;性能与安全性的常用平衡&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;no&lt;/code&gt;&lt;/td&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;code&gt;always&lt;/code&gt; 完全不丢数据”也不是绝对保证。磁盘控制器缓存、虚拟化存储、文件系统和硬件故障仍可能影响最终耐久性。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.4 AOF 重写&lt;a href=&quot;#34-aof-重写&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;AOF 会不断增长。例如某个计数器执行 100 次 &lt;code&gt;INCR&lt;/code&gt;，恢复当前状态可能并不需要保留全部 100 条历史命令。&lt;/p&gt;&lt;p&gt;手工重写：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BGREWRITEAOF&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;自动重写阈值：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 当前 AOF 相比上次重写后的基准大小增长 100%&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;auto-aof-rewrite-percentage 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 文件达到该大小后才考虑自动重写&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;auto-aof-rewrite-min-size 64mb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;重写不是在原 AOF 上删除命令，而是根据当前内存状态生成一套能够恢复相同数据集的最小表示。新文件准备完成前，旧 AOF 仍保持有效。&lt;/p&gt;&lt;p&gt;例如，原 AOF 中依次存在：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET num 123&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET name jack&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET num 666&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;最终有效状态只有 &lt;code&gt;name=jack&lt;/code&gt;、&lt;code&gt;num=666&lt;/code&gt;。重写后可以用更短的等价命令表示：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;MSET name jack num 666&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;SET num 123&lt;/code&gt;&lt;/td&gt;&lt;td&gt;后续被 &lt;code&gt;SET num 666&lt;/code&gt; 覆盖&lt;/td&gt;&lt;td&gt;不需要&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SET name jack&lt;/code&gt;&lt;/td&gt;&lt;td&gt;决定最终的 &lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;需要以等价形式保留&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SET num 666&lt;/code&gt;&lt;/td&gt;&lt;td&gt;决定最终的 &lt;code&gt;num&lt;/code&gt;&lt;/td&gt;&lt;td&gt;需要以等价形式保留&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Redis 会避免同时执行高开销的 RDB 后台保存和 AOF 重写。若 &lt;code&gt;BGSAVE&lt;/code&gt; 正在执行，&lt;code&gt;BGREWRITEAOF&lt;/code&gt; 可能进入排队状态。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.5 Redis 7+ 的多文件 AOF&lt;a href=&quot;#35-redis-7-的多文件-aof&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 7.0 起，AOF 不再只是一个不断追加的单文件，而是由以下部分组成：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;base AOF&lt;/strong&gt;：最多一个，表示最近一次重写时的数据基线；可以是 AOF 格式，也可以是 RDB 格式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;incremental AOF&lt;/strong&gt;：一个或多个，记录 base 生成之后的增量写入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;manifest&lt;/strong&gt;：记录当前有效的 base 和 incremental 文件组合。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这些文件存放在 &lt;code&gt;appenddirname&lt;/code&gt; 指定的目录中。重写时，父进程会继续向新的增量文件写入；重写完成后通过原子替换 manifest 切换到新文件集合。&lt;/p&gt;&lt;p&gt;因此，Redis 7+ 备份 AOF 时不能只复制某一个 &lt;code&gt;appendonly.aof&lt;/code&gt; 文件，而要复制整个 AOF 目录，并避免在重写过程中取得不一致的文件组合。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.6 AOF 的优缺点&lt;a href=&quot;#36-aof-的优缺点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;优点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;everysec&lt;/code&gt; 时，通常最多丢失约 1 秒数据。&lt;/li&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;文件通常比等价 RDB 更大。&lt;/li&gt;
&lt;li&gt;持续写入和 &lt;code&gt;fsync&lt;/code&gt; 会增加磁盘压力。&lt;/li&gt;
&lt;li&gt;重写仍需要 &lt;code&gt;fork&lt;/code&gt;，存在 COW 和额外 I/O 开销。&lt;/li&gt;
&lt;li&gt;大 AOF 启动时需要回放，恢复速度通常慢于 RDB。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 混合持久化与恢复优先级&lt;a href=&quot;#4-混合持久化与恢复优先级&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;4.1 同时开启 RDB 和 AOF&lt;a href=&quot;#41-同时开启-rdb-和-aof&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;同时开启两种持久化时：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;RDB 可用于周期性快照、归档和较快恢复。&lt;/li&gt;
&lt;li&gt;AOF 用于缩小故障时的数据丢失窗口。&lt;/li&gt;
&lt;li&gt;Redis 重启时会优先使用 AOF 恢复数据，因为 AOF 通常更完整。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 AOF 的 RDB 前导&lt;a href=&quot;#42-aof-的-rdb-前导&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;aof-use-rdb-preamble yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;开启后，AOF 重写生成的 base 部分可使用 RDB 格式，后续增量仍以 AOF 命令日志记录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;RDB 格式的 base + incremental AOF + manifest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;收益：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;base 更紧凑。&lt;/li&gt;
&lt;li&gt;重写速度和启动加载速度通常更好。&lt;/li&gt;
&lt;li&gt;增量 AOF 继续提供较小的数据丢失窗口。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;需要区分：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RDB + AOF&lt;/strong&gt;：同时开启两套持久化机制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RDB 前导 AOF&lt;/strong&gt;：AOF 重写后的 base 使用 RDB 格式，是 AOF 的内部文件结构。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. RDB 与 AOF 对比&lt;a href=&quot;#5-rdb-与-aof-对比&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;

















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;RDB&lt;/th&gt;&lt;th&gt;AOF&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;典型 RPO&lt;/td&gt;&lt;td&gt;取决于快照间隔，通常为分钟级&lt;/td&gt;&lt;td&gt;&lt;code&gt;everysec&lt;/code&gt; 通常约 1 秒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;启动恢复&lt;/td&gt;&lt;td&gt;通常更快&lt;/td&gt;&lt;td&gt;需要加载 base 并回放增量日志&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;周期性 &lt;code&gt;fork&lt;/code&gt; 和集中写盘&lt;/td&gt;&lt;td&gt;持续追加、&lt;code&gt;fsync&lt;/code&gt; 和周期重写&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;主要风险&lt;/td&gt;&lt;td&gt;快照间隔丢数据、fork/COW 峰值&lt;/td&gt;&lt;td&gt;磁盘延迟、文件膨胀、重写和回放时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;备份方式&lt;/td&gt;&lt;td&gt;复制完整 RDB 文件&lt;/td&gt;&lt;td&gt;Redis 7+ 复制整个 &lt;code&gt;appenddirname&lt;/code&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;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 生产环境选型建议&lt;a href=&quot;#6-生产环境选型建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;6.1 纯缓存，可从数据库重建&lt;a href=&quot;#61-纯缓存可从数据库重建&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;可以关闭持久化，降低 I/O 和 &lt;code&gt;fork&lt;/code&gt; 影响。&lt;/li&gt;
&lt;li&gt;若希望重启后快速预热，可保留低频 RDB。&lt;/li&gt;
&lt;li&gt;必须确认缓存重建不会压垮下游数据库。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 可以容忍数分钟数据丢失&lt;a href=&quot;#62-可以容忍数分钟数据丢失&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;可只使用 RDB。&lt;/li&gt;
&lt;li&gt;设置与业务 RPO 对齐的快照规则。&lt;/li&gt;
&lt;li&gt;定期把 RDB 复制到异机或对象存储。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 数据较重要，希望最多丢失约 1 秒&lt;a href=&quot;#63-数据较重要希望最多丢失约-1-秒&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;开启 AOF。&lt;/li&gt;
&lt;li&gt;通常选择 &lt;code&gt;appendfsync everysec&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;保留周期性 RDB，便于归档、恢复和应对 AOF 故障。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.4 极强耐久性要求&lt;a href=&quot;#64-极强耐久性要求&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;可以评估 &lt;code&gt;appendfsync always&lt;/code&gt;，但必须压测写延迟和吞吐。&lt;/li&gt;
&lt;li&gt;结合主从复制、高可用、可靠存储和异地备份。&lt;/li&gt;
&lt;li&gt;如果业务要求严格事务耐久性，需要评估 Redis 是否适合作为唯一事实数据源。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 监控与故障处理&lt;a href=&quot;#7-监控与故障处理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;7.1 查看持久化状态&lt;a href=&quot;#71-查看持久化状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;persistence&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;重点关注：&lt;/p&gt;&lt;p&gt;RDB：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rdb_bgsave_in_progress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rdb_last_bgsave_status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rdb_last_bgsave_time_sec&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rdb_last_cow_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rdb_changes_since_last_save&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;AOF：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aof_enabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_rewrite_in_progress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_rewrite_scheduled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_last_bgrewrite_status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_last_write_status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_current_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_base_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_pending_bio_fsync&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_delayed_fsync&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_last_cow_size&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;还应同时监控：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;latest_fork_usec&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;磁盘使用率、写延迟、I/O 等待&lt;/li&gt;
&lt;li&gt;Redis 主进程 RSS 与可用内存&lt;/li&gt;
&lt;li&gt;持久化文件更新时间&lt;/li&gt;
&lt;li&gt;备份任务成功率和恢复演练结果&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.2 AOF 尾部截断或损坏&lt;a href=&quot;#72-aof-尾部截断或损坏&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;处理原则：&lt;strong&gt;先停止写入并复制原文件，再尝试修复。&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 先检查&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-check-aof&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;aof-file-or-manifest&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 确认可接受丢弃损坏部分后再修复&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-check-aof&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--fix&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;aof-file-or-manifest&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果是中间区域损坏，修复工具可能丢弃损坏位置之后的内容，因此不能不做备份就直接使用 &lt;code&gt;--fix&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;RDB 可使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-check-rdb&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dump.rdb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.3 在线开启 AOF&lt;a href=&quot;#73-在线开启-aof&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在已有 RDB 数据的运行实例上切换为 AOF 时，不要只修改配置文件后直接重启。可按以下思路操作：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CONFIG&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SET&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;appendonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;persistence&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CONFIG&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;REWRITE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;等待 AOF 重写完成，并确认：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aof_rewrite_in_progress:0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_rewrite_scheduled:0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aof_last_bgrewrite_status:ok&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;AOF 持续增长且重启后 key 数量符合预期&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;code&gt;CONFIG SET&lt;/code&gt; 只修改运行时配置；若不修改配置文件或执行 &lt;code&gt;CONFIG REWRITE&lt;/code&gt;，重启后可能恢复旧配置。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Persistence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bgrewriteaof/&quot; target=&quot;_blank&quot;&gt;Redis 官方：BGREWRITEAOF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/info/&quot; target=&quot;_blank&quot;&gt;Redis 官方：INFO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/config/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis 主从复制与持久化</title><link>https://aronblake.cloud/posts/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6-%E8%A1%A5%E5%85%85%E6%95%B4%E7%90%86/</guid><description>Redis 主从复制与持久化</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;适用范围：Redis Open Source 7.x/8.x。文中优先使用 &lt;code&gt;master&lt;/code&gt;（主节点）和 &lt;code&gt;replica&lt;/code&gt;（副本节点）；部分配置项与 &lt;code&gt;INFO&lt;/code&gt; 字段为了兼容旧版本，仍保留 &lt;code&gt;slave&lt;/code&gt; 字样。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. 主从复制解决什么问题&lt;a href=&quot;#1-主从复制解决什么问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis 主从复制让一个或多个 replica 持续复制 master 的数据，主要用于：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;扩展读取能力，实现读写分离。&lt;/li&gt;
&lt;li&gt;保留数据的冗余副本。&lt;/li&gt;
&lt;li&gt;为 Sentinel 或 Redis Cluster 的故障转移提供可提升的节点。&lt;/li&gt;
&lt;li&gt;支持滚动升级、数据迁移和只读分析。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;典型结构：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;写请求&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端 ───────→ Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;异步复制命令流&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌────┴────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓         ↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Replica 1  Replica 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↑         ↑&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;读请求      读请求&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;需要明确：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Redis 默认使用&lt;strong&gt;异步复制&lt;/strong&gt;。&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;/ul&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;/td&gt;&lt;td&gt;在线冗余、读扩展、故障转移的数据来源&lt;/td&gt;&lt;td&gt;不保证零数据丢失，不是历史备份&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RDB/AOF&lt;/td&gt;&lt;td&gt;单节点重启后的本地数据恢复&lt;/td&gt;&lt;td&gt;不自动完成故障转移&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentinel&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;不提供实时读扩展&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 基础搭建与配置&lt;a href=&quot;#2-基础搭建与配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;2.1 把节点配置为 replica&lt;a href=&quot;#21-把节点配置为-replica&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;配置文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replicaof 192.168.10.10 6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;运行时命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;REPLICAOF&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.10.10&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;取消复制关系并把当前节点提升为独立 master：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;REPLICAOF&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ONE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.2 认证配置&lt;a href=&quot;#22-认证配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果 master 需要认证，replica 必须配置连接 master 所需的凭证：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;masterauth your-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 ACL 时，还需要为复制连接配置具有相应权限的用户。生产环境应同时保护 master 和 replica，避免 replica 成为绕过认证的数据入口。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.3 replica 的读写行为&lt;a href=&quot;#23-replica-的读写行为&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 默认开启，只允许客户端读取 replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-read-only yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 与 master 断开或正在同步时，是否允许返回可能过期的数据&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-serve-stale-data yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;即使把 &lt;code&gt;replica-read-only&lt;/code&gt; 改为 &lt;code&gt;no&lt;/code&gt;，也不代表 Redis 变成多主系统：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 上的本地写入不会反向复制给 master。&lt;/li&gt;
&lt;li&gt;重新同步时，本地写入可能被 master 的数据覆盖。&lt;/li&gt;
&lt;li&gt;普通主从架构应坚持所有业务写入只进入当前 master。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 正常复制链路&lt;a href=&quot;#3-正常复制链路&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;master 与 replica 已完成同步且连接正常时，流程如下：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;客户端向 master 发出写命令。&lt;/li&gt;
&lt;li&gt;master 修改自己的内存数据。&lt;/li&gt;
&lt;li&gt;master 把产生相同数据效果的命令写入复制流。&lt;/li&gt;
&lt;li&gt;replica 接收并执行复制流中的命令。&lt;/li&gt;
&lt;li&gt;replica 周期性向 master 上报自己已经处理到的复制偏移量。&lt;/li&gt;
&lt;/ol&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;&lt;p&gt;master 可以同时连接多个 replica。replica 也可以作为其他 replica 的上游，形成级联复制：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├── Replica A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│       ├── Sub-replica A1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│       └── Sub-replica A2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── Replica B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;级联复制可以减少 master 直接服务大量副本的压力，但会增加复制延迟、拓扑复杂度和故障排查成本。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 复制的三个核心标识&lt;a href=&quot;#4-复制的三个核心标识&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;4.1 Replication ID&lt;a href=&quot;#41-replication-id&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Replication ID（复制 ID，通常称 &lt;code&gt;replid&lt;/code&gt;）标识一段特定的数据历史。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;master 拥有自己的复制 ID。&lt;/li&gt;
&lt;li&gt;replica 同步后会记住 master 的复制 ID。&lt;/li&gt;
&lt;li&gt;复制 ID 与 offset 组合起来，才能唯一描述某个数据历史中的位置。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Redis 还维护第二复制 ID：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;master_replid&lt;/code&gt;：当前复制历史。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_replid2&lt;/code&gt;：上一段复制历史。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;second_repl_offset&lt;/code&gt;：旧历史可以继续部分同步的边界。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;第二复制 ID 主要用于故障转移后，让原 master 的其他 replica 仍有机会与新 master 进行部分同步。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 Replication Offset&lt;a href=&quot;#42-replication-offset&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;复制偏移量表示复制流已经生成或处理到的位置。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;master 的 offset 随复制流增加。&lt;/li&gt;
&lt;li&gt;replica 保存自己已处理的 offset。&lt;/li&gt;
&lt;li&gt;两者差值可以近似反映副本落后程度。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不能只比较 offset 而忽略复制 ID。不同复制历史中的相同 offset 没有可比性。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.3 Replication Backlog&lt;a href=&quot;#43-replication-backlog&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Replication backlog 是 master 内存中的&lt;strong&gt;固定容量环形缓冲区&lt;/strong&gt;，保存最近一段复制命令流。&lt;/p&gt;&lt;p&gt;它不是磁盘文件，正确配置名为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-backlog-size 256mb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;环形结构的特点：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;新复制数据持续写入 backlog。&lt;/li&gt;
&lt;li&gt;缓冲区写满后，从头覆盖最旧的数据。&lt;/li&gt;
&lt;li&gt;replica 短暂断线后，可以根据 offset 获取缺失部分。&lt;/li&gt;
&lt;li&gt;如果需要的旧数据已被覆盖，就不能部分同步，只能全量同步。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;文字示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;backlog 保存的 offset 范围：10001 ～ 20000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;master 当前 offset：       20000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica 已处理 offset：    17500&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;结果：17501 ～ 20000 仍在 backlog 中，可以部分同步。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果 replica 的 offset 是 &lt;code&gt;8000&lt;/code&gt;，而 backlog 最早只保留到 &lt;code&gt;10001&lt;/code&gt;，则缺失的 &lt;code&gt;8001～10000&lt;/code&gt; 已经被覆盖，只能全量同步。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. PSYNC：决定部分同步还是全量同步&lt;a href=&quot;#5-psync决定部分同步还是全量同步&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;新版本 Redis 使用 &lt;code&gt;PSYNC&lt;/code&gt; 协议进行复制协商。&lt;code&gt;SYNC&lt;/code&gt; 是不支持部分同步的旧协议，只为兼容保留。&lt;/p&gt;&lt;p&gt;replica 建立连接时，会向 master 提供自己记住的复制 ID 和 offset。master 根据以下条件判断：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;复制 ID 是否属于当前或仍可识别的旧历史？&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌─────────┴─────────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│是                 │否&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓                   ↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;缺失 offset 是否仍在 backlog？  全量同步&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;┌─────┴─────┐&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│是         │否&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓           ↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;部分同步       全量同步&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&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;复制 ID 可识别，缺失数据仍在 backlog&lt;/td&gt;&lt;td&gt;部分同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;第一次连接，没有有效复制 ID 和 offset&lt;/td&gt;&lt;td&gt;全量同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;复制 ID 不属于当前或可兼容历史&lt;/td&gt;&lt;td&gt;全量同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;replica 断开太久，需要的 offset 已被覆盖&lt;/td&gt;&lt;td&gt;全量同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;master 的历史发生无法兼容的变化&lt;/td&gt;&lt;td&gt;全量同步&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 全量同步流程&lt;a href=&quot;#6-全量同步流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;全量同步适用于首次连接或无法部分同步的情况。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;6.1 磁盘式全量同步&lt;a href=&quot;#61-磁盘式全量同步&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;完整时序：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;replica 发送 &lt;code&gt;PSYNC&lt;/code&gt;，请求继续原来的复制历史。&lt;/li&gt;
&lt;li&gt;master 判断不能部分同步，回复进行全量同步。&lt;/li&gt;
&lt;li&gt;master 启动后台保存，生成代表当前数据集的 RDB。&lt;/li&gt;
&lt;li&gt;生成 RDB 的同时，master 把新的写命令放入复制缓冲区。&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 期间积累的命令继续发送给 replica。&lt;/li&gt;
&lt;li&gt;replica 执行这些命令，追赶到 master 当前 offset。&lt;/li&gt;
&lt;li&gt;后续进入持续命令流复制。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Master                                   Replica&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│                                         │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ ←──── PSYNC replid offset ───────────── │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│                                         │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ ───── FULLRESYNC new-replid offset ───→ │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│                                         │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 生成 RDB，同时缓存新写入                 │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ ─────────── RDB 数据流 ───────────────→ │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│                                         │ 清空旧数据并加载 RDB&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ ───── RDB 期间积累的命令流 ───────────→ │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ ───────── 持续复制命令流 ─────────────→ │&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 无盘复制&lt;a href=&quot;#62-无盘复制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 等待一小段时间，让多个同时到来的 replica 共用一次同步&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync-delay 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;无盘复制时，master 的子进程直接通过网络套接字把 RDB 数据流发送给 replica，而不先在 master 磁盘生成 RDB 文件。&lt;/p&gt;&lt;p&gt;优点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;避免 master 上的 RDB 磁盘写入。&lt;/li&gt;
&lt;li&gt;适合磁盘较慢而网络较快的环境。&lt;/li&gt;
&lt;li&gt;多个同时请求同步的 replica 可以共享一次 RDB 生成过程。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;代价：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;仍然需要 &lt;code&gt;fork&lt;/code&gt;，仍存在 COW 内存开销。&lt;/li&gt;
&lt;li&gt;会占用大量网络带宽。&lt;/li&gt;
&lt;li&gt;网络慢或 replica 多时，子进程存活时间可能更长。&lt;/li&gt;
&lt;li&gt;需要结合 &lt;code&gt;repl-diskless-load&lt;/code&gt; 等配置评估 replica 的加载策略。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 全量同步的主要成本&lt;a href=&quot;#63-全量同步的主要成本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;


































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;阶段&lt;/th&gt;&lt;th&gt;master 成本&lt;/th&gt;&lt;th&gt;replica 成本&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;fork&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;RDB 生成&lt;/td&gt;&lt;td&gt;CPU、COW 内存、磁盘或网络&lt;/td&gt;&lt;td&gt;接收数据&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RDB 传输&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;清空旧数据、加载 RDB，可能暂停服务&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;追赶增量&lt;/td&gt;&lt;td&gt;发送积累命令&lt;/td&gt;&lt;td&gt;执行大量命令、增加 CPU&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;因此应尽量避免多个大 replica 频繁触发全量同步。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 部分同步流程&lt;a href=&quot;#7-部分同步流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;部分同步用于 replica 短暂断线且缺失命令仍在 backlog 中的情况。&lt;/p&gt;&lt;p&gt;流程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;replica 重连并提交复制 ID 与上次处理的 offset。&lt;/li&gt;
&lt;li&gt;master 确认复制历史兼容。&lt;/li&gt;
&lt;li&gt;master 确认缺失部分仍在 backlog。&lt;/li&gt;
&lt;li&gt;master 从 &lt;code&gt;offset+1&lt;/code&gt; 开始发送缺失命令。&lt;/li&gt;
&lt;li&gt;replica 执行缺失命令并追赶 master。&lt;/li&gt;
&lt;li&gt;双方恢复持续复制。&lt;/li&gt;
&lt;/ol&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;/td&gt;&lt;td&gt;完整 RDB + 同步期间增量命令&lt;/td&gt;&lt;td&gt;backlog 中缺失的命令&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;master 开销&lt;/td&gt;&lt;td&gt;通常需要 &lt;code&gt;fork&lt;/code&gt; 和生成 RDB&lt;/td&gt;&lt;td&gt;读取内存 backlog&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;replica 行为&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;短暂断线且历史仍保留&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 如何设置 repl-backlog-size&lt;a href=&quot;#8-如何设置-repl-backlog-size&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;backlog 太小会让短暂网络故障频繁退化成全量同步；太大则持续占用 master 内存。&lt;/p&gt;&lt;p&gt;可按下面的思路估算：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;backlog 大小&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;≈ 峰值复制流量（字节/秒）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;× 希望容忍的最长断线时间（秒）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;× 安全系数&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;峰值写入复制流量：20 MB/s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;希望容忍断线：    5 分钟 = 300 秒&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;安全系数：        1.5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;建议 backlog ≈ 20 × 300 × 1.5 = 9000 MB&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;实际设置前还要考虑：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Redis 命令编码后的复制流量可能与业务数据量不同。&lt;/li&gt;
&lt;li&gt;过期、淘汰、批量命令也会进入复制流。&lt;/li&gt;
&lt;li&gt;网络抖动时间不一定等于故障修复时间。&lt;/li&gt;
&lt;li&gt;backlog 由同一 master 的 replica 共享，不需要按 replica 数量简单相乘。&lt;/li&gt;
&lt;li&gt;必须确认机器有足够内存。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;配置与观察：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-backlog-size 1gb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-backlog-ttl 3600&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;replication&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;关注：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_first_byte_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_histlen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_repl_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;replica 的复制 offset&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 主从复制与 RDB/AOF 的关系&lt;a href=&quot;#9-主从复制与-rdbaof-的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;9.1 全量同步会使用 RDB&lt;a href=&quot;#91-全量同步会使用-rdb&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;即使业务持久化配置中关闭了周期性 RDB，传统磁盘式全量复制仍可能生成 RDB 文件。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;磁盘式复制：master 后台生成 RDB，再发送给 replica。&lt;/li&gt;
&lt;li&gt;无盘复制：生成 RDB 格式的数据流并直接发送，不在 master 磁盘保留该文件。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;所以“关闭 RDB 持久化”不等于“主从复制永远不会产生 RDB 相关开销”。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.2 复制不能替代持久化&lt;a href=&quot;#92-复制不能替代持久化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;复制的目标是让 replica 尽量成为 master 的当前副本。如果 master 变成空数据集，空数据也可能被复制出去。&lt;/p&gt;&lt;p&gt;危险场景：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;master 关闭 RDB 和 AOF。&lt;/li&gt;
&lt;li&gt;master 进程崩溃后被进程管理器自动重启。&lt;/li&gt;
&lt;li&gt;因为没有持久化，master 以空数据集启动。&lt;/li&gt;
&lt;li&gt;replica 重新连接并把空 master 当作正确数据源。&lt;/li&gt;
&lt;li&gt;replica 的原有数据被清空，整个复制组的数据一起丢失。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;因此 Redis 官方建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;使用复制时，在 master 和 replica 上开启适合业务的持久化。&lt;/li&gt;
&lt;li&gt;如果 master 确实关闭持久化，不要让它在崩溃后未经人工确认就自动以空数据集重启。&lt;/li&gt;
&lt;li&gt;Sentinel 场景尤其要避免“无持久化 master + 自动重启”的组合。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.3 replica 是否需要持久化&lt;a href=&quot;#93-replica-是否需要持久化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;通常建议 replica 也配置持久化，原因包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 重启后可先从本地恢复，减少完全从 master 获取数据的风险。&lt;/li&gt;
&lt;li&gt;某个 replica 可能在故障转移后成为新 master。&lt;/li&gt;
&lt;li&gt;可把备份、RDB 归档等磁盘任务放到专用 replica，降低 master 压力。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;但要注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 的持久化文件同样会反映复制来的删除和误操作。&lt;/li&gt;
&lt;li&gt;replica 本地持久化仍不是独立、版本化的备份。&lt;/li&gt;
&lt;li&gt;Redis 官方文档指出，replica 平滑停机时写入的 RDB 可以保存部分同步所需元数据；仅通过 AOF 重启的 replica 不能依靠 AOF 完成相同的部分同步恢复。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.4 AOF 与复制流不是同一个概念&lt;a href=&quot;#94-aof-与复制流不是同一个概念&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;AOF&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;/td&gt;&lt;td&gt;通过网络发送给 replica&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;耐久性由 &lt;code&gt;appendfsync&lt;/code&gt; 决定&lt;/td&gt;&lt;td&gt;延迟由网络和 replica 处理速度决定&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;重写用于控制文件体积&lt;/td&gt;&lt;td&gt;backlog 用于短暂断线后的部分同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;本机恢复时加载 AOF&lt;/td&gt;&lt;td&gt;replica 通过 RDB 和复制命令追赶 master&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. 故障转移为什么仍可能丢数据&lt;a href=&quot;#10-故障转移为什么仍可能丢数据&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis 主从复制默认是异步的。下面的写入可能已经被 master 确认，但还没到达 replica：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端 ── SET order:1 paid ──→ Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;客户端 ←──────── OK ───────── Master&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│ 尚未复制完成&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;× Master 故障&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Replica 被提升为新 Master，但没有这条写入&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Sentinel 能自动切换 master，但不能把异步复制变成零丢失复制。&lt;/li&gt;
&lt;li&gt;网络分区时，旧 master 可能仍短暂接受写入。&lt;/li&gt;
&lt;li&gt;故障恢复后，旧 master 会被配置为新 master 的 replica，其分叉数据会被新历史覆盖。&lt;/li&gt;
&lt;li&gt;replica 越落后，故障转移可能丢失的数据越多。&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h3&gt;10.1 使用 min-replicas 限制风险&lt;a href=&quot;#101-使用-min-replicas-限制风险&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-to-write 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-max-lag 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;至少需要 1 个 replica 满足最大延迟要求。&lt;/li&gt;
&lt;li&gt;如果 master 在规定时间内没有收到足够 replica 的进度确认，则停止接受写入。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;作用：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;限制 master 与 replica 长时间失联时继续产生大量孤立写入。&lt;/li&gt;
&lt;li&gt;缩小网络分区期间的数据分叉窗口。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;代价：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;replica 不满足条件时，master 会拒绝写入，可用性下降。&lt;/li&gt;
&lt;li&gt;这仍不是严格同步复制，也不能保证绝对零丢失。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10.2 使用 WAIT 提高关键写入安全性&lt;a href=&quot;#102-使用-wait-提高关键写入安全性&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET order:1 paid&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;WAIT 1 1000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;WAIT 1 1000&lt;/code&gt; 表示最多等待 1000 毫秒，希望至少 1 个 replica 确认已经接收到当前连接此前的写入。&lt;/p&gt;&lt;p&gt;应用必须检查返回值：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;返回 1：至少一个 replica 已确认相应复制位置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;返回 0：超时前没有 replica 满足条件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WAIT&lt;/code&gt; 提高写入已到达 replica 的概率，但不会把 Redis 变成强一致 CP 系统。&lt;/li&gt;
&lt;li&gt;replica 确认复制 offset 不一定等于写入已经按目标策略落到磁盘。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WAIT&lt;/code&gt; 不能替代 AOF、RDB、备份或正确的故障转移设计。&lt;/li&gt;
&lt;li&gt;执行 &lt;code&gt;WAIT&lt;/code&gt; 后若业务从另一个落后 replica 读取，仍可能读到旧值；读路由也必须设计。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;11. 读写分离的一致性问题&lt;a href=&quot;#11-读写分离的一致性问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;读 replica 可以扩展吞吐量，但要接受最终一致性。&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;表现&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;/td&gt;&lt;td&gt;写 master 后立即读 replica，结果尚未同步&lt;/td&gt;&lt;td&gt;关键读回 master；按业务使用 &lt;code&gt;WAIT&lt;/code&gt;；客户端做短期粘滞路由&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;主从切换后的旧连接&lt;/td&gt;&lt;td&gt;客户端仍向旧 master 写入&lt;/td&gt;&lt;td&gt;使用支持 Sentinel/Cluster 的客户端，及时刷新拓扑&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;replica 正在全量加载&lt;/td&gt;&lt;td&gt;暂停响应或返回旧数据&lt;/td&gt;&lt;td&gt;配置并评估 stale-data 行为；健康检查剔除同步中节点&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;复制延迟扩大&lt;/td&gt;&lt;td&gt;replica CPU、网络或磁盘不足&lt;/td&gt;&lt;td&gt;监控 offset 差值、链路状态和处理能力&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;过期时间看似不一致&lt;/td&gt;&lt;td&gt;replica 复制和过期处理存在时序差&lt;/td&gt;&lt;td&gt;以 master 为权威，避免依赖 replica 做强一致判断&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;不适合直接读 replica 的场景：&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;li&gt;支付、订单状态等不能容忍短暂旧值的业务。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;12. 主从复制优化&lt;a href=&quot;#12-主从复制优化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;12.1 控制单节点数据量&lt;a href=&quot;#121-控制单节点数据量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;单节点数据集越大：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;全量同步的 RDB 越大。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fork&lt;/code&gt;、COW、网络传输和加载时间越长。&lt;/li&gt;
&lt;li&gt;replica 追赶期间积累的命令越多。&lt;/li&gt;
&lt;li&gt;故障恢复 RTO 越长。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;应通过合理分片、内存上限和容量规划控制单节点规模。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.2 合理增大 backlog&lt;a href=&quot;#122-合理增大-backlog&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;backlog 应覆盖常见网络抖动和滚动重启时间，避免短暂断线退化为全量同步。&lt;/p&gt;&lt;p&gt;不要盲目设置：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;太小：频繁全量同步。&lt;/li&gt;
&lt;li&gt;太大：浪费 master 内存。&lt;/li&gt;
&lt;li&gt;应基于峰值复制流量和最长断线时间计算。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.3 评估无盘复制&lt;a href=&quot;#123-评估无盘复制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;磁盘慢、网络快时可考虑：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync-delay 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;但仍需压测网络、COW 内存和多个 replica 同步时的表现。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.4 限制直接 replica 数量&lt;a href=&quot;#124-限制直接-replica-数量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;大量 replica 同时直接连接 master 会增加：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;网络输出。&lt;/li&gt;
&lt;li&gt;每个 replica 的客户端输出缓冲区。&lt;/li&gt;
&lt;li&gt;心跳和状态维护。&lt;/li&gt;
&lt;li&gt;故障时的同步风暴。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;可以采用级联复制降低 master 压力，但要评估多一跳延迟和级联上游故障的影响。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12.5 避免同步风暴&lt;a href=&quot;#125-避免同步风暴&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;分批重启 replica。&lt;/li&gt;
&lt;li&gt;配合 &lt;code&gt;repl-diskless-sync-delay&lt;/code&gt; 合并相近的同步请求。&lt;/li&gt;
&lt;li&gt;不让大量 replica 在同一时间失联和重连。&lt;/li&gt;
&lt;li&gt;监控全量同步次数与网络出口带宽。&lt;/li&gt;
&lt;li&gt;Sentinel 中合理配置并行同步数量，避免故障转移后所有 replica 同时加载。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;13. 监控与排障&lt;a href=&quot;#13-监控与排障&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;13.1 查看复制状态&lt;a href=&quot;#131-查看复制状态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;replication&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ROLE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;master 侧重点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;role&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;connected_slaves&lt;/code&gt;：为兼容保留的旧字段名，表示已连接 replica 数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_replid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_replid2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_repl_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;second_repl_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_first_byte_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repl_backlog_histlen&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;replica 侧重点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;master_host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_port&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_link_status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_last_io_seconds_ago&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_sync_in_progress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slave_repl_offset&lt;/code&gt;：兼容旧协议保留的字段名。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slave_read_repl_offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;master_link_down_since_seconds&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;还应结合：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;persistence&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;memory&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis-cli&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LATENCY&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DOCTOR&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;13.2 常见故障判断表&lt;a href=&quot;#132-常见故障判断表&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;master_link_status:down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;网络、认证、TLS、超时或 master 不可达&lt;/td&gt;&lt;td&gt;检查网络、日志、&lt;code&gt;masterauth&lt;/code&gt;、ACL 和 TLS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;频繁全量同步&lt;/td&gt;&lt;td&gt;backlog 太小、断线太久、复制历史变化&lt;/td&gt;&lt;td&gt;查看 backlog 范围和同步日志，调整容量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;replica 长时间追不上&lt;/td&gt;&lt;td&gt;写入过快、CPU 不足、网络慢&lt;/td&gt;&lt;td&gt;比较 offset、CPU、带宽和命令执行速度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;master 内存突增&lt;/td&gt;&lt;td&gt;RDB/COW、输出缓冲区或 backlog 较大&lt;/td&gt;&lt;td&gt;查看 COW、客户端缓冲和 backlog 配置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;master 延迟抖动&lt;/td&gt;&lt;td&gt;&lt;code&gt;fork&lt;/code&gt;、磁盘 I/O、网络发送压力&lt;/td&gt;&lt;td&gt;查看 &lt;code&gt;latest_fork_usec&lt;/code&gt;、延迟监控和磁盘&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;replica 全量同步时不可用&lt;/td&gt;&lt;td&gt;正在清空并加载 RDB&lt;/td&gt;&lt;td&gt;调整健康检查、同步策略和读流量摘除&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;master 重启后所有数据消失&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;异步复制尚未到达被提升 replica&lt;/td&gt;&lt;td&gt;评估 &lt;code&gt;WAIT&lt;/code&gt;、min-replicas、持久化和业务补偿&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;14. 生产配置示例&lt;a href=&quot;#14-生产配置示例&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;以下仅作为思路示例，不能直接替代压测和容量规划。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;Master&lt;a href=&quot;#master&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 持久化&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;save 3600 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 部分同步窗口&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-backlog-size 1gb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-backlog-ttl 3600&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 全量同步&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;repl-diskless-sync-delay 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 限制失去副本后的孤立写入&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-to-write 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;min-replicas-max-lag 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;Replica&lt;a href=&quot;#replica&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replicaof 192.168.10.10 6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;masterauth your-password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-read-only yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;replica-serve-stale-data yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 作为可能被提升的新 master，通常也应具备持久化能力&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendonly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;appendfsync everysec&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;部署时还要补充：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;ACL 或密码配置。&lt;/li&gt;
&lt;li&gt;TLS 复制链路。&lt;/li&gt;
&lt;li&gt;主机地址通告与 NAT 环境配置。&lt;/li&gt;
&lt;li&gt;Sentinel 或 Cluster 故障转移。&lt;/li&gt;
&lt;li&gt;跨可用区延迟与带宽评估。&lt;/li&gt;
&lt;li&gt;备份、告警和恢复演练。&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/replication/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Persistence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/info/&quot; target=&quot;_blank&quot;&gt;Redis 官方：INFO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/wait/&quot; target=&quot;_blank&quot;&gt;Redis 官方：WAIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Sentinel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/admin/&quot; target=&quot;_blank&quot;&gt;Redis 官方：Administration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis BitMap</title><link>https://aronblake.cloud/posts/redis/redis-bitmap%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis-bitmap%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</guid><description>Redis BitMap</description><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;适用范围：Redis Open Source 2.2+。文中会特别标注 Redis 7.0 和 8.2 引入的新语法。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. Bitmap 是什么&lt;a href=&quot;#1-bitmap-是什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Bitmap（位图）使用一个二进制位表示一个对象的某种布尔状态：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;：是、存在、已发生；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;：否、不存在、未发生。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;例如，可以让 offset 等于用户 ID：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;offset:  0 1 2 3 4 5 6 7 ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;状态:    0 1 0 0 1 0 1 0 ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;含义:      ↑     ↑   ↑&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;用户1  用户4 用户6 活跃&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;li&gt;权限或功能开关；&lt;/li&gt;
&lt;li&gt;标签人群交集、并集和差集；&lt;/li&gt;
&lt;li&gt;大量小整数计数器（使用 &lt;code&gt;BITFIELD&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. Bitmap 不是独立数据类型&lt;a href=&quot;#2-bitmap-不是独立数据类型&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Bitmap 底层是二进制安全的 &lt;strong&gt;String&lt;/strong&gt;。Bitmap 只是 Redis 提供的一组按位操作：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT bitmap:key 10 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;TYPE bitmap:key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;所以 Bitmap key 也可以使用部分 String 命令，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;STRLEN bitmap:key       # String 占用的字节数&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GETRANGE bitmap:key 0 9 # 读取前 10 个字节&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;EXPIRE bitmap:key 86400 # 设置整个 Bitmap key 的 TTL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;DEL bitmap:key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;直接 &lt;code&gt;GET&lt;/code&gt; 得到的是二进制字节流，不一定是可读文本。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. bit、byte 与 offset&lt;a href=&quot;#3-bitbyte-与-offset&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;3.1 基本换算&lt;a href=&quot;#31-基本换算&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1 byte = 8 bit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Redis 的 offset 从 &lt;code&gt;0&lt;/code&gt; 开始：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;第 1 个字节保存 offset &lt;code&gt;0～7&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;第 2 个字节保存 offset &lt;code&gt;8～15&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;第 n 个 bit 所在字节是 &lt;code&gt;floor(offset / 8)&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;一个字节内按“从最高有效位到最低有效位”编号：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;字节内容： 1 0 1 0 0 0 0 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;offset：   0 1 2 3 4 5 6 7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT demo 0 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;会把第一个字节的最高位设置为 1，而不是最低位。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 最大容量&lt;a href=&quot;#32-最大容量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;String 的最大长度是 512 MiB，因此单个 Bitmap 最多可以寻址：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;512 MiB × 8 = 2^32 bit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;offset 的有效范围是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;0 ～ 2^32 - 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也就是最多约 42.95 亿个位。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 内存估算&lt;a href=&quot;#33-内存估算&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果最大 offset 为 &lt;code&gt;m&lt;/code&gt;，数据部分至少需要：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;floor(m / 8) + 1 字节&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;位图数据大小（约）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;100 万&lt;/td&gt;&lt;td&gt;122 KiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1,000 万&lt;/td&gt;&lt;td&gt;1.19 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 亿&lt;/td&gt;&lt;td&gt;11.92 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10 亿&lt;/td&gt;&lt;td&gt;119.21 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;2^32&lt;/code&gt; 个 bit&lt;/td&gt;&lt;td&gt;512 MiB&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这些数字不包含 Redis 对象、key、内存分配器等额外开销。&lt;/p&gt;&lt;p&gt;Bitmap 并不是稀疏压缩结构。即使只执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT users 1000000000 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Redis 也必须分配能够覆盖 offset 10 亿的连续 String，约占 119 MiB。对很短的 key 突然设置极远 offset，扩容和补零还可能阻塞 Redis 主线程。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 适合与不适合的场景&lt;a href=&quot;#4-适合与不适合的场景&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;4.1 适合&lt;a href=&quot;#41-适合&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;对象可以映射为较连续、较紧凑的非负整数；&lt;/li&gt;
&lt;li&gt;每个对象只需表示 0/1；&lt;/li&gt;
&lt;li&gt;经常需要计数、交集、并集或差集；&lt;/li&gt;
&lt;li&gt;不要求直接从 Bitmap 中列出完整业务对象。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 不适合&lt;a href=&quot;#42-不适合&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;ID 极度稀疏，例如只有少量用户但 ID 接近十亿；&lt;/li&gt;
&lt;li&gt;需要保存名称、时间、次数等附加信息；&lt;/li&gt;
&lt;li&gt;经常需要遍历并返回所有成员；&lt;/li&gt;
&lt;li&gt;单个对象不只是布尔状态；&lt;/li&gt;
&lt;li&gt;需要给每个 bit 单独设置 TTL。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Bitmap 的 TTL 是 key 级别的，不能给单独一个 bit 设置过期时间。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 命令总览&lt;a href=&quot;#5-命令总览&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;th&gt;时间复杂度&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SETBIT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置指定 offset 的值&lt;/td&gt;&lt;td&gt;2.2+&lt;/td&gt;&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;，扩容除外&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GETBIT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;获取指定 offset 的值&lt;/td&gt;&lt;td&gt;2.2+&lt;/td&gt;&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BITCOUNT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计值为 1 的 bit 数&lt;/td&gt;&lt;td&gt;2.6+&lt;/td&gt;&lt;td&gt;&lt;code&gt;O(N)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BITOP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;多个 String/Bitmap 做位运算并保存结果&lt;/td&gt;&lt;td&gt;2.6+&lt;/td&gt;&lt;td&gt;&lt;code&gt;O(N)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BITPOS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查找第一个 0 或 1 的位置&lt;/td&gt;&lt;td&gt;2.8.7+&lt;/td&gt;&lt;td&gt;&lt;code&gt;O(N)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BITFIELD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;原子读写、自增不同宽度的整数&lt;/td&gt;&lt;td&gt;3.2+&lt;/td&gt;&lt;td&gt;每个子命令 &lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BITFIELD_RO&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只读地获取 bitfield 整数&lt;/td&gt;&lt;td&gt;6.0+&lt;/td&gt;&lt;td&gt;每个子命令 &lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;其中 &lt;code&gt;N&lt;/code&gt; 与扫描或参与运算的字节数有关。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 命令详解&lt;a href=&quot;#6-命令详解&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;6.1 SETBIT：设置 bit&lt;a href=&quot;#61-setbit设置-bit&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT key offset value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;offset&lt;/code&gt; 从 0 开始；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; 只能是 &lt;code&gt;0&lt;/code&gt; 或 &lt;code&gt;1&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;key 不存在时自动创建；&lt;/li&gt;
&lt;li&gt;超出当前长度时自动扩容，中间部分补 0；&lt;/li&gt;
&lt;li&gt;返回 &lt;strong&gt;修改前的 bit 值&lt;/strong&gt;，不是修改后的值。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT active:2026-07-27 1001 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;第一次返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;(integer) 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;重复执行返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;(integer) 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此返回值可以用来判断“这是不是用户当天第一次活跃”，但业务端仍需考虑事件、网络重试和整体流程的幂等性。&lt;/p&gt;&lt;p&gt;清除状态：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT active:2026-07-27 1001 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 GETBIT：读取 bit&lt;a href=&quot;#62-getbit读取-bit&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GETBIT key offset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GETBIT active:2026-07-27 1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回 &lt;code&gt;0&lt;/code&gt; 或 &lt;code&gt;1&lt;/code&gt;。key 不存在或 offset 超过当前 String 长度时返回 &lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 BITCOUNT：统计 1 的数量&lt;a href=&quot;#63-bitcount统计-1-的数量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT key [start end [BYTE | BIT]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;统计整个 Bitmap：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果“一名用户对应一个 offset”，结果就是当天去重活跃用户数。&lt;/p&gt;&lt;p&gt;范围查询默认按 &lt;strong&gt;byte&lt;/strong&gt;，而且 &lt;code&gt;start&lt;/code&gt;、&lt;code&gt;end&lt;/code&gt; 都包含在内：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT key 0 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;表示统计第 1 个字节（offset 0～7），不是只统计 bit 0。&lt;/p&gt;&lt;p&gt;Redis 7.0+ 可以显式按 bit 范围统计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT key 0 0 BIT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这才表示只统计 bit 0。&lt;code&gt;BYTE&lt;/code&gt; 是默认模式。范围索引可以为负数，&lt;code&gt;-1&lt;/code&gt; 表示最后一个 byte 或 bit，取决于指定的模式。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.4 BITOP：位运算&lt;a href=&quot;#64-bitop位运算&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当前语法：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITOP operation destination source [source ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AND&lt;/code&gt;&lt;/td&gt;&lt;td&gt;交集：所有源 Bitmap 都为 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;OR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;并集：至少一个源 Bitmap 为 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;XOR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;异或：常用于两个 Bitmap 状态不同的成员&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;NOT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;取反；只能有一个源 key&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Redis 8.2 新增：&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;DIFF dest X Y...&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在 X 中但不在任何 Y 中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;DIFF1 dest X Y...&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在任一 Y 中但不在 X 中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ANDOR dest X Y...&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在 X 中，并且至少在一个 Y 中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ONE dest X...&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只在一个源 Bitmap 中出现&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例——连续两天都活跃：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITOP AND active:{app}:both \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-26 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:{app}:both&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例——两天内至少活跃一次：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITOP OR active:{app}:union \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-26 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:{app}:union&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Redis 8.2+ 查询“昨天活跃、今天未活跃”：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITOP DIFF active:{app}:lost \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-26 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:{app}:lost&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;需要注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;运算结果总会写入 &lt;code&gt;destination&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;返回值是目标 String 的字节长度，不是 1 的数量；&lt;/li&gt;
&lt;li&gt;要统计结果，继续使用 &lt;code&gt;BITCOUNT destination&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;较短或不存在的源 key 会按 0 补齐到最长源 key 的长度；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BITOP&lt;/code&gt; 是 &lt;code&gt;O(N)&lt;/code&gt;，大 Bitmap 运算可能阻塞；&lt;/li&gt;
&lt;li&gt;Redis 8.2 以前只有 &lt;code&gt;AND&lt;/code&gt;、&lt;code&gt;OR&lt;/code&gt;、&lt;code&gt;XOR&lt;/code&gt;、&lt;code&gt;NOT&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;在 Redis Cluster 中，源 key 和目标 key 应位于同一个 slot。上例通过共同的 hash tag &lt;code&gt;{app}&lt;/code&gt; 达到这一点。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.5 BITPOS：寻找第一个 0 或 1&lt;a href=&quot;#65-bitpos寻找第一个-0-或-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITPOS key bit [start [end [BYTE | BIT]]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITPOS active:2026-07-27 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回第一个值为 1 的绝对 bit offset。&lt;/p&gt;&lt;p&gt;默认情况下，&lt;code&gt;start&lt;/code&gt; 和 &lt;code&gt;end&lt;/code&gt; 是 byte 范围；Redis 7.0+ 可使用 &lt;code&gt;BIT&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITPOS key 0 100 199 BIT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;在 bit 100～199 中寻找第一个 0，但返回值仍是从整个 Bitmap offset 0 开始计算的绝对位置。&lt;/p&gt;&lt;p&gt;特殊返回语义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;查找 1，但 key 为空或全为 0：返回 &lt;code&gt;-1&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;不限定完整范围地查找 0 时，Redis 会把 String 右侧视作有无限个 0，因此全为 1 的三字节 String 会返回 &lt;code&gt;24&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;如果同时明确给出 &lt;code&gt;start&lt;/code&gt; 和 &lt;code&gt;end&lt;/code&gt;，而该范围内没有目标 bit，则返回 &lt;code&gt;-1&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.6 BITFIELD：把位数组当小整数数组&lt;a href=&quot;#66-bitfield把位数组当小整数数组&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[GET encoding offset |&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[OVERFLOW WRAP|SAT|FAIL]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;SET encoding offset value |&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;INCRBY encoding offset increment&amp;gt; ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;BITFIELD&lt;/code&gt; 不只是操作单个 0/1，它可以将一段连续 bit 解释为整数。&lt;/p&gt;&lt;p&gt;编码格式：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uN&lt;/code&gt;：N 位无符号整数，支持到 &lt;code&gt;u63&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iN&lt;/code&gt;：N 位有符号整数，支持到 &lt;code&gt;i64&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;例如 &lt;code&gt;u8&lt;/code&gt; 的范围是 0～255，&lt;code&gt;i8&lt;/code&gt; 的范围是 -128～127。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;三种主要操作：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET&lt;/code&gt;：读取整数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SET&lt;/code&gt;：写入整数，返回旧值；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INCRBY&lt;/code&gt;：原子增减，返回新值。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;普通 offset 表示 bit offset：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD stats SET u8 0 100 SET u8 8 20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;带 &lt;code&gt;#&lt;/code&gt; 的 offset 表示“第几个同宽整数”，Redis 会自动乘以字段宽度：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD stats SET u8 #0 100 SET u8 #1 20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD stats GET u8 #0 GET u8 #1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&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;行为&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;WRAP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;默认，环绕；例如 &lt;code&gt;u8&lt;/code&gt; 的 255 加 1 变为 0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SAT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;饱和，超过范围后停在最大值或最小值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;FAIL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;不修改，并为该子操作返回 &lt;code&gt;nil/null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD counters \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SET u8 #0 254 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;OVERFLOW SAT INCRBY u8 #0 10 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;GET u8 #0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;对应返回值依次是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;255&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;255&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;一条 &lt;code&gt;BITFIELD&lt;/code&gt; 可以包含多个子操作，它们会按顺序原子执行，返回数组与子操作一一对应。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.7 BITFIELD_RO：只读查询&lt;a href=&quot;#67-bitfield_ro只读查询&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD_RO key GET encoding offset [GET encoding offset ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;它只允许 &lt;code&gt;GET&lt;/code&gt;，不能使用 &lt;code&gt;SET&lt;/code&gt;、&lt;code&gt;INCRBY&lt;/code&gt; 或 &lt;code&gt;OVERFLOW&lt;/code&gt;，适合明确的只读访问和只读副本。&lt;/p&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITFIELD_RO stats GET u8 #0 GET u8 #1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 完整案例一：用户签到&lt;a href=&quot;#7-完整案例一用户签到&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;设计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;key    = signin:{userId}:2026-07&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;offset = 当月日期 - 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;value  = 是否签到&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如用户 1001 在 7 月 1、2、5、27 日签到：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT signin:{1001}:2026-07 0 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT signin:{1001}:2026-07 1 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT signin:{1001}:2026-07 4 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT signin:{1001}:2026-07 26 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询 7 月 27 日是否签到：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GETBIT signin:{1001}:2026-07 26&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;统计本月签到天数：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT signin:{1001}:2026-07&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;结果：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;(integer) 4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Bitmap 能高效回答“是否签到”和“签到多少天”，但签到的具体时间、设备、奖励流水仍应保存在数据库、Hash、Stream 等其他结构中。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 完整案例二：活跃用户与留存&lt;a href=&quot;#8-完整案例二活跃用户与留存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;设计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;key    = active:{app}:yyyy-MM-dd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;offset = 紧凑的用户数字 ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;value  = 当天是否活跃&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;记录活跃：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT active:{app}:2026-07-27 1001 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT active:{app}:2026-07-27 1002 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SETBIT active:{app}:2026-07-27 2000 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;日活：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:{app}:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;两日都活跃：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITOP AND active:{app}:retained \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-20 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;active:{app}:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BITCOUNT active:{app}:retained&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果“7 月 20 日活跃用户”正是所定义的初始 cohort，上述交集数可作为 7 日回访人数。留存率应在业务端计算：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;7 日留存率 = 7 月 20 日与 7 月 27 日交集人数 ÷ 7 月 20 日 cohort 人数&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;真实留存通常还要限定“新增用户 cohort”等业务条件，不能把任意两个日活 Bitmap 的交集都直接称为标准留存。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. Bitmap、Set、HyperLogLog、Bloom Filter 的选择&lt;a href=&quot;#9-bitmapsethyperloglogbloom-filter-的选择&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;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;Bitmap&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;很快&lt;/td&gt;&lt;td&gt;不方便&lt;/td&gt;&lt;td&gt;适合紧凑整数 ID 和布尔状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Set&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;支持&lt;/td&gt;&lt;td&gt;支持&lt;/td&gt;&lt;td&gt;适合稀疏 ID，单成员开销较大&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;HyperLogLog&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;近似基数&lt;/td&gt;&lt;td&gt;不直接支持交集&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;固定小内存，适合只求 UV&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bloom Filter&lt;/td&gt;&lt;td&gt;概率判断&lt;/td&gt;&lt;td&gt;不用于精确人数&lt;/td&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;/p&gt;&lt;ul&gt;
&lt;li&gt;ID 连续、需要交并集：Bitmap；&lt;/li&gt;
&lt;li&gt;ID 稀疏、需要列出成员：Set；&lt;/li&gt;
&lt;li&gt;只关心近似 UV：HyperLogLog；&lt;/li&gt;
&lt;li&gt;只需要低内存的“可能存在/一定不存在”判断：Bloom Filter。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. 官方资料&lt;a href=&quot;#10-官方资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/bitmaps/&quot; target=&quot;_blank&quot;&gt;Redis Bitmap 数据类型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/bitfields/&quot; target=&quot;_blank&quot;&gt;Redis Bitfield 数据类型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/setbit/&quot; target=&quot;_blank&quot;&gt;SETBIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/getbit/&quot; target=&quot;_blank&quot;&gt;GETBIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bitcount/&quot; target=&quot;_blank&quot;&gt;BITCOUNT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bitop/&quot; target=&quot;_blank&quot;&gt;BITOP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bitpos/&quot; target=&quot;_blank&quot;&gt;BITPOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bitfield/&quot; target=&quot;_blank&quot;&gt;BITFIELD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/bitfield_ro/&quot; target=&quot;_blank&quot;&gt;BITFIELD_RO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis GEO</title><link>https://aronblake.cloud/posts/redis/redis-geo%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis-geo%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</guid><description>Redis GEO知识整理</description><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;适用范围：Redis Open Source 3.2+；新项目优先采用 Redis 6.2 引入的 &lt;code&gt;GEOSEARCH&lt;/code&gt; 和 &lt;code&gt;GEOSEARCHSTORE&lt;/code&gt;。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. GEO 是什么&lt;a href=&quot;#1-geo-是什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis GEO（Geospatial，地理空间索引）用于保存“成员—经纬度”的对应关系，并完成：&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;li&gt;按圆形半径或矩形范围搜索附近成员；&lt;/li&gt;
&lt;li&gt;按距离排序、限制数量或保存查询结果。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;它适合“附近门店、车辆、骑手、充电桩、车站”等简单邻近搜索。它不是完整的 GIS：不支持道路距离、导航路径、行政区或任意多边形判断。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 底层数据结构与原理&lt;a href=&quot;#2-底层数据结构与原理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;GEO 底层就是一个 &lt;strong&gt;Sorted Set（有序集合）&lt;/strong&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;member&lt;/code&gt; 是成员名，例如 &lt;code&gt;北京站&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;score&lt;/code&gt; 是经纬度经过 Geohash 思路编码得到的 52 位整数；&lt;/li&gt;
&lt;li&gt;经纬度的二进制位交错排列，使空间上相近的点大概率拥有相近的 score；&lt;/li&gt;
&lt;li&gt;范围搜索先按网格/包围盒筛选候选点，再计算实际球面距离并剔除范围外的点。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此可以对 GEO key 使用部分 Sorted Set 命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;TYPE geo:stations                 # zset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ZCARD geo:stations                # 成员数量&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ZREM geo:stations 北京西站        # 删除成员；没有 GEODEL 命令&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不要随意用 &lt;code&gt;ZADD&lt;/code&gt; 修改 GEO 成员的 score，否则会破坏地理编码。需要修改坐标时重新执行 &lt;code&gt;GEOADD&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 坐标规则&lt;a href=&quot;#3-坐标规则&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;GEOADD&lt;/code&gt; 的坐标顺序固定为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;经度 longitude（x）在前，纬度 latitude（y）在后&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;有效范围：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;经度：&lt;code&gt;-180&lt;/code&gt; 到 &lt;code&gt;180&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;纬度：&lt;code&gt;-85.05112878&lt;/code&gt; 到 &lt;code&gt;85.05112878&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;纬度不能到达南北极，因为 Redis 采用的投影/编码范围不覆盖极区。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;国内坐标系注意事项&lt;a href=&quot;#国内坐标系注意事项&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 只存数字，不识别或转换坐标系。WGS‑84、GCJ‑02（高德/腾讯常见）和 BD‑09（百度常见）不可混用，否则会产生数百米甚至更大的偏移。写入、搜索中心和业务展示应统一使用同一种坐标系。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 常用命令总览&lt;a href=&quot;#4-常用命令总览&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;GEOADD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;添加或更新成员坐标&lt;/td&gt;&lt;td&gt;3.2+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEOPOS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;返回成员经纬度&lt;/td&gt;&lt;td&gt;3.2+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEODIST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;计算两个已存在成员的距离&lt;/td&gt;&lt;td&gt;3.2+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEOHASH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;返回成员的标准 Geohash 字符串&lt;/td&gt;&lt;td&gt;3.2+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEOSEARCH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;按圆形或矩形范围搜索&lt;/td&gt;&lt;td&gt;6.2+，推荐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEOSEARCHSTORE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;搜索并把结果保存为新 key&lt;/td&gt;&lt;td&gt;6.2+，推荐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEORADIUS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;以给定坐标为圆心搜索&lt;/td&gt;&lt;td&gt;6.2 起 deprecated&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GEORADIUSBYMEMBER&lt;/code&gt;&lt;/td&gt;&lt;td&gt;以已有成员为圆心搜索&lt;/td&gt;&lt;td&gt;6.2 起 deprecated&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;“Deprecated”表示不建议新代码继续使用，并不等同于 Redis 6.2 立即删除了旧命令。迁移关系是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEORADIUS / GEORADIUSBYMEMBER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOSEARCH（只返回）/ GEOSEARCHSTORE（保存结果）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 命令详解&lt;a href=&quot;#5-命令详解&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;5.1 GEOADD：添加或更新位置&lt;a href=&quot;#51-geoadd添加或更新位置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;默认：不存在则新增，存在则更新坐标；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NX&lt;/code&gt;：只新增，不更新已有成员；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XX&lt;/code&gt;：只更新已有成员，不新增；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CH&lt;/code&gt;：返回新增或坐标发生变化的成员数；不加时只统计新增数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NX&lt;/code&gt; 与 &lt;code&gt;XX&lt;/code&gt; 互斥。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;单次可以批量写入多个成员：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOADD geo:stations \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;116.378248 39.865275 北京南站 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;116.428030 39.903738 北京站 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;116.322287 39.893729 北京西站&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每个元素写入的时间复杂度为 &lt;code&gt;O(log N)&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 GEOPOS：查询坐标&lt;a href=&quot;#52-geopos查询坐标&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOPOS key member [member ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOPOS geo:stations 北京站 北京西站 不存在的站&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回顺序仍是“经度、纬度”；不存在的成员返回 &lt;code&gt;nil/null&lt;/code&gt;。由于坐标会先编码成 52 位值，再解码返回，所以结果可能与写入值存在很小差异。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 GEODIST：计算两个成员的距离&lt;a href=&quot;#53-geodist计算两个成员的距离&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEODIST key member1 member2 [M | KM | FT | MI]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;单位：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M&lt;/code&gt;：米，默认；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;KM&lt;/code&gt;：千米；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MI&lt;/code&gt;：英里；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FT&lt;/code&gt;：英尺。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEODIST geo:stations 北京西站 北京站 KM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;结果约为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;9.0915 km&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果任一成员不存在，返回 &lt;code&gt;nil/null&lt;/code&gt;。&lt;code&gt;GEODIST&lt;/code&gt; 只能接受已经存入同一个 GEO key 的成员，不能直接传两个临时坐标。&lt;/p&gt;&lt;p&gt;Redis 使用 Haversine 公式，并把地球视为球体；极端情况下误差可能达到约 0.5%，因此不适合测绘、计费等高精度场景。这里得到的是球面直线距离，不是驾车或步行路线距离。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.4 GEOHASH：查询 Geohash 字符串&lt;a href=&quot;#54-geohash查询-geohash-字符串&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOHASH key member [member ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回 11 个字符的标准 Geohash。可以从右侧截短以降低精度、扩大表示区域。&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;GEO 内部使用的是 52 位整数变体，&lt;code&gt;GEOHASH&lt;/code&gt; 返回的是便于外部使用的标准字符串。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.5 GEOSEARCH：推荐的范围查询&lt;a href=&quot;#55-geosearch推荐的范围查询&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOSEARCH key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;FROMMEMBER member | FROMLONLAT longitude latitude&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;BYRADIUS radius M|KM|FT|MI | BYBOX width height M|KM|FT|MI&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[ASC | DESC]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[COUNT count [ANY]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[WITHCOORD] [WITHDIST] [WITHHASH]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;搜索中心二选一：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FROMMEMBER member&lt;/code&gt;：以已有成员为中心；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FROMLONLAT longitude latitude&lt;/code&gt;：以临时坐标为中心。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;搜索形状二选一：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BYRADIUS&lt;/code&gt;：圆形范围；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BYBOX&lt;/code&gt;：以中心为中心点、宽度和高度给定的轴对齐矩形。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;常用选项：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ASC&lt;/code&gt;：从近到远；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DESC&lt;/code&gt;：从远到近；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COUNT n&lt;/code&gt;：最多返回 n 条；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COUNT n ANY&lt;/code&gt;：找到足够数量就尽早停止，可能更快，但不保证拿到真正最近的 n 条；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WITHDIST&lt;/code&gt;：附带到中心的距离；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WITHCOORD&lt;/code&gt;：附带坐标；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WITHHASH&lt;/code&gt;：附带内部 52 位 Geohash 值，通常只用于调试。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.6 GEOSEARCHSTORE：保存搜索结果&lt;a href=&quot;#56-geosearchstore保存搜索结果&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOSEARCHSTORE destination source&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;FROMMEMBER member | FROMLONLAT longitude latitude&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;BYRADIUS radius M|KM|FT|MI | BYBOX width height M|KM|FT|MI&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[ASC | DESC]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[COUNT count [ANY]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[STOREDIST]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;不加 &lt;code&gt;STOREDIST&lt;/code&gt;：目标 Sorted Set 的 score 仍是地理编码，可继续做 GEO 查询；&lt;/li&gt;
&lt;li&gt;加 &lt;code&gt;STOREDIST&lt;/code&gt;：目标 Sorted Set 的 score 是到中心的距离，适合再用 &lt;code&gt;ZRANGE ... WITHSCORES&lt;/code&gt; 排名，但目标 key 不再是可直接查询的地理索引；&lt;/li&gt;
&lt;li&gt;命令返回写入目标 key 的元素数量；&lt;/li&gt;
&lt;li&gt;如果目标 key 已存在，会被结果集替换。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GEOSEARCHSTORE geo:nearby:distance geo:stations \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;FROMLONLAT 116.397904 39.909005 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BYRADIUS 10 KM ASC STOREDIST&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ZRANGE geo:nearby:distance 0 -1 WITHSCORES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;在 Redis Cluster 中，这是一个涉及源 key 和目标 key 的多 key 命令。可用相同 hash tag 让它们落到同一 slot，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;geo:{beijing}:stations&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;geo:{beijing}:nearby&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 性能与工程建议&lt;a href=&quot;#6-性能与工程建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;6.1 复杂度&lt;a href=&quot;#61-复杂度&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GEOADD&lt;/code&gt;：每个成员 &lt;code&gt;O(log N)&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GEODIST&lt;/code&gt;：&lt;code&gt;O(1)&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GEOPOS&lt;/code&gt;、&lt;code&gt;GEOHASH&lt;/code&gt;：每个成员 &lt;code&gt;O(1)&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GEOSEARCH&lt;/code&gt; / &lt;code&gt;GEOSEARCHSTORE&lt;/code&gt;：官方标注为 &lt;code&gt;O(N + log M)&lt;/code&gt;，其中 N 是形状外接网格范围内的候选元素数，M 是索引总元素数。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;查询成本取决于范围内的候选密度，而不只是最终返回数量。超大半径、热点区域和无上限返回都可能带来较高延迟。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 建议&lt;a href=&quot;#62-建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;按城市、区域或业务类型拆分 key，避免一个 GEO key 无限制膨胀；&lt;/li&gt;
&lt;li&gt;查询时尽量设置合理半径和 &lt;code&gt;COUNT&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;只追求低延迟且能接受近似结果时，考虑 &lt;code&gt;COUNT n ANY&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;成员只保存稳定 ID，例如 &lt;code&gt;station:123&lt;/code&gt;，名称、地址等详情放在 Hash/JSON；&lt;/li&gt;
&lt;li&gt;GEO key 和详情 key 分开设置容量治理与 TTL；过期是 key 级别，不能直接只给某个 GEO member 设置 TTL；&lt;/li&gt;
&lt;li&gt;动态对象离线时用 &lt;code&gt;ZREM&lt;/code&gt; 移除，或另外维护心跳时间并定期清理；&lt;/li&gt;
&lt;li&gt;道路距离、路径规划、复杂多边形、跨坐标系转换应交给地图/GIS 服务；&lt;/li&gt;
&lt;li&gt;如果还要按名称、标签、价格等条件联合过滤，可考虑 Redis Search 的 GEO/GEOSHAPE 能力，而不是只用基础 GEO 命令。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 官方资料&lt;a href=&quot;#7-官方资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/geospatial/&quot; target=&quot;_blank&quot;&gt;Redis geospatial 数据类型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geoadd/&quot; target=&quot;_blank&quot;&gt;GEOADD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geodist/&quot; target=&quot;_blank&quot;&gt;GEODIST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geohash/&quot; target=&quot;_blank&quot;&gt;GEOHASH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geopos/&quot; target=&quot;_blank&quot;&gt;GEOPOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geosearch/&quot; target=&quot;_blank&quot;&gt;GEOSEARCH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/geosearchstore/&quot; target=&quot;_blank&quot;&gt;GEOSEARCHSTORE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/georadius/&quot; target=&quot;_blank&quot;&gt;GEORADIUS（deprecated）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis HyperLogLog</title><link>https://aronblake.cloud/posts/redis/redis-hyperloglog%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis-hyperloglog%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/</guid><description>Redis HyperLogLog相关知识</description><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;适用范围：Redis Open Source 2.8.9+。&lt;/p&gt;&lt;/blockquote&gt;
&lt;section&gt;&lt;h2&gt;1. 从 PV、UV 和基数说起&lt;a href=&quot;#1-从-pvuv-和基数说起&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1.1 PV&lt;a href=&quot;#11-pv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;PV（Page View）通常表示页面浏览量或事件发生次数。一次访问记一次，同一用户访问 10 次通常产生 10 个 PV。&lt;/p&gt;&lt;p&gt;PV 不需要去重，可以直接使用计数器：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INCR metrics:{shop}:pv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.2 UV&lt;a href=&quot;#12-uv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;UV（Unique Visitor）表示某个统计窗口内去重后的访问者数量。同一个用户在一天内访问多次，在日 UV 中只算一次。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;访问事件：A A B C A B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PV：6&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UV：3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;严格来说，UV 不一定等于“自然人数”。它取决于业务选择的身份标识：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;登录用户 ID；&lt;/li&gt;
&lt;li&gt;Cookie ID；&lt;/li&gt;
&lt;li&gt;设备 ID；&lt;/li&gt;
&lt;li&gt;经过隐私评审的匿名标识；&lt;/li&gt;
&lt;li&gt;IP 地址与其他特征的组合。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;标识不稳定会把同一个人算成多人；多人共用一个标识又会被算成一人。因此定义 UV 时，必须同时说明身份标识和时间窗口。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.3 基数&lt;a href=&quot;#13-基数&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;基数（Cardinality）是集合中不重复元素的数量：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;集合 {A, A, B, C, C} 的基数 = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;HyperLogLog（简称 HLL）解决的正是“大规模数据的近似基数统计”问题。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. HyperLogLog 是什么&lt;a href=&quot;#2-hyperloglog-是什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;HyperLogLog 是一种概率数据结构：&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;li&gt;最终返回去重数量的近似值；&lt;/li&gt;
&lt;li&gt;内存基本不随已观察元素数量线性增长。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Redis 的实现：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;最坏情况下约使用 12 KB 数据空间；&lt;/li&gt;
&lt;li&gt;标准误差约为 0.81%；&lt;/li&gt;
&lt;li&gt;最多可估计约 &lt;code&gt;2^64&lt;/code&gt; 个不同元素；&lt;/li&gt;
&lt;li&gt;核心命令是 &lt;code&gt;PFADD&lt;/code&gt;、&lt;code&gt;PFCOUNT&lt;/code&gt;、&lt;code&gt;PFMERGE&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;它适合流量趋势、独立访客、独立搜索词、独立设备、独立视频观众等“允许近似”的大规模统计。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 为什么不用普通 Set&lt;a href=&quot;#3-为什么不用普通-set&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;使用 Set 可以得到精确 UV：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SADD uv:exact user:1 user:2 user:3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SCARD uv:exact&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;但 Set 必须保存每一个唯一成员，内存复杂度为 &lt;code&gt;O(N)&lt;/code&gt;。随着访问者数量增长，成员数据、哈希表节点和分配器开销都会持续增加。&lt;/p&gt;&lt;p&gt;HLL 不保存成员本身，只保存统计摘要。无论观察几万、几百万还是更多不同元素，密集表示的数据部分都约为 12 KB。代价是：&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;li&gt;无法删除某一个已加入元素。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 核心原理&lt;a href=&quot;#4-核心原理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;HyperLogLog 利用了这样一个概率现象：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;在均匀随机的二进制序列中，连续出现很多个前导 0 很少见；观察到的最大前导 0 数越大，通常意味着观察过的不同元素越多。&lt;/p&gt;&lt;/blockquote&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;用剩余部分计算“第一个 1 出现前有多少个 0”；&lt;/li&gt;
&lt;li&gt;该寄存器只保留它见过的最大值；&lt;/li&gt;
&lt;li&gt;综合所有寄存器，通过调和平均和偏差修正估计基数。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Redis 使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;16384 个寄存器 × 每个寄存器 6 bit = 98304 bit = 12288 byte&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;再加上 16 字节头部等内部信息。&lt;/p&gt;&lt;p&gt;同一个元素经过相同哈希后总会定位到同一寄存器、得到相同观测值，因此重复加入不会不断增加估算值。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;4.1 为什么需要很多寄存器&lt;a href=&quot;#41-为什么需要很多寄存器&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;只记录一个“最大前导 0 数”波动太大。HLL 将输入分散到大量寄存器中，再综合所有观测值，使估计更稳定。&lt;/p&gt;&lt;p&gt;标准误差可近似理解为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1.04 / sqrt(m)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;当 &lt;code&gt;m = 16384&lt;/code&gt; 时：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1.04 / sqrt(16384) ≈ 0.8125%&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 0.81% 不是最大误差保证&lt;a href=&quot;#42-081-不是最大误差保证&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 文档中的 0.81% 是 &lt;strong&gt;标准误差&lt;/strong&gt;，不是“每次结果与真实值的误差一定小于 0.81%”。&lt;/p&gt;&lt;p&gt;例如真实基数为 100 万时，0.81% 对应的标准误差量级约为 8100，但某一次估算的偏差可能更大或更小。若业务要求计费、结算、配额、审计等严格精确结果，应使用精确数据结构或数据库统计。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. Redis 中的存储表示&lt;a href=&quot;#5-redis-中的存储表示&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis HLL 在内部编码为 String：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD hll:demo a b c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;TYPE hll:demo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;HLL 有两种内部表示：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稀疏表示&lt;/strong&gt;：初期大量寄存器为 0，使用游程编码，内存可显著低于 12 KB；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密集表示&lt;/strong&gt;：数据增多后自动转换，使用 16384 个 6-bit 寄存器，数据部分为 12288 字节。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;它可以用 &lt;code&gt;GET&lt;/code&gt; 序列化、用 &lt;code&gt;SET&lt;/code&gt; 恢复，但不应使用普通 String 命令随意修改其中的字节，否则会破坏 HLL 编码或得到无意义结果。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 命令总览&lt;a href=&quot;#6-命令总览&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;th&gt;返回值&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;PFADD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;将一个或多个元素加入 HLL&lt;/td&gt;&lt;td&gt;每个元素 &lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;寄存器是否发生变化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;PFCOUNT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;返回一个 HLL或多个 HLL 并集的估计基数&lt;/td&gt;&lt;td&gt;单 key 平均 &lt;code&gt;O(1)&lt;/code&gt;；多 key 为 &lt;code&gt;O(N)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;估计基数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;PFMERGE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;将多个 HLL 的并集保存到目标 key&lt;/td&gt;&lt;td&gt;合并 N 个 HLL 为 &lt;code&gt;O(N)&lt;/code&gt;，常数较高&lt;/td&gt;&lt;td&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;PFDEBUG&lt;/code&gt;、&lt;code&gt;PFSELFTEST&lt;/code&gt; 是内部调试/测试命令，带有危险或管理属性，不属于普通业务 API。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 命令详解&lt;a href=&quot;#7-命令详解&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;7.1 PFADD：加入观测元素&lt;a href=&quot;#71-pfadd加入观测元素&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD key [element [element ...]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;添加单个用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;批量添加：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;user:1001 user:1002 user:1003&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回值：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;：至少一个内部寄存器发生变化；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;：没有寄存器发生变化。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;需要特别注意：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD 返回 1 ≠ 一定加入了一个从未出现的新元素&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD 返回 0 ≠ 这个元素一定曾经出现过&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;原因是 HLL 不保存成员集合。不同元素可能对现有寄存器状态没有进一步贡献。因此不能用 &lt;code&gt;PFADD&lt;/code&gt; 的返回值实现精确的“首次访问”“用户是否存在”判断。&lt;/p&gt;&lt;p&gt;同一个元素重复执行 &lt;code&gt;PFADD&lt;/code&gt; 对最终摘要是幂等的，适合处理可能重试的事件。&lt;/p&gt;&lt;p&gt;不传元素也是合法的：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD hll:empty&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;key 不存在时会创建一个空 HLL；存在时不做实际修改。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.2 PFCOUNT：估计基数&lt;a href=&quot;#72-pfcount估计基数&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;单 key：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT metrics:{shop}:uv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回该日的估计 UV。key 不存在时返回 0。&lt;/p&gt;&lt;p&gt;多 key：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-21 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-22 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-23&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回三个 HLL &lt;strong&gt;并集&lt;/strong&gt; 的估计基数。重复出现在多天中的同一用户只近似计算一次。&lt;/p&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;周 UV ≠ 每日 UV 直接相加&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每日 UV 相加会重复计算跨天访问者，周 UV 应通过多 key &lt;code&gt;PFCOUNT&lt;/code&gt; 或 &lt;code&gt;PFMERGE&lt;/code&gt; 后再统计。&lt;/p&gt;&lt;p&gt;性能区别：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;单 key &lt;code&gt;PFCOUNT&lt;/code&gt; 会使用内部缓存，平均开销很小；&lt;/li&gt;
&lt;li&gt;多 key &lt;code&gt;PFCOUNT&lt;/code&gt; 会临时合并所有 HLL，不能复用并集缓存，调用频繁时成本明显更高。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;一个较少见但重要的内部细节是：&lt;code&gt;PFCOUNT&lt;/code&gt; 可能更新 HLL 头部中的基数缓存。因此从底层实现看，它可能修改最后几个缓存字节，即使业务语义上它是读取统计值。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7.3 PFMERGE：合并并保存&lt;a href=&quot;#73-pfmerge合并并保存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFMERGE destination [source [source ...]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFMERGE metrics:{shop}:uv:2026-W31 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-27 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-28 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-29&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT metrics:{shop}:uv:2026-W31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;PFMERGE&lt;/code&gt; 保存的是可继续合并和计数的 HLL 摘要，不是普通整数。&lt;/p&gt;&lt;p&gt;合并的底层含义可以简化为：对每个寄存器取所有源 HLL 中的最大值。因此 HLL 合并具有：&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;section&gt;&lt;h4&gt;目标 key 的累积语义&lt;a href=&quot;#目标-key-的累积语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;如果 destination 已存在，Redis 会把 destination 本身也当作一个源 HLL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFMERGE total old-part&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFMERGE total new-part&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;第二次结果包含原有 &lt;code&gt;total&lt;/code&gt; 与 &lt;code&gt;new-part&lt;/code&gt; 的并集，而不是单纯用 &lt;code&gt;new-part&lt;/code&gt; 覆盖。&lt;/p&gt;&lt;p&gt;如果要从头重新计算某个固定名称的汇总 key，需要先明确删除旧目标，或者更稳妥地写入一个新的版本化 key，再切换引用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;metrics:{shop}:uv:2026-W31:v2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 完整案例：同时统计 PV 和 UV&lt;a href=&quot;#8-完整案例同时统计-pv-和-uv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;假设用户 1001 当天访问三次，用户 1002 访问两次。&lt;/p&gt;&lt;p&gt;每次访问都增加 PV：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;INCR metrics:{shop}:pv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每次访问也将稳定用户标识加入 HLL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1001&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFADD metrics:{shop}:uv:2026-07-27 user:1002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GET metrics:{shop}:pv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT metrics:{shop}:uv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;小样本中通常会得到类似：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PV = 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UV ≈ 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;PV 是精确计数，UV 是近似基数。不要使用 HLL 统计 PV，因为 HLL 会自动弱化重复元素的贡献。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 日 UV、周 UV、月 UV&lt;a href=&quot;#9-日-uv周-uv月-uv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;9.1 每天一个 HLL&lt;a href=&quot;#91-每天一个-hll&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-28&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-29&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样可以：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;独立查询每天 UV；&lt;/li&gt;
&lt;li&gt;灵活合并周/月 UV；&lt;/li&gt;
&lt;li&gt;按保留周期设置 TTL；&lt;/li&gt;
&lt;li&gt;避免永久 HLL 无法删除历史元素的问题。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.2 临时查询周 UV&lt;a href=&quot;#92-临时查询周-uv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-27 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-28 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-29 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-30 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;适合低频临时查询。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.3 预聚合周 UV&lt;a href=&quot;#93-预聚合周-uv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFMERGE metrics:{shop}:uv:2026-W31 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-27 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-28 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-29 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-30 \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;metrics:{shop}:uv:2026-07-31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;PFCOUNT metrics:{shop}:uv:2026-W31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;适合频繁查询报表。汇总 key 可设置比日 key 更长的 TTL。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9.4 时间窗口必须统一&lt;a href=&quot;#94-时间窗口必须统一&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;业务应明确：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;使用 UTC 还是业务时区；&lt;/li&gt;
&lt;li&gt;按事件发生时间还是服务器接收时间；&lt;/li&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;否则同一事件可能被放入不同日期的 HLL，导致跨系统统计不一致。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. HLL 能做什么、不能做什么&lt;a href=&quot;#10-hll-能做什么不能做什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;10.1 能做&lt;a href=&quot;#101-能做&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;近似统计去重数量；&lt;/li&gt;
&lt;li&gt;合并多个统计窗口或分片的并集；&lt;/li&gt;
&lt;li&gt;用固定小内存持续接收大量重复事件；&lt;/li&gt;
&lt;li&gt;序列化摘要并在其他 Redis 实例恢复。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10.2 不能做&lt;a href=&quot;#102-不能做&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;判断用户 1001 是否访问过；&lt;/li&gt;
&lt;li&gt;列出所有访问用户；&lt;/li&gt;
&lt;li&gt;返回某个用户出现次数；&lt;/li&gt;
&lt;li&gt;删除单个用户的贡献；&lt;/li&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;如果必须支持成员查询、删除、枚举或精确集合运算，应使用 Set、Bitmap、数据库或其他合适结构。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;11. 交集与留存为什么要谨慎&lt;a href=&quot;#11-交集与留存为什么要谨慎&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;数学上可以用容斥关系估算两个集合的交集：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;|A ∩ B| ≈ PFCOUNT(A) + PFCOUNT(B) - PFCOUNT(A, B)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;但三次 HLL 估计都有误差，做减法时误差会叠加。如果真实交集远小于 A、B 的规模，相对误差可能非常大，甚至可能出现不合理结果。&lt;/p&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;HLL 很适合估计并集 UV；&lt;/li&gt;
&lt;li&gt;不适合要求稳定精度的留存、交集、流失用户统计；&lt;/li&gt;
&lt;li&gt;精确或小交集场景优先使用 Bitmap、Set 或离线明细计算。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;12. HLL、Set、Bitmap、Bloom Filter 的选择&lt;a href=&quot;#12-hllsetbitmapbloom-filter-的选择&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;th&gt;成员查询&lt;/th&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;HyperLogLog&lt;/td&gt;&lt;td&gt;有多少个不同元素&lt;/td&gt;&lt;td&gt;近似&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;主要支持并集合并&lt;/td&gt;&lt;td&gt;最高约 12 KB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Set&lt;/td&gt;&lt;td&gt;有哪些不同元素&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;支持&lt;/td&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;Bitmap&lt;/td&gt;&lt;td&gt;哪些紧凑整数 ID 为真&lt;/td&gt;&lt;td&gt;精确&lt;/td&gt;&lt;td&gt;支持&lt;/td&gt;&lt;td&gt;可清 bit&lt;/td&gt;&lt;td&gt;快速交并差&lt;/td&gt;&lt;td&gt;取决于最大 offset&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bloom Filter&lt;/td&gt;&lt;td&gt;某元素是否可能存在&lt;/td&gt;&lt;td&gt;概率&lt;/td&gt;&lt;td&gt;支持概率判断&lt;/td&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;/p&gt;&lt;ul&gt;
&lt;li&gt;只要近似 UV，数据量很大：HLL；&lt;/li&gt;
&lt;li&gt;要精确人数并保留成员：Set；&lt;/li&gt;
&lt;li&gt;用户 ID 紧凑且需要精确交并集：Bitmap；&lt;/li&gt;
&lt;li&gt;只要快速判断“可能存在/一定不存在”：Bloom Filter。s&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;13. 官方资料&lt;a href=&quot;#13-官方资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/probabilistic/hyperloglogs/&quot; target=&quot;_blank&quot;&gt;Redis HyperLogLog 数据类型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/pfadd/&quot; target=&quot;_blank&quot;&gt;PFADD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/pfcount/&quot; target=&quot;_blank&quot;&gt;PFCOUNT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/commands/pfmerge/&quot; target=&quot;_blank&quot;&gt;PFMERGE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/probabilistic/&quot; target=&quot;_blank&quot;&gt;Redis 概率数据结构总览&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis实战：Redisson 分布式锁与 Stream 消息队列</title><link>https://aronblake.cloud/posts/redis/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/</guid><description>Redis实战：Redisson 分布式锁与 Stream 消息队列</description><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文整理两个常见的 Redis 实战场景：使用 Redisson 实现分布式锁，以及使用 Redis Stream 构建支持消息持久化、阻塞读取、消费者组和消息确认的消息队列。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;一、Redisson 分布式锁&lt;a href=&quot;#一redisson-分布式锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redisson 是 Redis 的 Java 客户端之一。它在 Redis 命令之上封装了分布式锁、集合、信号量等常用组件，可以减少手动编写锁续期和解锁脚本的工作。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1. 引入依赖&lt;a href=&quot;#1-引入依赖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;org.redisson&amp;lt;/&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;redisson&amp;lt;/&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;3.13.6&amp;lt;/&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 配置 Redisson 客户端&lt;a href=&quot;#2-配置-redisson-客户端&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedissonConfig&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedissonClient&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redissonClient&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Config&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;useSingleServer&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;setAddress&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;redis://10.211.55.3:6379&quot;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;setPassword&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;123123&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 创建RedissonClient对象&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Redisson&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(config);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 在业务中使用锁&lt;a href=&quot;#3-在业务中使用锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这段代码以用户 ID 作为锁粒度，保证同一用户的下单请求串行执行。不同用户使用不同的锁，因此仍然可以并发下单。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Resource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedissonClient&lt;/span&gt;&lt;span&gt; redissonClient&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; userId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UserHolder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getUser&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 创建锁对象&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// SimpleRedisLock lock = new SimpleRedisLock(&quot;order&quot; + userId, stringRedisTemplate);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RLock&lt;/span&gt;&lt;span&gt; lock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redissonClient&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;lock:order:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; userId);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; isLock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;//  判断是否获取锁成功&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;isLock){&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;// 获取锁失败，返回错误或重试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;不允许重复下单&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;// 获取代理对象(事物)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;IVoucherOrderService&lt;/span&gt;&lt;span&gt; proxy &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (IVoucherOrderService) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AopContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentProxy&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;proxy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createVoucherOrder&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;// 释放锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 使用分布式锁时需要注意什么&lt;a href=&quot;#4-使用分布式锁时需要注意什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tryLock()&lt;/code&gt; 会立即尝试获取锁，失败后直接返回；需要等待时可以使用带等待时间的重载方法。&lt;/li&gt;
&lt;li&gt;未显式指定租约时间时，Redisson 的看门狗机制会在持锁线程仍然存活时自动续期。&lt;/li&gt;
&lt;li&gt;解锁必须放在 &lt;code&gt;finally&lt;/code&gt; 中，避免业务异常导致锁无法释放。&lt;/li&gt;
&lt;li&gt;只有锁的持有线程才能解锁。复杂流程中可在解锁前使用 &lt;code&gt;lock.isHeldByCurrentThread()&lt;/code&gt; 检查。&lt;/li&gt;
&lt;li&gt;分布式锁不能替代数据库约束。防止重复下单时，数据库唯一索引仍是最后一道保障。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;AopContext.currentProxy()&lt;/code&gt; 获取代理对象，需要启用代理暴露；否则可能抛出异常。也可以通过拆分 Service 避免同类内部调用导致事务失效。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;二、Redis Stream 基础&lt;a href=&quot;#二redis-stream-基础&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis Stream 是 Redis 5.0 引入的数据类型，适合保存按时间追加的事件。一个 Stream 可以理解为一条只向尾部追加的日志，每条消息称为一个 Entry。&lt;/p&gt;&lt;p&gt;Stream 的基本结构如下：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Stream key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├── 1720000000000-0  name=jack  age=21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├── 1720000000100-0  name=rose  age=20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── 1720000000100-1  name=tom   age=22&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每条 Entry 包含两部分：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;唯一消息 ID，例如 &lt;code&gt;1720000000000-0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;一个或多个 &lt;code&gt;field value&lt;/code&gt; 键值对。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;消息 ID 的格式是 &lt;code&gt;毫秒时间戳-序列号&lt;/code&gt;。同一毫秒内产生多条消息时，序列号会递增。通常使用 &lt;code&gt;*&lt;/code&gt; 让 Redis 自动生成 ID。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三、使用 XADD 发送消息&lt;a href=&quot;#三使用-xadd-发送消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 基本语法&lt;a href=&quot;#1-基本语法&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XADD key [NOMKSTREAM] [MAXLEN | MINID [= | ~] threshold [LIMIT count]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* | ID field value [field value ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;常用参数：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt;：Stream 的名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NOMKSTREAM&lt;/code&gt;：Stream 不存在时不自动创建；默认会自动创建。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MAXLEN&lt;/code&gt;：限制 Stream 的最大长度，避免消息无限堆积。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MINID&lt;/code&gt;：删除小于指定 ID 的旧消息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~&lt;/code&gt;：近似裁剪，通常比精确裁剪 &lt;code&gt;=&lt;/code&gt; 的性能更好。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;：让 Redis 自动生成消息 ID。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;field value&lt;/code&gt;：消息内容，可以包含多个键值对。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 添加一条消息&lt;a href=&quot;#2-添加一条消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XADD users * name jack age 21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;返回值是新消息的 ID：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&quot;1644805700523-0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 限制队列长度&lt;a href=&quot;#3-限制队列长度&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XADD users MAXLEN ~ 10000 * name jack age 21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;该命令在添加消息的同时，把 Stream 大致控制在 10000 条以内。&lt;code&gt;~&lt;/code&gt; 是近似裁剪，实际长度可能略大于阈值。&lt;/p&gt;&lt;p&gt;常用的查看命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XLEN users&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XRANGE users - + COUNT 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREVRANGE users + - COUNT 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XINFO STREAM users&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;四、使用 XREAD 读取消息&lt;a href=&quot;#四使用-xread-读取消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;XREAD&lt;/code&gt; 直接读取 Stream，不使用消费者组。它适合单消费者读取，或者多个消费者都需要接收同一份消息的广播式场景。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1. 基本语法&lt;a href=&quot;#1-基本语法-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;阻塞 1 秒，等待 &lt;code&gt;users&lt;/code&gt; 中的新消息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREAD COUNT 1 BLOCK 1000 STREAMS users $&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果 1 秒内没有新消息，命令返回 &lt;code&gt;nil&lt;/code&gt;。&lt;code&gt;BLOCK 0&lt;/code&gt; 表示一直阻塞，直到有消息到达。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 起始 ID 的含义&lt;a href=&quot;#2-起始-id-的含义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0-0&lt;/code&gt;：从最早的消息开始读取。&lt;/li&gt;
&lt;li&gt;某个具体 ID：读取 ID 大于它的消息，适合接着上一次的位置继续读取。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt;：只等待执行命令之后到达的新消息。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 为什么循环使用 &lt;code&gt;$&lt;/code&gt; 可能漏读&lt;a href=&quot;#3-为什么循环使用--可能漏读&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果每次循环都执行下面的命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREAD COUNT 1 BLOCK 2000 STREAMS users $&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;那么 &lt;code&gt;$&lt;/code&gt; 每次都会重新代表“当前 Stream 的最后一条消息”。消费者处理上一条消息期间，如果又有多条消息到达，下次读取会从新的队尾开始等待，这些已经到达的消息可能被跳过。&lt;/p&gt;&lt;p&gt;更稳妥的做法是保存最后一次成功读取的消息 ID，并在下一次读取时传入该 ID：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;lastId = 0-0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;循环：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;messages = XREAD COUNT 10 BLOCK 2000 STREAMS users lastId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;依次处理 messages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lastId = 本批最后一条消息的 ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果进程重启后仍要从原位置继续，还需要把 &lt;code&gt;lastId&lt;/code&gt; 持久化。Redis 本身不会为普通 &lt;code&gt;XREAD&lt;/code&gt; 保存消费者进度。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. XREAD 的特点&lt;a href=&quot;#4-xread-的特点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;支持按 ID 回溯历史消息。&lt;/li&gt;
&lt;li&gt;支持阻塞读取。&lt;/li&gt;
&lt;li&gt;多个客户端可以读取同一条消息，彼此之间不会自动分流。&lt;/li&gt;
&lt;li&gt;Redis 不记录每个读取者的确认状态。&lt;/li&gt;
&lt;li&gt;使用方式不当会跳过消息，因此不适合直接承担需要可靠消费的复杂业务。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五、消费者组 Consumer Group&lt;a href=&quot;#五消费者组-consumer-group&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;消费者组将多个消费者组织成一个组，共同消费同一个 Stream。它主要解决三个问题：消息分流、消费进度记录和消息确认。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1. 消息分流&lt;a href=&quot;#1-消息分流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;同一消费者组中的多个消费者会竞争组内的新消息。一条新消息通常只交给组内的一个消费者处理，从而提高整体吞吐量。&lt;/p&gt;&lt;p&gt;不同消费者组之间互不影响。同一条消息可以分别被多个消费者组各消费一次。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 消费进度&lt;a href=&quot;#2-消费进度&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;消费者组维护最后投递位置，用于记录哪些新消息已经投递给该组。消费者宕机重启后，消费者组可以继续从组的进度读取新消息。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. Pending Entries List&lt;a href=&quot;#3-pending-entries-list&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;消费者读取消息后，如果没有使用 &lt;code&gt;NOACK&lt;/code&gt;，该消息会进入 Pending Entries List，简称 PEL。PEL 记录消息 ID、所属消费者、空闲时间和投递次数。&lt;/p&gt;&lt;p&gt;业务处理成功后，需要执行 &lt;code&gt;XACK&lt;/code&gt; 确认消息。确认成功后，消息才会从 PEL 中移除。注意，&lt;code&gt;XACK&lt;/code&gt; 只会修改消费者组的确认状态，不会删除 Stream 中的原始消息。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;六、管理消费者组&lt;a href=&quot;#六管理消费者组&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 创建消费者组&lt;a href=&quot;#1-创建消费者组&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP CREATE key groupName ID [MKSTREAM]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP CREATE users user-group 0-0 MKSTREAM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;参数说明：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt;：Stream 名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;groupName&lt;/code&gt;：消费者组名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ID&lt;/code&gt;：消费者组的起始位置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0-0&lt;/code&gt;：从 Stream 中现有的第一条消息开始消费。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt;：忽略当前已有消息，只消费创建消费者组之后的新消息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MKSTREAM&lt;/code&gt;：Stream 不存在时自动创建一个空 Stream。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 其他管理命令&lt;a href=&quot;#2-其他管理命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 删除消费者组&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP DESTROY users user-group&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 手动创建消费者&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP CREATECONSUMER users user-group consumer-1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 删除消费者&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP DELCONSUMER users user-group consumer-1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看消费者组和消费者信息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XINFO GROUPS users&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XINFO CONSUMERS users user-group&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;消费者通常不必手动创建。第一次执行 &lt;code&gt;XREADGROUP&lt;/code&gt; 时，如果消费者名称不存在，Redis 会自动创建该消费者。&lt;/p&gt;&lt;p&gt;删除消费者前必须先处理其 Pending 消息。直接执行 &lt;code&gt;XGROUP DELCONSUMER&lt;/code&gt; 会删除该消费者对应的 Pending 记录，未确认消息将无法再通过原 PEL 恢复。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;七、使用 XREADGROUP 消费消息&lt;a href=&quot;#七使用-xreadgroup-消费消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 基本语法&lt;a href=&quot;#1-基本语法-2&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREADGROUP GROUP group consumer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[COUNT count]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[BLOCK milliseconds]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[NOACK]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;STREAMS key [key ...] ID [ID ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;读取新消息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREADGROUP GROUP user-group consumer-1 COUNT 10 BLOCK 2000 STREAMS users &amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;参数说明：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;group&lt;/code&gt;：消费者组名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;consumer&lt;/code&gt;：当前消费者名称；不存在时会自动创建。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COUNT&lt;/code&gt;：本次最多返回的消息数量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BLOCK&lt;/code&gt;：没有消息时的最长等待时间，单位为毫秒。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STREAMS&lt;/code&gt;：后面依次提供 Stream 名称和对应的起始 ID。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;：读取从未投递给当前消费者组的新消息。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. &lt;code&gt;&amp;gt;&lt;/code&gt; 和具体 ID 的区别&lt;a href=&quot;#2--和具体-id-的区别&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;&amp;gt;&lt;/code&gt; 时，读取尚未投递给消费者组的新消息。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;0&lt;/code&gt; 或 &lt;code&gt;0-0&lt;/code&gt; 等具体 ID 时，读取已经分配给当前消费者、但尚未确认的 Pending 消息。&lt;/li&gt;
&lt;li&gt;具体 ID 不会直接读取其他消费者名下的 Pending 消息。接管其他消费者的消息需要使用 &lt;code&gt;XCLAIM&lt;/code&gt; 或 &lt;code&gt;XAUTOCLAIM&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 谨慎使用 NOACK&lt;a href=&quot;#3-谨慎使用-noack&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;NOACK&lt;/code&gt; 表示消息被读取后不进入 PEL。它更接近“无需确认”，而不是业务成功后的“自动确认”。如果消费者读取后立刻宕机，消息不会留在 PEL 中供后续重试。&lt;/p&gt;&lt;p&gt;对订单、支付、库存等可靠性要求高的业务，不建议使用 &lt;code&gt;NOACK&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;八、消息确认与异常恢复&lt;a href=&quot;#八消息确认与异常恢复&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 确认消息&lt;a href=&quot;#1-确认消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;业务处理成功后执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XACK users user-group 1644805700523-0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;推荐顺序是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;读取消息 -&amp;gt; 执行业务 -&amp;gt; 业务成功提交 -&amp;gt; XACK&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果业务处理失败，不要确认消息，让它继续保留在 PEL 中，等待重试或被其他消费者接管。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 查看 Pending 消息&lt;a href=&quot;#2-查看-pending-消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XPENDING users user-group&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XPENDING users user-group - + 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XPENDING users user-group - + 10 consumer-1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;第一条命令查看 PEL 摘要，后两条命令查看 Pending 消息明细。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 接管长时间未处理的消息&lt;a href=&quot;#3-接管长时间未处理的消息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis 6.2 及以上可以使用 &lt;code&gt;XAUTOCLAIM&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XAUTOCLAIM users user-group consumer-2 60000 0-0 COUNT 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这表示由 &lt;code&gt;consumer-2&lt;/code&gt; 接管空闲时间至少达到 60000 毫秒的 Pending 消息。较早版本可以先用 &lt;code&gt;XPENDING&lt;/code&gt; 找到消息 ID，再使用 &lt;code&gt;XCLAIM&lt;/code&gt; 接管。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 推荐的可靠消费流程&lt;a href=&quot;#4-推荐的可靠消费流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1. 使用 XREADGROUP ... STREAMS users &amp;gt; 阻塞读取新消息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2. 执行业务逻辑&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;3. 业务成功后执行 XACK&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;4. 业务失败时保留 Pending 状态，并记录失败原因&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;5. 定时扫描空闲时间过长的 Pending 消息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;6. 使用 XAUTOCLAIM 或 XCLAIM 接管并重试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;7. 超过最大重试次数后写入自定义死信 Stream，并人工或定时处理&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;消费者组配合 PEL 和 ACK 可以实现至少一次投递，但不能天然实现严格的恰好一次。消费者可能在“业务已成功、ACK 尚未发送”时宕机，恢复后同一条消息会再次处理，因此业务必须具备幂等性。&lt;/p&gt;&lt;p&gt;常见幂等方案：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;使用消息 ID 作为幂等键，并记录已处理消息。&lt;/li&gt;
&lt;li&gt;利用数据库唯一索引阻止重复写入。&lt;/li&gt;
&lt;li&gt;使用业务单号检查当前状态，只允许合法的状态迁移。&lt;/li&gt;
&lt;li&gt;把业务写入和消费记录放在同一个数据库事务中。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;九、XREAD 与 XREADGROUP 对比&lt;a href=&quot;#九xread-与-xreadgroup-对比&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对比项&lt;/th&gt;&lt;th&gt;&lt;code&gt;XREAD&lt;/code&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;XREADGROUP&lt;/code&gt;&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;客户端自行保存最后 ID&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;不支持&lt;/td&gt;&lt;td&gt;支持 &lt;code&gt;XACK&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pending 记录&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;支持 PEL&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;code&gt;XPENDING&lt;/code&gt;、&lt;code&gt;XCLAIM&lt;/code&gt;、&lt;code&gt;XAUTOCLAIM&lt;/code&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;/tbody&gt;&lt;/table&gt;&lt;p&gt;不能简单地认为 &lt;code&gt;XREADGROUP&lt;/code&gt; “绝对不会漏消息”。可靠性仍取决于是否正确使用 ACK、是否恢复 Pending 消息、是否误用 &lt;code&gt;NOACK&lt;/code&gt;、是否过早裁剪 Stream，以及业务是否具备幂等性。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;十、List、Pub/Sub 与 Stream 对比&lt;a href=&quot;#十listpubsub-与-stream-对比&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;




















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;List&lt;/th&gt;&lt;th&gt;Pub/Sub&lt;/th&gt;&lt;th&gt;Stream&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;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;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;td&gt;消费者组原生支持&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;消息确认&lt;/td&gt;&lt;td&gt;无原生 ACK&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;不支持&lt;/td&gt;&lt;td&gt;按 ID 支持&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;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;td&gt;可靠任务队列、事件流&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;选择建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;只需要非常简单的先进先出任务队列，可以考虑 List。&lt;/li&gt;
&lt;li&gt;只关心在线订阅者，并且允许离线期间丢消息，可以使用 Pub/Sub。&lt;/li&gt;
&lt;li&gt;需要持久化、回溯、消费者组、确认和故障恢复时，优先考虑 Stream。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;十一、生产实践建议&lt;a href=&quot;#十一生产实践建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;MAXLEN ~&lt;/code&gt; 或定期 &lt;code&gt;XTRIM&lt;/code&gt; 控制 Stream 长度，防止内存无限增长。&lt;/li&gt;
&lt;li&gt;每个消费者实例使用唯一且稳定的消费者名称，便于观察和故障接管。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;BLOCK&lt;/code&gt; 阻塞读取，避免无消息时高频轮询消耗 CPU。&lt;/li&gt;
&lt;li&gt;业务成功后再执行 &lt;code&gt;XACK&lt;/code&gt;，不要把“读取成功”当成“处理成功”。&lt;/li&gt;
&lt;li&gt;定时监控 PEL 数量、消息空闲时间、投递次数和消费者状态。&lt;/li&gt;
&lt;li&gt;对重复消费做好幂等处理，这是至少一次投递模型中的必要设计。&lt;/li&gt;
&lt;li&gt;设计最大重试次数和死信 Stream，避免异常消息永久占用重试资源。&lt;/li&gt;
&lt;li&gt;裁剪或删除消息前确认消费组的处理进度。过早清理可能导致 PEL 中只剩消息 ID，而消息正文已经不存在。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redisson 分布式锁解决的是多个应用实例之间的并发互斥问题，Redis Stream 解决的是消息的持久化、分发与消费进度管理问题。二者可以组合使用，但职责不同：锁用于保护临界区，Stream 用于解耦生产者和消费者。&lt;/p&gt;&lt;p&gt;学习 Redis Stream 时，需要重点掌握以下关系：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XADD        负责生产消息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREAD       负责不带消费者组的读取&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XGROUP      负责创建和管理消费者组&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XREADGROUP  负责组内分流和消费&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XPENDING    负责查看未确认消息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XACK        负责确认处理完成&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;XCLAIM / XAUTOCLAIM 负责接管超时未完成的消息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis全局唯一ID</title><link>https://aronblake.cloud/posts/redis/%E5%85%A8%E5%B1%80%E5%94%AF%E4%B8%80id/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/%E5%85%A8%E5%B1%80%E5%94%AF%E4%B8%80id/</guid><description>Redis全局唯一ID</description><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;全局ID生成器&lt;a href=&quot;#全局id生成器&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;订单表使用数据库自增ID存在一些问题：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;ID的规律性太明显，容易暴露业务数据量&lt;/li&gt;
&lt;li&gt;分库分表后，不同表可能生成重复ID&lt;/li&gt;
&lt;li&gt;受单表数据量和单库写入能力的限制&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;全局ID生成器，是一种在分布式系统下用来生成全局唯一ID的工具，一般要满足下列特性：&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;li&gt;递增性&lt;/li&gt;
&lt;li&gt;安全性&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;为了增加ID的安全性，不直接使用Redis自增的数值，而是拼接时间戳等其它信息。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;ID的组成&lt;a href=&quot;#id的组成&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;64位long类型表示：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;符号位：1 bit，固定为0&lt;/li&gt;
&lt;li&gt;时间戳：31 bit，以秒为单位，大约可以使用68年&lt;/li&gt;
&lt;li&gt;序列号：32 bit，使用Redis自增值生成&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;0 | 31位时间戳 | 32位序列号&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;生成公式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; timestamp &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; COUNT_BITS &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用相对时间戳而不是完整时间戳，可以减少时间戳占用的位数。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;Redis自增策略&lt;a href=&quot;#redis自增策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Redis Key按照“业务类型+日期”划分：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;icr:order:2026:07:09&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;icr:order:2026:07:10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样可以让不同业务使用不同计数器，并且能够按天统计订单量。&lt;/p&gt;&lt;p&gt;Redis的INCR命令是原子操作，多线程并发执行时不会生成重复序号。&lt;/p&gt;&lt;p&gt;代码中的计数器实际上是按天递增，因此同一个Key在一天内不能超过2^32 - 1。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;RedisIdWorker.java&lt;a href=&quot;#redisidworkerjava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisIdWorker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 开始时间戳&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; BEGIN_TIMESTAMP &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1783555200L&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 序列号的位数&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; COUNT_BITS &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt; stringRedisTemplate&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisIdWorker&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stringRedisTemplate;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nextId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;keyPrefix&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 1.生成时间戳&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nowSecond&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toEpochSecond&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ZoneOffset&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UTC&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timestamp&lt;/span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; nowSecond &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; BEGIN_TIMESTAMP;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 2.生成序列号&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 2.1获取当前日期，精确到日&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DateTimeFormatter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofPattern&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;yyyy:MM:dd&quot;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;increment&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;icr:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; keyPrefix &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; date);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 3.拼接并返回&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; timestamp &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; COUNT_BITS &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; count;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;[] &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2026&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;second&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toEpochSecond&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ZoneOffset&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UTC&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(second);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;HmDianPingApplicationTests.java&lt;a href=&quot;#hmdianpingapplicationtestsjava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Resource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisIdWorker&lt;/span&gt;&lt;span&gt; redisIdWorker&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ExecutorService&lt;/span&gt;&lt;span&gt; es &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Executors&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newFixedThreadPool&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testIDWorker&lt;/span&gt;&lt;span&gt;() throws InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;CountDownLatch&lt;/span&gt;&lt;span&gt; latch &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CountDownLatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;300&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Runnable&lt;/span&gt;&lt;span&gt; task &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisIdWorker&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;nextId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;order&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;id= &quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;latch&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;countDown&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; begin &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentTimeMillis&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;300&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;es&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;submit&lt;/span&gt;&lt;span&gt;(task);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;latch&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; end &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentTimeMillis&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;time = &quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (end &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; begin));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;es&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;shutdown&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;全局ID常见实现还有：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;UUID&lt;/li&gt;
&lt;li&gt;数据库自增&lt;/li&gt;
&lt;li&gt;Redis自增&lt;/li&gt;
&lt;li&gt;Snowflake雪花算法&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;优惠券添加&lt;a href=&quot;#优惠券添加&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;数据库使用两张表保存优惠券信息：&lt;/p&gt;&lt;p&gt;&lt;code&gt;tb_voucher&lt;/code&gt;保存优惠券基本信息，例如优惠金额、使用规则、折扣信息和店铺ID。&lt;/p&gt;&lt;p&gt;&lt;code&gt;tb_seckill_voucher&lt;/code&gt;保存秒杀库存、秒杀开始时间和秒杀结束时间。只有秒杀优惠券才需要保存这些信息。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;VoucherController.java&lt;a href=&quot;#vouchercontrollerjava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;RestController&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;RequestMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/voucher&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;VoucherController&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Resource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IVoucherService&lt;/span&gt;&lt;span&gt; voucherService&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 新增秒杀券&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* &lt;/span&gt;&lt;span&gt;@param&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt; 优惠券信息，包含秒杀信息&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* &lt;/span&gt;&lt;span&gt;@return&lt;/span&gt;&lt;span&gt; 优惠券id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;PostMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;seckill&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;addSeckillVoucher&lt;/span&gt;&lt;span&gt;(@&lt;/span&gt;&lt;span&gt;RequestBody&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Voucher&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;voucherService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addSeckillVoucher&lt;/span&gt;&lt;span&gt;(voucher);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;VoucherOrderServiceImpl.java&lt;a href=&quot;#voucherorderserviceimpljava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;seckillVoucher&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; voucherId) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 1.查询优惠卷&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;SeckillVoucher&lt;/span&gt;&lt;span&gt; voucher &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;seckillVoucherService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 2.判断秒杀是否开始&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getBeginTime&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;isAfter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;&lt;span&gt;())&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 尚未开始&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;秒杀尚未开始:&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 3.判断秒杀时候已经结束&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getEndTime&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;isBefore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;&lt;span&gt;())&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;秒杀已经结束:&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 4.判断库存是否充足&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;voucher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 库存不足&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;库存不足&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 5.扣减库存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; success &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;seckillVoucherService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setSql&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;stock = stock - 1&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;voucher_id&quot;&lt;/span&gt;&lt;span&gt;, voucherId)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;success) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 扣减失败&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;库存不足&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.创建订单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;VoucherOrder&lt;/span&gt;&lt;span&gt; voucherOrder &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;VoucherOrder&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.1 订单id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; orderId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisIdWorker&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;nextId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;order&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setId&lt;/span&gt;&lt;span&gt;(orderId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.2 用户id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; userId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UserHolder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getUser&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setUserId&lt;/span&gt;&lt;span&gt;(userId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.3 代金劵id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setVoucherId&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;save&lt;/span&gt;&lt;span&gt;&lt;span&gt;(voucherOrder)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 7 返回订单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(orderId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;商品超卖&lt;a href=&quot;#商品超卖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;原因是查询库存、判断库存和扣减库存不是一个不可分割的原子操作。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;悲观锁&lt;a href=&quot;#悲观锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;悲观锁认为线程安全问题一定会发生，因此操作共享数据前先获取锁，使线程串行执行。&lt;/p&gt;&lt;p&gt;常见实现：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;synchronized&lt;/li&gt;
&lt;li&gt;Lock&lt;/li&gt;
&lt;li&gt;数据库排他锁&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;优点是实现简单、安全性直观；缺点是线程需要等待，并发性能相对较低。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;乐观锁&lt;a href=&quot;#乐观锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;乐观锁不直接加锁，而是在更新数据时判断数据是否已经被其他线程修改。&lt;/p&gt;&lt;p&gt;常见方式：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;版本号法&lt;/li&gt;
&lt;li&gt;CAS法&lt;/li&gt;
&lt;li&gt;使用库存本身作为判断条件&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;版本号法：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UPDATE&lt;/span&gt;&lt;span&gt; tb_seckill_voucher&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET&lt;/span&gt;&lt;span&gt;&lt;span&gt; stock &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stock - &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt; + &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt;&lt;span&gt; voucher_id &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;AND&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ?;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;秒杀库存只需要保证库存不小于0，可以使用stock &amp;gt; 0作为更新条件：&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;VoucherOrderServiceImpl.java&lt;a href=&quot;#voucherorderserviceimpljava-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 5.扣减库存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; success &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;seckillVoucherService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setSql&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;stock = stock - 1&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;voucher_id&quot;&lt;/span&gt;&lt;span&gt;, voucherId).&lt;/span&gt;&lt;span&gt;gt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;stock&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;success) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 扣减失败&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;库存不足&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;一人一单&lt;a href=&quot;#一人一单&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;需求：同一个用户只能购买同一种优惠券一次。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;单机环境加锁&lt;a href=&quot;#单机环境加锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;VoucherOrderServiceImpl.java&lt;a href=&quot;#voucherorderserviceimpljava-2&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; userId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UserHolder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getUser&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;synchronized&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;userId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;intern&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 获取代理对象(事物)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;IVoucherOrderService&lt;/span&gt;&lt;span&gt; proxy &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (IVoucherOrderService) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AopContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentProxy&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;proxy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createVoucherOrder&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;锁对象使用用户ID，能够使同一用户的请求互斥，同时允许不同用户并发下单。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;创建订单&lt;a href=&quot;#创建订单&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;VoucherOrderServiceImpl.java&lt;a href=&quot;#voucherorderserviceimpljava-3&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;createVoucherOrder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; voucherId) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 一人一单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; userId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UserHolder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getUser&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 查询订单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; count &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span&gt;, userId).&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;voucher_id&quot;&lt;/span&gt;&lt;span&gt;, voucherId).&lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 判断是否存在&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (count &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 用户已经购买过了&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;用户已经购买一次&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 5.扣减库存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; success &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;seckillVoucherService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setSql&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;stock = stock - 1&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// set stock = stock - 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;voucher_id&quot;&lt;/span&gt;&lt;span&gt;, voucherId).&lt;/span&gt;&lt;span&gt;gt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;stock&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// where id = ? and stock = ?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;success) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 扣减失败&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;库存不足&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.创建订单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;VoucherOrder&lt;/span&gt;&lt;span&gt; voucherOrder &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;VoucherOrder&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.1 订单id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; orderId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisIdWorker&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;nextId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;order&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setId&lt;/span&gt;&lt;span&gt;(orderId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.2 用户id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setUserId&lt;/span&gt;&lt;span&gt;(userId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 6.3 代金劵id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;voucherOrder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setVoucherId&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;save&lt;/span&gt;&lt;span&gt;&lt;span&gt;(voucherOrder)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 7 返回订单&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(orderId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;HmDianPingApplication.java&lt;a href=&quot;#hmdianpingapplicationjava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 启动类&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EnableAspectJAutoProxy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;exposeProxy&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;MapperScan&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;com.hmdp.mapper&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SpringBootApplication&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HmDianPingApplication&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;[] &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;SpringApplication&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;HmDianPingApplication&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;xml&lt;a href=&quot;#xml&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;org.aspectj&amp;lt;/&lt;/span&gt;&lt;span&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;aspectjweaver&amp;lt;/&lt;/span&gt;&lt;span&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;数据库唯一索引兜底&lt;a href=&quot;#数据库唯一索引兜底&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;即使业务代码已经加锁，也建议在数据库中增加唯一索引：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ALTER&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TABLE&lt;/span&gt;&lt;span&gt; tb_voucher_order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ADD&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CONSTRAINT&lt;/span&gt;&lt;span&gt; uk_user_voucher&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UNIQUE&lt;/span&gt;&lt;span&gt; (user_id, voucher_id);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;唯一索引是“一人一单”的最后一道防线，可以防止程序异常、锁失效或重复消息造成重复订单。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;集群环境中的锁失效问题&lt;a href=&quot;#集群环境中的锁失效问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;集群环境下，请求可能分别进入JVM1和JVM2。每个JVM都有自己的锁监视器，因此两个线程都可能获得各自JVM中的锁。&lt;/p&gt;&lt;p&gt;&lt;code&gt;synchronized&lt;/code&gt;只能保证单个JVM内部互斥，不能解决集群环境中的并发问题。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis分布式锁</title><link>https://aronblake.cloud/posts/redis/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/</guid><description>Redis分布式锁</description><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;分布式锁&lt;a href=&quot;#分布式锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;分布式锁是满足分布式系统或集群模式下多进程可见并且互斥的锁。&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;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;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;MySQL&lt;/td&gt;&lt;td&gt;唯一索引、行锁或排他锁&lt;/td&gt;&lt;td&gt;实现方便，性能通常低于Redis&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Redis&lt;/td&gt;&lt;td&gt;SET NX EX&lt;/td&gt;&lt;td&gt;性能高，需要处理过期和误删问题&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZooKeeper&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;/section&gt;
&lt;section&gt;&lt;h2&gt;基于Redis实现分布式锁&lt;a href=&quot;#基于redis实现分布式锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;ILock.lua&lt;a href=&quot;#ilocklua&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;interface&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ILock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 尝试获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* &lt;/span&gt;&lt;span&gt;@param&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeoutSec&lt;/span&gt;&lt;span&gt; 锁持有的超时时间，过期后自动释放&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* &lt;/span&gt;&lt;span&gt;@return&lt;/span&gt;&lt;span&gt; true代表获取锁成功，false代表获取锁失败&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeoutSec&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 释放锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;SimpleRedisLock.java&lt;a href=&quot;#simpleredislockjava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SimpleRedisLock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ILock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt; stringRedisTemplate&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SimpleRedisLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; name;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stringRedisTemplate;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; KEY_PREFIX&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;lock&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeoutSec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 获取线程标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;success&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;setIfAbsent&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; name, threadId &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;, timeoutSec, &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TRUE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;equals&lt;/span&gt;&lt;span&gt;(success);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 释放锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; name);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;setIfAbsent&lt;/code&gt;同时传入过期时间时，底层相当于一个原子的Redis命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SET lock thread1 NX EX 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;NX保证只有Key不存在时才能获取锁&lt;/li&gt;
&lt;li&gt;EX设置过期时间，避免服务宕机后产生死锁&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;VoucherOrderServiceImpl.java&lt;a href=&quot;#voucherorderserviceimpljava&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; userId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UserHolder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getUser&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 创建锁对象&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;SimpleRedisLock&lt;/span&gt;&lt;span&gt; lock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SimpleRedisLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;order&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; userId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; stringRedisTemplate)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; isLock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1200&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;//  判断是否获取锁成功&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;isLock){&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 获取锁失败，返回错误或重试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;不允许重复下单&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 获取代理对象(事物)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;IVoucherOrderService&lt;/span&gt;&lt;span&gt; proxy &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (IVoucherOrderService) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AopContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentProxy&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;proxy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createVoucherOrder&lt;/span&gt;&lt;span&gt;(voucherId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 释放锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Redis分布式锁误删问题&lt;a href=&quot;#redis分布式锁误删问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1获取锁成功&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1执行时间过长，锁自动过期&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程2获取到同一把锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1执行完成，直接执行DEL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1错误地删除了线程2的锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程3也可以获取锁并进入业务&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;锁中需要保存锁持有者的唯一标识：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UUID + 线程ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;UUID用于区分不同JVM，线程ID用于区分同一个JVM中的不同线程。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;改进Redis的分布锁&lt;a href=&quot;#改进redis的分布锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; ID_PREFIX&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UUID&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;randomUUID&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;-&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 获取线程标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; threadId &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ID_PREFIX&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// 获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; success &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;setIfAbsent&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; threadId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; timeoutSec&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;UUID.randomUUID().toString(true)&lt;/code&gt;是Hutool UUID的写法。如果使用JDK的&lt;code&gt;java.util.UUID&lt;/code&gt;，应写为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;UUID&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;randomUUID&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;SimpleRedisLock.java&lt;a href=&quot;#simpleredislockjava-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 获取线程标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;  threadId&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ID_PREFIX&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 获取锁中的标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; name);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 判断标识是否一致&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;threadId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;equals&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// 释放锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; name);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Redis分布式锁原子性问题&lt;a href=&quot;#redis分布式锁原子性问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;上面的&lt;code&gt;GET&lt;/code&gt;和&lt;code&gt;DEL&lt;/code&gt;是两个独立操作，仍然可能出现：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1执行GET，确认锁属于自己&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1发生阻塞&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;锁到期自动删除&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程2获取锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1恢复执行DEL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;线程1删除了线程2的锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;因此“判断锁标识”和“删除锁”必须作为一个原子操作执行。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Redis的Lua脚本&lt;a href=&quot;#redis的lua脚本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis可以在一个Lua脚本中编写多条Redis命令。Redis会将整个脚本作为一个整体执行，脚本执行期间不会插入其他命令。&lt;/p&gt;&lt;p&gt;基本语法：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;命令名称&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;key&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;其它参数&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;set&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;name&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;jack&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;执行多条命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;set&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;name&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;jack&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;local&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;get&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;name&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;section&gt;&lt;h3&gt;EVAL命令&lt;a href=&quot;#eval命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;EVAL script numkeys key [key ...] arg [arg ...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;固定参数：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;EVAL &quot;return redis.call(&apos;set&apos;, &apos;name&apos;, &apos;jack&apos;)&quot; 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;动态参数：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;EVAL &quot;return redis.call(&apos;set&apos;, KEYS[1], ARGV[1])&quot; 1 name Rose&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;参数对应关系：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1       脚本需要一个Key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;name    放入KEYS[1]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Rose    放入ARGV[1]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Lua数组从1开始，因此使用&lt;code&gt;KEYS[1]&lt;/code&gt;和&lt;code&gt;ARGV[1]&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;使用Lua脚本释放锁&lt;a href=&quot;#使用lua脚本释放锁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;unLock.lua&lt;a href=&quot;#unlocklua&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;--- 比较线程标识与锁中的标识是否一致&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;get&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;KEYS&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]) == &lt;/span&gt;&lt;span&gt;ARGV&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]) &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;--- 释放锁 del key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;del&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;KEYS&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;脚本将读取标识、比较标识和删除锁放在同一次执行中，保证操作的原子性。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Spring调用Lua脚本&lt;a href=&quot;#spring调用lua脚本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;SimpleRedisLock.java&lt;a href=&quot;#simpleredislockjava-2&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DefaultRedisScript&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UNLOCK_SCRIPT&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UNLOCK_SCRIPT &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DefaultRedisScript&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;UNLOCK_SCRIPT&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setLocation&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ClassPathResource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;unLock.lua&quot;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;UNLOCK_SCRIPT&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setResultType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unlock&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 调用lua脚本&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;UNLOCK_SCRIPT,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;singletonList&lt;/span&gt;&lt;span&gt;&lt;span&gt;(KEY_PREFIX&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;name),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ID_PREFIX&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux软件安装、服务管理、环境变量与压缩解压</title><link>https://aronblake.cloud/posts/linux/04-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85%E6%9C%8D%E5%8A%A1%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E5%8E%8B%E7%BC%A9%E8%A7%A3%E5%8E%8B/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/04-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85%E6%9C%8D%E5%8A%A1%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E5%8E%8B%E7%BC%A9%E8%A7%A3%E5%8E%8B/</guid><description>Linux 软件安装、服务管理、环境变量与压缩解压</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;软件安装方式概览&lt;a href=&quot;#软件安装方式概览&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Linux 软件安装常见方式有三类：&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;rpm&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CentOS、RHEL、openEuler 等&lt;/td&gt;&lt;td&gt;安装本地 &lt;code&gt;.rpm&lt;/code&gt; 包，依赖需要额外处理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;yum&lt;/code&gt; / &lt;code&gt;dnf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CentOS、RHEL、Fedora 等&lt;/td&gt;&lt;td&gt;自动处理依赖，适合在线安装&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;apt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Ubuntu、Debian 等&lt;/td&gt;&lt;td&gt;自动处理依赖，Ubuntu 最常用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;入门阶段建议优先掌握 &lt;code&gt;yum&lt;/code&gt; 和 &lt;code&gt;apt&lt;/code&gt;，因为它们会自动处理大部分依赖问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;rpm：本地软件包管理&lt;a href=&quot;#rpm本地软件包管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;安装 rpm 包：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ivh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件包名.rpm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;升级 rpm 包：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-Uvh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件包名.rpm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询软件是否安装：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-q&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件包名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询所有已安装软件包：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-qa&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询软件包详细信息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-qi&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件包名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询软件安装了哪些文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ql&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件包名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询某个文件属于哪个 rpm 包：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-qf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/usr/bin/vim&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;rpm&lt;/code&gt; 的缺点是依赖处理不够方便。比如安装 A 包时，如果它依赖 B、C 包，就需要手动补齐依赖。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;yum：CentOS 常用软件管理&lt;a href=&quot;#yumcentos-常用软件管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;安装软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-y&lt;/code&gt; 表示自动确认。&lt;/p&gt;&lt;p&gt;卸载软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;remove&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;搜索软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;关键字&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看软件信息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;列出可安装和已安装软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;检查可更新软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check-update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;更新全部软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;清理缓存：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;clean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;配置本地 yum 源时，常见步骤是挂载光盘并配置 repo 文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mount&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/dev/sr0&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/mnt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;vi&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc/yum.repos.d/local.repo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例内容：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[local]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;centos7&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;baseurl&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;file:///mnt&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;gpgcheck&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看 yum 源：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;repolist&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;apt：Ubuntu 常用软件管理&lt;a href=&quot;#aptubuntu-常用软件管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Ubuntu 和 Debian 系统常用 &lt;code&gt;apt&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;更新软件源缓存：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;安装软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;卸载软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;remove&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;软件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;搜索软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;apt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;关键字&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;升级系统已安装软件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;upgrade&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;无论是 &lt;code&gt;yum&lt;/code&gt; 还是 &lt;code&gt;apt&lt;/code&gt;，安装和卸载系统软件通常都需要 root 权限。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;wget：命令行下载文件&lt;a href=&quot;#wget命令行下载文件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;wget&lt;/code&gt; 是非交互式下载工具，适合在服务器上下载文件。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wget&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;后台下载：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wget&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-b&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;后台下载日志默认写入当前目录的 &lt;code&gt;wget-log&lt;/code&gt;，可以查看进度：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-f&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;wget-log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;下载并指定保存文件名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wget&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-O&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CentOS-Base.repo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;https://mirrors.aliyun.com/repo/Centos-7.repo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;systemctl：系统服务管理&lt;a href=&quot;#systemctl系统服务管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;systemctl&lt;/code&gt; 用来管理系统服务，比如 nginx、mysql、sshd、ntpd。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;restart&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;disable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;start&lt;/code&gt;&lt;/td&gt;&lt;td&gt;启动服务&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;停止服务&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;restart&lt;/code&gt;&lt;/td&gt;&lt;td&gt;重启服务&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看服务状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置开机自启&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;&lt;td&gt;关闭开机自启&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sshd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;restart&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;排查服务问题时，通常先看状态，再看日志：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;journalctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;软链接：ln -s&lt;a href=&quot;#软链接ln--s&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;软链接类似快捷方式。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ln&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;源文件或目录&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;链接位置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ln&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/usr/local/nginx/sbin/nginx&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/usr/bin/nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样就可以直接执行 &lt;code&gt;nginx&lt;/code&gt;，不用每次输入完整路径。&lt;/p&gt;&lt;p&gt;查看软链接：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;软链接前面通常会显示 &lt;code&gt;-&amp;gt;&lt;/code&gt; 指向原路径。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;日期、时区和时间同步&lt;a href=&quot;#日期时区和时间同步&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看当前时间：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;date&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;格式化输出：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;+%Y-%m-%d&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;+%Y-%m-%d %H:%M:%S&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%Y&lt;/code&gt;&lt;/td&gt;&lt;td&gt;四位年份&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%y&lt;/code&gt;&lt;/td&gt;&lt;td&gt;两位年份&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%m&lt;/code&gt;&lt;/td&gt;&lt;td&gt;月&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;日&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%H&lt;/code&gt;&lt;/td&gt;&lt;td&gt;小时&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%M&lt;/code&gt;&lt;/td&gt;&lt;td&gt;分钟&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%S&lt;/code&gt;&lt;/td&gt;&lt;td&gt;秒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;%s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Unix 时间戳&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;修改时区可以使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;timedatectl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;set-timezone&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Asia/Shanghai&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;安装 NTP：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ntp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;启动 NTP 服务：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ntpd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ntpd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;手动校准时间：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ntpdate&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ntp.aliyun.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;环境变量和 PATH&lt;a href=&quot;#环境变量和-path&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看全部环境变量：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;env&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看某个变量：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;$PATH&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;临时设置变量：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;APP_HOME&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;临时变量只在当前终端有效。想永久生效，可以写入：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;用户级配置：&lt;code&gt;~/.bashrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;全局配置：&lt;code&gt;/etc/profile&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;code&gt;PATH&lt;/code&gt; 记录了系统查找可执行命令的路径。比如把自定义脚本目录加入 PATH：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PATH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$PATH&lt;/span&gt;&lt;span&gt;:/&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;scripts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果变量名后面要紧跟其他字符，建议使用 &lt;code&gt;${}&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;PATH&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ABC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;压缩和解压&lt;a href=&quot;#压缩和解压&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;使用 &lt;code&gt;tar&lt;/code&gt; 打包压缩：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-zcvf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;archive.tar.gz&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file1&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dir1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-z&lt;/code&gt;&lt;/td&gt;&lt;td&gt;使用 gzip&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建归档&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显示过程&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定文件名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看归档内容&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-x&lt;/code&gt;&lt;/td&gt;&lt;td&gt;解包&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定解压目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;查看压缩包内容：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-tf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;archive.tar.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;解压：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-zxvf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;archive.tar.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-zxvf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;archive.tar.gz&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-C&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/opt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;zip&lt;/code&gt; 压缩：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;project.zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;unzip&lt;/code&gt; 解压：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;unzip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.zip&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;unzip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/opt/project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;rpm -ivh 包名.rpm&lt;/code&gt;&lt;/td&gt;&lt;td&gt;安装 rpm 包&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;yum install -y 软件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CentOS 安装软件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;apt install 软件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Ubuntu 安装软件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;wget URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;下载文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;systemctl status 服务&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看服务状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;systemctl enable 服务&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置服务开机自启&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ln -s 源 链接&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建软链接&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;date &quot;+%Y-%m-%d&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;格式化时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;env&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看环境变量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;echo $PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看 PATH&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tar -zcvf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;打包压缩&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tar -zxvf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;解压&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;zip -r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;zip 压缩目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;unzip -d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;解压 zip 到指定目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux网络、进程与系统资源排查常用命令</title><link>https://aronblake.cloud/posts/linux/05-%E7%BD%91%E7%BB%9C%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%B3%BB%E7%BB%9F%E8%B5%84%E6%BA%90%E6%8E%92%E6%9F%A5/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/05-%E7%BD%91%E7%BB%9C%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%B3%BB%E7%BB%9F%E8%B5%84%E6%BA%90%E6%8E%92%E6%9F%A5/</guid><description>Linux 网络、进程与系统资源排查常用命令</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;IP 地址基础&lt;a href=&quot;#ip-地址基础&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;IPv4 地址通常是类似下面这样的格式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;192.168.1.10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每一段的范围是 &lt;code&gt;0&lt;/code&gt; 到 &lt;code&gt;255&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;本机回环地址，只代表当前机器&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;localhost&lt;/code&gt;&lt;/td&gt;&lt;td&gt;通常解析到 &lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;0.0.0.0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在服务监听中常表示监听所有网卡&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;例如服务监听 &lt;code&gt;127.0.0.1:8080&lt;/code&gt;，通常只能本机访问；监听 &lt;code&gt;0.0.0.0:8080&lt;/code&gt;，其他机器才可能通过服务器 IP 访问。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看 IP 地址&lt;a href=&quot;#查看-ip-地址&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;老系统常用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ifconfig&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果提示命令不存在，可以安装 &lt;code&gt;net-tools&lt;/code&gt;，或者使用更现代的命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;addr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;简写：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看默认路由：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;route&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;主机名&lt;a href=&quot;#主机名&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看主机名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;设置主机名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;hostnamectl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;set-hostname&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;新主机名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;主机名常用于区分多台服务器，比如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;web-01&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;web-02&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;db-01&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;测试网络连通：ping&lt;a href=&quot;#测试网络连通ping&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ping&lt;/code&gt; 用于测试网络是否连通。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ping&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目标地址&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;限制次数：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ping&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;baidu.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ping&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.1.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果 IP 能 ping 通，域名不能 ping 通，可能是 DNS 问题。如果都不通，可能是网络、网关、防火墙或目标机器问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;下载和接口测试：curl&lt;a href=&quot;#下载和接口测试curl&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; 常用于测试 HTTP 接口。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://127.0.0.1:8080&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看响应头：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-I&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;https://example.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;发送 POST 请求：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-X&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://127.0.0.1:8080/api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;排查 Web 服务时，常见顺序是：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;systemctl status 服务名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netstat&lt;/code&gt; 或 &lt;code&gt;ss&lt;/code&gt; 查看端口是否监听&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl 127.0.0.1:端口&lt;/code&gt; 测试本机访问&lt;/li&gt;
&lt;li&gt;从其他机器访问服务器 IP 和端口&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看端口占用：netstat 和 ss&lt;a href=&quot;#查看端口占用netstat-和-ss&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;老系统常用 &lt;code&gt;netstat&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;netstat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-anp&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;端口&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;netstat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-anp&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;现代系统更推荐 &lt;code&gt;ss&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ss&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-lntp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ss&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-lntp&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只看监听端口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;不解析服务名，直接显示数字端口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UDP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显示进程信息&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;如果端口没有监听，说明服务可能没启动或启动失败。如果端口已经被其他进程占用，新服务可能无法启动。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看进程：ps&lt;a href=&quot;#查看进程ps&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看全部进程：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ef&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;配合 &lt;code&gt;grep&lt;/code&gt; 过滤：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ef&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ef&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;进程所属用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;PID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;进程 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;PPID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;父进程 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CMD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;启动命令&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;查看某个进程的详细状态：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PID&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-f&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;结束进程：kill&lt;a href=&quot;#结束进程kill&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;结束进程：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;kill&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;强制结束：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;kill&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-9&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;建议优先使用普通 &lt;code&gt;kill&lt;/code&gt;，让进程有机会正常退出。&lt;code&gt;kill -9&lt;/code&gt; 是强制终止，可能导致临时文件、锁文件或数据状态来不及清理。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;实时查看系统状态：top&lt;a href=&quot;#实时查看系统状态top&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;top&lt;/code&gt; 可以实时查看系统运行状态。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;top&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;load average&lt;/td&gt;&lt;td&gt;系统负载&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU 使用率&lt;/td&gt;&lt;td&gt;用户态、系统态、空闲比例&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mem&lt;/td&gt;&lt;td&gt;内存使用情况&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Swap&lt;/td&gt;&lt;td&gt;交换分区使用情况&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PID&lt;/td&gt;&lt;td&gt;进程 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%CPU&lt;/td&gt;&lt;td&gt;进程 CPU 占用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%MEM&lt;/td&gt;&lt;td&gt;进程内存占用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;P&lt;/code&gt;&lt;/td&gt;&lt;td&gt;按 CPU 占用排序&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;M&lt;/code&gt;&lt;/td&gt;&lt;td&gt;按内存占用排序&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;&lt;td&gt;退出&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;如果某个进程 CPU 或内存异常高，可以记录 PID，再结合日志继续排查。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看磁盘占用：df 和 du&lt;a href=&quot;#查看磁盘占用df-和-du&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看磁盘分区使用情况：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;df&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-h&lt;/code&gt; 表示用人类易读的单位显示。&lt;/p&gt;&lt;p&gt;查看目录大小：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;du&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-sh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看当前目录下各文件和子目录大小：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;du&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-sh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;磁盘满了时，常见排查路径：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;df&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;du&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-sh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;du&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-sh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;逐层定位哪个目录占用最大。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看磁盘和 CPU IO：iostat&lt;a href=&quot;#查看磁盘和-cpu-ioiostat&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;iostat&lt;/code&gt; 可以查看 CPU 和磁盘 IO 情况，常用于排查磁盘读写压力。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;iostat&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;iostat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果系统没有该命令，CentOS 可安装：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;yum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sysstat&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看网络统计：sar&lt;a href=&quot;#查看网络统计sar&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;sar&lt;/code&gt; 也来自 &lt;code&gt;sysstat&lt;/code&gt; 工具包，可以查看网络、CPU、内存等历史统计。&lt;/p&gt;&lt;p&gt;查看网络设备统计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DEV&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看 TCP 统计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TCP&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sar&lt;/code&gt; 更偏系统性能分析，入门阶段先知道它能查看历史和实时统计即可。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;固定 IP 配置思路&lt;a href=&quot;#固定-ip-配置思路&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在虚拟机或服务器中配置固定 IP，通常涉及两部分：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;虚拟化平台或云平台的网络配置。&lt;/li&gt;
&lt;li&gt;Linux 系统内部网卡配置。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;CentOS 7 常见配置文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/etc/sysconfig/network-scripts/ifcfg-ens33&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;核心配置示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;BOOTPROTO&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;static&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ONBOOT&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;yes&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;IPADDR&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;192.168.88.131&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;NETMASK&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;255.255.255.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GATEWAY&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;192.168.88.2&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;DNS1&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;192.168.88.2&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;配置后通常需要重启网络服务或重启机器。不同发行版网络配置方式差异较大，实际操作前要确认系统版本。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;常见排查套路&lt;a href=&quot;#常见排查套路&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;服务访问不了时：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ef&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;服务关键字&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ss&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-lntp&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;端口&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://127.0.0.1:端口&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ping&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目标IP&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;机器变慢时：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;top&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;df&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;free&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-h&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;iostat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;日志异常时：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-f&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;ERROR&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;ip addr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看 IP 地址&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;hostname&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看主机名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;hostnamectl set-hostname&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置主机名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ping -c 4 地址&lt;/code&gt;&lt;/td&gt;&lt;td&gt;测试连通性&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;curl URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;测试 HTTP 请求&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;netstat -anp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看网络连接和端口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ss -lntp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看监听端口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ps -ef&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看进程&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;kill PID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;结束进程&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;top&lt;/code&gt;&lt;/td&gt;&lt;td&gt;实时查看系统状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看磁盘分区占用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;du -sh *&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看目录大小&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;iostat -x 1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看磁盘 IO&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sar -n DEV 1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看网络统计&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux用户、用户组、权限与 sudo 管理</title><link>https://aronblake.cloud/posts/linux/06-%E7%94%A8%E6%88%B7%E7%BB%84%E6%9D%83%E9%99%90%E5%92%8Csudo%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/06-%E7%94%A8%E6%88%B7%E7%BB%84%E6%9D%83%E9%99%90%E5%92%8Csudo%E7%AE%A1%E7%90%86/</guid><description>Linux 用户、用户组、权限与 sudo 管理</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;用户和用户组的关系&lt;a href=&quot;#用户和用户组的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Linux 中每个用户都有一个 UID，每个用户组都有一个 GID。&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看当前用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;whoami&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看系统用户信息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;passwd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看系统用户组信息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;group&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;创建用户：useradd&lt;a href=&quot;#创建用户useradd&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;创建用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;useradd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定描述信息&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定 UID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定用户家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-m&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-g&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定主组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-G&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定附加组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-M&lt;/code&gt;&lt;/td&gt;&lt;td&gt;不创建家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定登录 Shell&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;useradd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/home/testuser&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/bin/bash&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testuser&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;创建用户后设置密码：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;passwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testuser&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;管理密码状态：passwd 和 chage&lt;a href=&quot;#管理密码状态passwd-和-chage&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;修改用户密码：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;passwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看密码过期信息：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;强制用户下次登录修改密码：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;锁定用户密码：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;passwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;解锁用户密码：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;passwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;删除用户：userdel&lt;a href=&quot;#删除用户userdel&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;删除用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;userdel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除用户并删除家目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;userdel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除用户是高风险操作，尤其是带 &lt;code&gt;-r&lt;/code&gt; 时会删除家目录。执行前建议确认该用户是否仍有业务文件或运行中的进程。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;修改用户：usermod&lt;a href=&quot;#修改用户usermod&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;usermod&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改描述信息&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改 UID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-m&lt;/code&gt;&lt;/td&gt;&lt;td&gt;移动家目录内容到新位置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-g&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改主组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-G&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改附加组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-aG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;追加附加组，常用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改登录 Shell&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-e&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置账号过期时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改账号名称&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-L&lt;/code&gt;&lt;/td&gt;&lt;td&gt;锁定用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-U&lt;/code&gt;&lt;/td&gt;&lt;td&gt;解锁用户&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;把用户加入附加组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;usermod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-aG&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testuser&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这里推荐使用 &lt;code&gt;-aG&lt;/code&gt;，表示追加附加组。如果只用 &lt;code&gt;-G&lt;/code&gt;，可能会覆盖用户原有附加组。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;用户组管理&lt;a href=&quot;#用户组管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;创建用户组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;groupadd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;组名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;指定 GID：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;groupadd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-g&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1001&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除用户组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;groupdel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;组名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;把用户加入组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;gpasswd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;组名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;从组中移除用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;gpasswd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;组名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看某个组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;group&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;组名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;文件权限怎么看&lt;a href=&quot;#文件权限怎么看&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;使用 &lt;code&gt;ls -l&lt;/code&gt; 查看文件权限：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;-rw-r--r-- 1 aron dev 1024 Jul 9 10:00 file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;第一段 &lt;code&gt;-rw-r--r--&lt;/code&gt; 表示权限：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;-   rw-   r--   r--&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;类型 所有者 所属组 其他人&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;td&gt;普通文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;软链接&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;对文件&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;r&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;w&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;x&lt;/code&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;code&gt;x&lt;/code&gt; 权限很重要。没有 &lt;code&gt;x&lt;/code&gt;，即使有 &lt;code&gt;r&lt;/code&gt;，也可能无法进入目录。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;chmod：修改权限&lt;a href=&quot;#chmod修改权限&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;符号方式：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;u+x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;script.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g-w&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o+r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a+r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;所有者&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;g&lt;/code&gt;&lt;/td&gt;&lt;td&gt;所属组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;o&lt;/code&gt;&lt;/td&gt;&lt;td&gt;其他人&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;所有人&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;&lt;td&gt;增加权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置为指定权限&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;数值&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;w&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;x&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;常见权限：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;755&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;script.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;644&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;700&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;private-dir&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;755&lt;/code&gt;&lt;/td&gt;&lt;td&gt;所有者可读写执行，组和其他人可读执行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;644&lt;/code&gt;&lt;/td&gt;&lt;td&gt;所有者可读写，组和其他人只读&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;700&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只有所有者可读写执行&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;递归修改目录及其内容：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-R&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;755&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;递归操作要谨慎，不建议随意对系统目录执行 &lt;code&gt;chmod -R&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;chown：修改所有者和所属组&lt;a href=&quot;#chown修改所有者和所属组&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;修改文件所有者：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chown&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;修改所有者和所属组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chown&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户:用户组&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;递归修改目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chown&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-R&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户:用户组&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chown&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-R&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx:nginx&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/www/html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;特殊权限：SGID 和粘滞位&lt;a href=&quot;#特殊权限sgid-和粘滞位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;SGID 常用于共享目录。对目录设置 SGID 后，用户在该目录中新建的文件会继承目录的所属组。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g+s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;适合多人协作目录，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g+s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/data/project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;粘滞位常用于公共可写目录。即使用户对目录有写权限，也不能删除其他用户的文件。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o+t&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;取消粘滞位：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o-t&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;典型例子是 &lt;code&gt;/tmp&lt;/code&gt; 目录。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;ACL：更细粒度的权限控制&lt;a href=&quot;#acl更细粒度的权限控制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;传统权限只能控制所有者、所属组、其他人。ACL 可以针对指定用户或指定组设置额外权限。&lt;/p&gt;&lt;p&gt;给用户设置 ACL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;u:用户名:权限&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;给用户组设置 ACL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g:组名:权限&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除某个 ACL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;u:用户名&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g:组名&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除全部 ACL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-b&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看 ACL：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;setfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;u:alice:rw&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;su 和 sudo&lt;a href=&quot;#su-和-sudo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;su&lt;/code&gt; 用于切换用户：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;su&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;用户名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;切换到 root：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;su&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-&lt;/code&gt; 表示同时切换用户环境，更接近完整登录该用户。&lt;/p&gt;&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; 用于以管理员权限执行单条命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;restart&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;配置 sudo 权限建议使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;visudo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;testuser ALL=(ALL) NOPASSWD: ALL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这表示 &lt;code&gt;testuser&lt;/code&gt; 可以免密执行所有 sudo 命令。生产环境中不建议随意给 &lt;code&gt;NOPASSWD: ALL&lt;/code&gt;，应按最小权限原则授权。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;权限排查思路&lt;a href=&quot;#权限排查思路&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;遇到权限不足时，可以按这个顺序排查：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;当前用户是谁：&lt;code&gt;whoami&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;当前用户属于哪些组：&lt;code&gt;id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;文件或目录权限是什么：&lt;code&gt;ls -l&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;上级目录是否有执行权限：逐级检查目录权限&lt;/li&gt;
&lt;li&gt;是否存在 ACL：&lt;code&gt;getfacl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;是否需要 sudo 或切换用户&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;whoami&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ld&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ld&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/data/project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/data/project/app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;getfacl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/data/project/app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;很多权限问题并不是文件本身没权限，而是上级目录缺少 &lt;code&gt;x&lt;/code&gt; 权限。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;












































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;id 用户名&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看用户 UID、GID 和所属组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;whoami&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看当前用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;getent passwd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看系统用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;getent group&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看系统用户组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;useradd 用户&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;passwd 用户&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置用户密码&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;userdel -r 用户&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除用户及家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;usermod -aG 组 用户&lt;/code&gt;&lt;/td&gt;&lt;td&gt;追加附加组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;groupadd 组&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建用户组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;gpasswd -a 用户 组&lt;/code&gt;&lt;/td&gt;&lt;td&gt;添加用户到组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ls -l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;chmod 755 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;chown 用户:组 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;修改所有者和所属组&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;setfacl -m&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设置 ACL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;getfacl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看 ACL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;su - 用户&lt;/code&gt;&lt;/td&gt;&lt;td&gt;切换用户&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sudo 命令&lt;/code&gt;&lt;/td&gt;&lt;td&gt;以管理员权限执行命令&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux目录结构、路径与终端基本认知</title><link>https://aronblake.cloud/posts/linux/01-linux%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E4%B8%8E%E8%B7%AF%E5%BE%84%E5%9F%BA%E7%A1%80/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/01-linux%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E4%B8%8E%E8%B7%AF%E5%BE%84%E5%9F%BA%E7%A1%80/</guid><description>Linux 入门：目录结构、路径与终端基本认知</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;Linux 的目录结构&lt;a href=&quot;#linux-的目录结构&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Linux 只有一个顶级目录，也就是根目录 &lt;code&gt;/&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;根目录，Linux 文件系统的起点&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/home&lt;/code&gt;&lt;/td&gt;&lt;td&gt;普通用户的家目录所在位置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/root&lt;/code&gt;&lt;/td&gt;&lt;td&gt;root 用户的家目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/etc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;系统和软件配置文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/var&lt;/code&gt;&lt;/td&gt;&lt;td&gt;日志、缓存、运行时数据等经常变化的文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/usr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;用户级软件、命令、库文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/bin&lt;/code&gt;、&lt;code&gt;/sbin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;常用系统命令&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/tmp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;临时文件目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/home/user/a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;表示从根目录 &lt;code&gt;/&lt;/code&gt; 开始，依次进入 &lt;code&gt;home&lt;/code&gt; 目录、&lt;code&gt;user&lt;/code&gt; 目录，最后找到 &lt;code&gt;a.txt&lt;/code&gt; 文件。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;HOME 目录&lt;a href=&quot;#home-目录&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;每个用户在 Linux 中通常都有自己的专属工作目录，也叫 HOME 目录。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;普通用户的 HOME 目录通常是 &lt;code&gt;/home/用户名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;root 用户的 HOME 目录是 &lt;code&gt;/root&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;终端刚登录后，默认通常会进入当前用户的 HOME 目录&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;可以使用 &lt;code&gt;pwd&lt;/code&gt; 查看当前位置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pwd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果当前登录用户是 &lt;code&gt;aron&lt;/code&gt;，输出可能是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/home/aron&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;绝对路径和相对路径&lt;a href=&quot;#绝对路径和相对路径&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;路径是 Linux 中非常重要的概念。它分为绝对路径和相对路径。&lt;/p&gt;&lt;p&gt;绝对路径从根目录 &lt;code&gt;/&lt;/code&gt; 开始描述位置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/home/aron/test/a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不管你当前在哪个目录，这个路径指向的位置都固定不变。&lt;/p&gt;&lt;p&gt;相对路径不以 &lt;code&gt;/&lt;/code&gt; 开头，它以当前所在目录作为起点：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;test/a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果当前目录是 &lt;code&gt;/home/aron&lt;/code&gt;，那么 &lt;code&gt;test/a.txt&lt;/code&gt; 实际指向：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/home/aron/test/a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;特殊路径符&lt;a href=&quot;#特殊路径符&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Linux 中有几个很常见的特殊路径符。&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;.&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;./a.txt&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;..&lt;/code&gt;&lt;/td&gt;&lt;td&gt;上一级目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;cd ..&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;../..&lt;/code&gt;&lt;/td&gt;&lt;td&gt;上两级目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;cd ../..&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;~&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前用户 HOME 目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;cd ~&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;例如，回到用户 HOME 目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;进入上一级目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;执行当前目录下的脚本：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;./start.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;./&lt;/code&gt; 表示“当前目录下”。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;隐藏文件和隐藏目录&lt;a href=&quot;#隐藏文件和隐藏目录&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Linux 中，以 &lt;code&gt;.&lt;/code&gt; 开头的文件或目录默认是隐藏的，例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;.bashrc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;.ssh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;.vimrc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;普通 &lt;code&gt;ls&lt;/code&gt; 看不到隐藏文件，需要加 &lt;code&gt;-a&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;很多用户配置、软件配置、SSH 密钥都会放在隐藏文件或隐藏目录里，所以排查环境变量、登录配置、密钥问题时经常会用到 &lt;code&gt;ls -a&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看命令帮助&lt;a href=&quot;#查看命令帮助&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看简要帮助：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;命令&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--help&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--help&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看详细手册：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;man&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;命令&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;man&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ls&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;man&lt;/code&gt; 手册中按 &lt;code&gt;q&lt;/code&gt; 可以退出。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;




































&lt;table&gt;&lt;thead&gt;&lt;tr&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;pwd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看当前工作目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cd 目录&lt;/code&gt;&lt;/td&gt;&lt;td&gt;切换目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cd ~&lt;/code&gt;&lt;/td&gt;&lt;td&gt;回到当前用户 HOME 目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cd ..&lt;/code&gt;&lt;/td&gt;&lt;td&gt;回到上一级目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ls -a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看包含隐藏文件在内的目录内容&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;命令 --help&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看命令简要帮助&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;man 命令&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看命令详细手册&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux文件与目录操作</title><link>https://aronblake.cloud/posts/linux/02-%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/02-%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C/</guid><description>Linux 文件与目录操作：ls、cd、mkdir、cp、mv、rm</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;查看目录内容：ls&lt;a href=&quot;#查看目录内容ls&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ls&lt;/code&gt; 用来列出目录中的文件和子目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; [选项] [目录]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不写目录时，默认查看当前目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;以长格式显示详细信息&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-h&lt;/code&gt;&lt;/td&gt;&lt;td&gt;配合 &lt;code&gt;-l&lt;/code&gt;，用更易读的方式显示文件大小&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显示隐藏文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只显示目录本身，不展开目录内容&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;按修改时间排序&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;常见组合：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-lh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-la&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ld&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-lt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;ls -lh&lt;/code&gt; 很常用，可以看到权限、所属用户、所属组、大小、修改时间等信息。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看当前位置：pwd&lt;a href=&quot;#查看当前位置pwd&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;pwd&lt;/code&gt; 用来显示当前工作目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pwd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;切换目录：cd&lt;a href=&quot;#切换目录cd&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; 用来切换工作目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; [目标目录]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;常用写法：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;../logs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;不带参数的 &lt;code&gt;cd&lt;/code&gt; 默认回到当前用户的 HOME 目录。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;创建目录：mkdir&lt;a href=&quot;#创建目录mkdir&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt; 用来创建目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目录名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果要一次性创建多级目录，使用 &lt;code&gt;-p&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;project/logs/nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果不加 &lt;code&gt;-p&lt;/code&gt;，上级目录不存在时会报错。&lt;/p&gt;&lt;p&gt;有些 Shell 支持用大括号批量创建目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;project/{bin,conf,logs,data}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这会创建：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;project/bin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;project/conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;project/logs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;project/data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;创建空文件：touch&lt;a href=&quot;#创建空文件touch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;touch&lt;/code&gt; 常用于创建空文件，也可以更新文件的修改时间。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;touch&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;touch&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;touch&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;README.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果文件不存在，会创建空文件；如果文件已经存在，会更新它的时间戳。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;复制文件和目录：cp&lt;a href=&quot;#复制文件和目录cp&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;cp&lt;/code&gt; 用来复制文件或目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; [选项] 源 目标&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;复制文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;b.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;复制文件到目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;复制目录需要加 &lt;code&gt;-r&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;递归复制目录及其内容&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;强制覆盖&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;保留源文件属性&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;实际工作中，如果复制配置文件，常见做法是先备份：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx.conf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx.conf.bak&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;再修改原文件，这样出问题时可以快速恢复。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;移动和重命名：mv&lt;a href=&quot;#移动和重命名mv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;mv&lt;/code&gt; 既可以移动文件，也可以重命名文件。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;源&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;目标&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;重命名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;old.txt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;移动到目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;logs/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;移动并改名：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;logs/app-2026.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;覆盖前询问&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;强制覆盖&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;不覆盖已存在文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;源文件更新或目标不存在时才移动&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;覆盖前创建备份&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;对重要文件执行 &lt;code&gt;mv&lt;/code&gt; 时，可以用 &lt;code&gt;-i&lt;/code&gt; 降低误覆盖风险：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-i&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config.yml&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config.yml.bak&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;删除文件和目录：rm&lt;a href=&quot;#删除文件和目录rm&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;rm&lt;/code&gt; 用来删除文件或目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rm&lt;/span&gt;&lt;span&gt; [选项] 文件或目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;删除目录需要加 &lt;code&gt;-r&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;递归删除目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;强制删除，不提示&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除前逐个确认&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;rm&lt;/code&gt; 是高风险命令，尤其是 &lt;code&gt;rm -rf&lt;/code&gt;。执行前建议先用 &lt;code&gt;ls&lt;/code&gt; 确认目标：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;rm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;




















































&lt;table&gt;&lt;thead&gt;&lt;tr&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;ls -lh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看详细文件列表&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ls -a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看隐藏文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看当前位置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cd 目录&lt;/code&gt;&lt;/td&gt;&lt;td&gt;切换目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;mkdir -p 目录&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建多级目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;touch 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建空文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cp 源 目标&lt;/code&gt;&lt;/td&gt;&lt;td&gt;复制文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cp -r 源目录 目标目录&lt;/code&gt;&lt;/td&gt;&lt;td&gt;复制目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;mv 源 目标&lt;/code&gt;&lt;/td&gt;&lt;td&gt;移动或重命名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;rm 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;rm -r 目录&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Linux文本处理基础</title><link>https://aronblake.cloud/posts/linux/03-%E6%96%87%E6%9C%AC%E6%9F%A5%E7%9C%8B%E7%BC%96%E8%BE%91%E7%AE%A1%E9%81%93%E9%87%8D%E5%AE%9A%E5%90%91/</link><guid isPermaLink="true">https://aronblake.cloud/posts/linux/03-%E6%96%87%E6%9C%AC%E6%9F%A5%E7%9C%8B%E7%BC%96%E8%BE%91%E7%AE%A1%E9%81%93%E9%87%8D%E5%AE%9A%E5%90%91/</guid><description>Linux 文本处理基础：查看、编辑、搜索、管道与重定向</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;查看完整文件：cat&lt;a href=&quot;#查看完整文件cat&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;cat&lt;/code&gt; 会把文件内容直接输出到终端。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显示所有行行号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只给非空行编号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;将连续空行压缩为一行&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;cat&lt;/code&gt; 适合查看内容不长的文件。如果文件很大，建议使用 &lt;code&gt;less&lt;/code&gt;、&lt;code&gt;more&lt;/code&gt;、&lt;code&gt;head&lt;/code&gt; 或 &lt;code&gt;tail&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;分页查看：more 和 less&lt;a href=&quot;#分页查看more-和-less&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;more&lt;/code&gt; 可以分页查看文件。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;more&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&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;/tr&gt;&lt;tr&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;b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;上一页&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;&lt;td&gt;退出&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;less&lt;/code&gt; 功能更强，也更常用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;less&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&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;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;上一页&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/关键字&lt;/code&gt;&lt;/td&gt;&lt;td&gt;搜索关键字&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;下一个匹配&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;上一个匹配&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;&lt;td&gt;退出&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;查看日志或配置文件时，&lt;code&gt;less&lt;/code&gt; 比 &lt;code&gt;cat&lt;/code&gt; 更稳，因为它不会一次性刷满终端。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查看文件开头和结尾：head、tail&lt;a href=&quot;#查看文件开头和结尾headtail&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;查看文件前几行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看文件最后几行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;持续跟踪文件变化：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-f&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tail -f&lt;/code&gt; 是看实时日志的常用命令。退出时按 &lt;code&gt;Ctrl+C&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;搜索文件内容：grep&lt;a href=&quot;#搜索文件内容grep&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; 用来按关键字过滤文本。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; [选项] 关键字 文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;显示匹配行号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;反向匹配，显示不包含关键字的行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;忽略大小写&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;递归搜索目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-i&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;failed&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;#&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;server_name&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc/nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;一些常用匹配：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;^root&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc/passwd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;bash$&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc/passwd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;^$&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义分别是：匹配以 &lt;code&gt;root&lt;/code&gt; 开头的行、匹配以 &lt;code&gt;bash&lt;/code&gt; 结尾的行、匹配空行。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;查找文件：find&lt;a href=&quot;#查找文件find&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;find&lt;/code&gt; 用来在目录中查找文件或目录。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;路径&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;条件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;按名称查找：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;*.conf&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;按类型查找：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/home&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;按大小查找：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-size&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+100M&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;普通文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;目录&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;find&lt;/code&gt; 的搜索范围越大，耗时越长。实际使用时最好先限定目录，比如从 &lt;code&gt;/var/log&lt;/code&gt;、&lt;code&gt;/etc&lt;/code&gt;、项目目录开始。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;统计文本：wc&lt;a href=&quot;#统计文本wc&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;wc&lt;/code&gt; 用来统计文件内容。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wc&lt;/span&gt;&lt;span&gt; [选项] 文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计行数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-w&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计单词数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计字节数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-m&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计字符数&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;wc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-w&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;article.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;配合管道可以统计搜索结果：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;ERROR&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;wc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这表示统计日志中包含 &lt;code&gt;ERROR&lt;/code&gt; 的行数。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;管道符：|&lt;a href=&quot;#管道符&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;管道符 &lt;code&gt;|&lt;/code&gt; 的作用是把左边命令的输出，作为右边命令的输入。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;命令1&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;命令2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;ERROR&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ps&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-ef&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/etc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;*.conf&quot;&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;wc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-l&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;管道可以连续使用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cat&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;ERROR&quot;&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;timeout&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这表示先找出包含 &lt;code&gt;ERROR&lt;/code&gt; 的日志，再从结果中找出包含 &lt;code&gt;timeout&lt;/code&gt; 的行。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;输出和重定向：echo、&amp;gt;、&amp;gt;&amp;gt;&lt;a href=&quot;#输出和重定向echo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;echo&lt;/code&gt; 用来输出内容：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;hello linux&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;&amp;gt;&lt;/code&gt; 可以覆盖写入文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;hello&quot;&lt;/span&gt;&lt;span&gt; &amp;gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; 可以追加写入文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;world&quot;&lt;/span&gt;&lt;span&gt; &amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;a.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;错误输出可以使用 &lt;code&gt;2&amp;gt;&lt;/code&gt; 重定向：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/not-exist&lt;/span&gt;&lt;span&gt; 2&amp;gt; &lt;/span&gt;&lt;span&gt;error.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;code&gt;&amp;gt;&lt;/code&gt; 会覆盖文件原内容，写配置或日志时要确认是否真的需要覆盖。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;反引号和命令替换&lt;a href=&quot;#反引号和命令替换&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;被反引号包围的内容会作为命令执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;pwd&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;输出当前工作目录。&lt;/p&gt;&lt;p&gt;现代 Shell 中更推荐使用 &lt;code&gt;$()&lt;/code&gt;，可读性更好：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;$(&lt;/span&gt;&lt;span&gt;pwd&lt;/span&gt;&lt;span&gt;)&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;例如创建带日期的备份文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app.log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;app-$(&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; +%Y%m%d).log&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;vim 编辑器入门&lt;a href=&quot;#vim-编辑器入门&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;vim&lt;/code&gt; 是 Linux 中非常常见的文本编辑器。它至少要理解三种模式：&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&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;/tr&gt;&lt;tr&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;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&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;i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在光标前插入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在光标后插入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;o&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在下一行插入新行&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;G&lt;/code&gt;&lt;/td&gt;&lt;td&gt;跳到最后一行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;50gg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;跳到第 50 行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;10dd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;删除 10 行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;10yy&lt;/code&gt;&lt;/td&gt;&lt;td&gt;复制 10 行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;粘贴&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;末行模式常用操作：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nonu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:w&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:q&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:wq&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:q!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义分别是显示行号、取消行号、保存、退出、保存并退出、强制退出不保存。&lt;/p&gt;&lt;p&gt;文本替换：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:s&lt;/span&gt;&lt;span&gt;/old/&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:s&lt;/span&gt;&lt;span&gt;/old/&lt;/span&gt;&lt;span&gt;new/g&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;:%s&lt;/span&gt;&lt;span&gt;/old/&lt;/span&gt;&lt;span&gt;new/g&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;含义分别是替换当前行第一个匹配、替换当前行所有匹配、替换全文所有匹配。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;本篇命令速查&lt;a href=&quot;#本篇命令速查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
























































&lt;table&gt;&lt;thead&gt;&lt;tr&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;cat -n 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看文件并显示行号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;less 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;分页查看文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;head -n 20 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看前 20 行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tail -n 50 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查看最后 50 行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tail -f 日志&lt;/code&gt;&lt;/td&gt;&lt;td&gt;实时跟踪日志&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;grep -n 关键字 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;搜索关键字并显示行号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;find 路径 -name 名称&lt;/code&gt;&lt;/td&gt;&lt;td&gt;按名称查找&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;wc -l 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;统计行数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`命令1&lt;/td&gt;&lt;td&gt;命令2`&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;echo 内容 &amp;gt; 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;覆盖写入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;echo 内容 &amp;gt;&amp;gt; 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;追加写入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;vim 文件&lt;/code&gt;&lt;/td&gt;&lt;td&gt;编辑文件&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis缓存和更新</title><link>https://aronblake.cloud/posts/redis/rediscache/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/rediscache/</guid><description>Redis缓存介绍，缓存更新</description><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;缓存是数据交换的缓冲区，用来临时存储热点数据。相比数据库，缓存通常具备更高的读写性能。&lt;/p&gt;
&lt;p&gt;常见缓存层级：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器缓存&lt;/li&gt;
&lt;li&gt;应用层缓存，例如 Tomcat、本地缓存&lt;/li&gt;
&lt;li&gt;分布式缓存，例如 Redis&lt;/li&gt;
&lt;li&gt;数据库缓存&lt;/li&gt;
&lt;li&gt;操作系统缓存、CPU 缓存、磁盘缓存&lt;/li&gt;
&lt;/ul&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;li&gt;提升系统吞吐量&lt;/li&gt;
&lt;/ul&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;li&gt;缓存异常场景处理成本&lt;/li&gt;
&lt;/ul&gt;
&lt;section&gt;&lt;h2&gt;添加 Redis 缓存&lt;a href=&quot;#添加-redis-缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;常见的查询模型是 Cache Aside Pattern，也叫旁路缓存模式。&lt;/p&gt;&lt;p&gt;查询流程：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;客户端提交查询请求。&lt;/li&gt;
&lt;li&gt;服务端先根据 key 查询 Redis。&lt;/li&gt;
&lt;li&gt;如果缓存命中，直接返回缓存数据。&lt;/li&gt;
&lt;li&gt;如果缓存未命中，查询数据库。&lt;/li&gt;
&lt;li&gt;如果数据库存在数据，将数据写入 Redis，并返回结果。&lt;/li&gt;
&lt;li&gt;如果数据库不存在数据，返回错误或空结果。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; shopJson &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isNotEmpty&lt;/span&gt;&lt;span&gt;&lt;span&gt;(shopJson)&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(shopJson, &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(shop);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shop &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;商铺不存在&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(shop),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;30L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(shop);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;缓存更新策略&lt;a href=&quot;#缓存更新策略&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&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;说明&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;/td&gt;&lt;td&gt;依赖 Redis 内存淘汰机制，内存不足时自动淘汰部分数据&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;给缓存设置 TTL，到期后自动删除，下次查询时重新加载&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;好&lt;/td&gt;&lt;td&gt;高&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;业务选择建议：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;低一致性需求：使用 Redis 自带的内存淘汰机制，例如店铺类型、排行榜等不敏感数据。&lt;/li&gt;
&lt;li&gt;高一致性需求：使用主动更新，并结合超时剔除作为兜底方案，例如店铺详情、商品详情等核心数据。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;主动更新模式&lt;a href=&quot;#主动更新模式&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;主动更新有三种常见模式：&lt;/p&gt;&lt;section&gt;&lt;h3&gt;Cache Aside Pattern&lt;a href=&quot;#cache-aside-pattern&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;由业务代码维护缓存和数据库。&lt;/p&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;/li&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;/ol&gt;&lt;p&gt;这是业务系统中最常见的方案。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;Read/Write Through Pattern&lt;a href=&quot;#readwrite-through-pattern&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;缓存与数据库被整合成一个服务，调用者只访问这个服务，不直接感知缓存一致性问题。&lt;/p&gt;&lt;p&gt;优点是调用方简单，缺点是实现复杂，需要专门维护缓存服务。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;Write Behind Caching Pattern&lt;a href=&quot;#write-behind-caching-pattern&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;调用者只操作缓存，由缓存异步把数据持久化到数据库，保证最终一致。&lt;/p&gt;&lt;p&gt;优点是写性能好，缺点是数据可靠性和一致性风险更高，常用于对一致性要求不强、写入压力很高的场景。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Cache Aside 的关键问题&lt;a href=&quot;#cache-aside-的关键问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;删除缓存还是更新缓存&lt;a href=&quot;#删除缓存还是更新缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;推荐删除缓存。&lt;/p&gt;&lt;p&gt;更新缓存的问题是：每次数据库更新后都要重新写缓存，如果该数据后续没有被读取，就产生了无效写操作。&lt;/p&gt;&lt;p&gt;删除缓存的好处是：缓存失效后，等下一次查询时再重新构建，避免无效写。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;先操作数据库还是先操作缓存&lt;a href=&quot;#先操作数据库还是先操作缓存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;/section&gt;&lt;section&gt;&lt;h3&gt;如何保证数据库和缓存同时成功或失败&lt;a href=&quot;#如何保证数据库和缓存同时成功或失败&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;单体系统中，可以把数据库操作和缓存操作放在一个事务流程中。&lt;/p&gt;&lt;p&gt;分布式系统中，可以考虑：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;TCC&lt;/li&gt;
&lt;li&gt;可靠消息&lt;/li&gt;
&lt;li&gt;Canal 监听 binlog&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (id &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;店铺id不能为空&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;updateById&lt;/span&gt;&lt;span&gt;&lt;span&gt;(shop)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis缓存穿透，雪崩，击穿，工具封装</title><link>https://aronblake.cloud/posts/redis/rediscachepassthrough/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/rediscachepassthrough/</guid><description>Redis缓存穿透、缓存雪崩、缓存击穿与缓存工具封装</description><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;缓存穿透&lt;a href=&quot;#缓存穿透&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;缓存穿透是指客户端请求的数据在缓存和数据库中都不存在，导致每次请求都会打到数据库。&lt;/p&gt;&lt;p&gt;典型场景：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;恶意请求不存在的 id&lt;/li&gt;
&lt;li&gt;随机请求大量非法 key&lt;/li&gt;
&lt;li&gt;数据库中确实没有对应数据&lt;/li&gt;
&lt;/ul&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;优点&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;/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;内存占用低，不会产生大量空 key&lt;/td&gt;&lt;td&gt;实现复杂，存在误判，不支持天然删除&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;section&gt;&lt;h3&gt;缓存空对象&lt;a href=&quot;#缓存空对象&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;核心逻辑：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;查询 Redis。&lt;/li&gt;
&lt;li&gt;如果 Redis 返回正常 JSON，说明缓存命中，直接返回。&lt;/li&gt;
&lt;li&gt;如果 Redis 返回空字符串，说明之前查库不存在，直接返回不存在。&lt;/li&gt;
&lt;li&gt;如果 Redis 返回 null，说明缓存未命中，查询数据库。&lt;/li&gt;
&lt;li&gt;数据库不存在时，将空字符串写入 Redis，并设置较短 TTL。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithPassThrough&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; shopJson &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isNotEmpty&lt;/span&gt;&lt;span&gt;&lt;span&gt;(shopJson)&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(shopJson, &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shopJson &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shop &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;2L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(shop),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;30L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; shop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;空值缓存的 TTL 要短一些。&lt;/li&gt;
&lt;li&gt;数据库新增该数据时，需要主动删除对应空值缓存。&lt;/li&gt;
&lt;li&gt;空字符串和 null 的语义不同：空字符串表示缓存命中但业务数据不存在，null 表示缓存未命中。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;布隆过滤器&lt;a href=&quot;#布隆过滤器&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;布隆过滤器可以在访问 Redis 前判断 key 是否可能存在。&lt;/p&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;如果判断可能存在，再继续访问 Redis。&lt;/li&gt;
&lt;li&gt;Redis 未命中时再查数据库并写缓存。&lt;/li&gt;
&lt;/ol&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;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;缓存雪崩&lt;a href=&quot;#缓存雪崩&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;缓存雪崩是指同一时间大量缓存 key 同时失效，或者 Redis 服务宕机，导致大量请求直接访问数据库，数据库压力瞬间升高。&lt;/p&gt;&lt;p&gt;常见原因：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;大量 key 设置了相同 TTL&lt;/li&gt;
&lt;li&gt;Redis 宕机&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;给不同 key 的 TTL 添加随机值，避免同时过期。&lt;/li&gt;
&lt;li&gt;搭建 Redis 主从、哨兵或集群，提高可用性。&lt;/li&gt;
&lt;li&gt;给缓存业务添加限流、熔断、降级。&lt;/li&gt;
&lt;li&gt;使用多级缓存，例如本地缓存 + Redis。&lt;/li&gt;
&lt;li&gt;核心热点数据可以提前预热。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; ttl &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;30L&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;RandomUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;randomLong&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(shop),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ttl,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;缓存击穿&lt;a href=&quot;#缓存击穿&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;缓存击穿也叫热点 key 问题。&lt;/p&gt;&lt;p&gt;它指的是某个被高并发访问的热点 key 突然失效，导致大量请求同时发现缓存未命中，并发查询数据库、重建缓存，给数据库造成瞬时冲击。&lt;/p&gt;&lt;p&gt;缓存击穿和缓存雪崩的区别：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;缓存击穿：一个热点 key 失效。&lt;/li&gt;
&lt;li&gt;缓存雪崩：大量 key 同时失效，或 Redis 整体不可用。&lt;/li&gt;
&lt;/ul&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;优点&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;/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;不保证强一致性，有额外内存消耗，实现更复杂&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;互斥锁解决缓存击穿&lt;a href=&quot;#互斥锁解决缓存击穿&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&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;li&gt;未命中时尝试获取互斥锁。&lt;/li&gt;
&lt;li&gt;获取锁成功的线程查询数据库并重建缓存。&lt;/li&gt;
&lt;li&gt;获取锁失败的线程休眠一小段时间后重试。&lt;/li&gt;
&lt;li&gt;重建完成后释放锁。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithMutex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; shopJson &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isNotEmpty&lt;/span&gt;&lt;span&gt;&lt;span&gt;(shopJson)&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(shopJson, &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shopJson &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; lockKey &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;lock:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; isLock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;&lt;span&gt;(lockKey)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;isLock) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sleep&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithMutex&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shop &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shop &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;2L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(shop),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;30L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;InterruptedException&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Thread&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;interrupt&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RuntimeException&lt;/span&gt;&lt;span&gt;&lt;span&gt;(e)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;unLock&lt;/span&gt;&lt;span&gt;&lt;span&gt;(lockKey)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;47&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;48&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; shop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;49&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;50&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;51&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;52&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; flag &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;53&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setIfAbsent&lt;/span&gt;&lt;span&gt;(key, &lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;54&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BooleanUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isTrue&lt;/span&gt;&lt;span&gt;(flag);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;55&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;56&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;57&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;58&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;59&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;加锁需要设置过期时间，避免业务异常导致锁永远不释放。&lt;/li&gt;
&lt;li&gt;获取锁失败后应短暂休眠再重试，避免 CPU 空转。&lt;/li&gt;
&lt;li&gt;释放锁最好校验锁标识，避免误删其他线程的锁。生产环境建议使用 Redisson。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;逻辑过期解决缓存击穿&lt;a href=&quot;#逻辑过期解决缓存击穿&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;逻辑过期不是依赖 Redis TTL 删除 key，而是在 value 中额外保存一个过期时间字段。&lt;/p&gt;&lt;p&gt;数据结构示例：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;data&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;name&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;Jack&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;expireTime&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;2026-07-06T20:00:00&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;核心思想：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;热点数据提前写入 Redis，不设置 Redis TTL。&lt;/li&gt;
&lt;li&gt;查询时先读取缓存。&lt;/li&gt;
&lt;li&gt;如果逻辑时间未过期，直接返回。&lt;/li&gt;
&lt;li&gt;如果逻辑时间已过期，尝试获取互斥锁。&lt;/li&gt;
&lt;li&gt;获取锁成功，则开启独立线程异步重建缓存。&lt;/li&gt;
&lt;li&gt;当前请求先返回旧数据。&lt;/li&gt;
&lt;li&gt;获取锁失败，也直接返回旧数据。&lt;/li&gt;
&lt;/ol&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt; expireTime&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;预热热点数据：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;saveShop2Redis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; expireSeconds) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt; redisData &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setData&lt;/span&gt;&lt;span&gt;(shop);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setExpireTime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;plusSeconds&lt;/span&gt;&lt;span&gt;(expireSeconds));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(redisData)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查询逻辑：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ExecutorService&lt;/span&gt;&lt;span&gt; CACHE_REBUILD_EXECUTOR &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Executors&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newFixedThreadPool&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithLogicalExpire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; key &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;cache:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; shopJson &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isEmpty&lt;/span&gt;&lt;span&gt;&lt;span&gt;(shopJson)&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt; redisData &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(shopJson, &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;JSONObject&lt;/span&gt;&lt;span&gt; data &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (JSONObject) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getData&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(data, &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt; expireTime &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getExpireTime&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;expireTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isAfter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;&lt;span&gt;())&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; shop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; lockKey &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;lock:shop:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; isLock &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;&lt;span&gt;(lockKey)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (isLock) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;CACHE_REBUILD_EXECUTOR&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;saveShop2Redis&lt;/span&gt;&lt;span&gt;(id, &lt;/span&gt;&lt;span&gt;30L&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;unLock&lt;/span&gt;&lt;span&gt;(lockKey);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; shop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&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;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;缓存工具封装&lt;a href=&quot;#缓存工具封装&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;可以基于 &lt;code&gt;StringRedisTemplate&lt;/code&gt; 封装一个通用缓存工具类，统一处理：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;普通缓存写入，并设置 TTL。&lt;/li&gt;
&lt;li&gt;逻辑过期缓存写入。&lt;/li&gt;
&lt;li&gt;缓存穿透查询。&lt;/li&gt;
&lt;li&gt;逻辑过期查询。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Slf4j&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheClient&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt; stringRedisTemplate&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ExecutorService&lt;/span&gt;&lt;span&gt; CACHE_REBUILD_EXECUTOR &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Executors&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newFixedThreadPool&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheClient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stringRedisTemplate;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(value),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;time,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;setWithLogicalExpire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setData&lt;/span&gt;&lt;span&gt;(value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setExpireTime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;plusSeconds&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toSeconds&lt;/span&gt;&lt;span&gt;(time)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toJsonStr&lt;/span&gt;&lt;span&gt;(redisData)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithPassThrough&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;keyPrefix&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Class&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Function&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;dbFallback&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;47&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; keyPrefix &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;48&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;49&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;50&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;51&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isNotEmpty&lt;/span&gt;&lt;span&gt;(json)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;52&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(json, type);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;53&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;54&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;55&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (json &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;56&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;57&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;58&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;59&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;dbFallback&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(id);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;60&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;61&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (r &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;62&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;63&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;64&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;65&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;2L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;66&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;67&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;68&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;69&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;70&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;71&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(key, r, time, timeUnit);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;72&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;73&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;74&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;75&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;76&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryWithLogicalExpire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;77&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;keyPrefix&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;78&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;79&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Class&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;80&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Function&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;dbFallback&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;81&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;82&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeUnit&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;83&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;84&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; keyPrefix &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;85&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;86&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;87&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;88&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StrUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isEmpty&lt;/span&gt;&lt;span&gt;(json)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;89&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;90&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;91&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;92&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;(json, &lt;/span&gt;&lt;span&gt;RedisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;93&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSONUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toBean&lt;/span&gt;&lt;span&gt;((JSONObject) &lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getData&lt;/span&gt;&lt;span&gt;(), type);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;94&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;95&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;expireTime&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;redisData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getExpireTime&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;96&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;expireTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isAfter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt;())) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;97&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;98&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;99&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lockKey&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;lock:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; key;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;101&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isLock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(lockKey);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;102&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;103&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (isLock) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;104&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;CACHE_REBUILD_EXECUTOR&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;105&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;106&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;freshData&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;dbFallback&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(id);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;107&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setWithLogicalExpire&lt;/span&gt;&lt;span&gt;(key, freshData, time, timeUnit);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;108&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;109&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;unLock&lt;/span&gt;&lt;span&gt;(lockKey);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;110&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;111&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;112&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;113&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;114&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;115&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;116&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;117&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tryLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;118&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;flag&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;opsForValue&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;119&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setIfAbsent&lt;/span&gt;&lt;span&gt;(key, &lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;120&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BooleanUtil&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isTrue&lt;/span&gt;&lt;span&gt;(flag);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;121&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;122&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;123&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unLock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;124&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;stringRedisTemplate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;125&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;126&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;业务调用示例&lt;a href=&quot;#业务调用示例&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;queryById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Long&lt;/span&gt;&lt;span&gt; id) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt; shop &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cacheClient&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;queryWithLogicalExpire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;RedisConstants&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CACHE_SHOP_KEY&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getById,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;RedisConstants&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CACHE_SHOP_TTL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MINUTES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (shop &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;店铺不存在&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;(shop);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;测试预热逻辑过期缓存：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SpringBootTest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HmDianPingApplicationTests&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Resource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ShopServiceImpl&lt;/span&gt;&lt;span&gt; shopService&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Resource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CacheClient&lt;/span&gt;&lt;span&gt; cacheClient&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;testSaveShop&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Shop&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shopService&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1L&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;cacheClient&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setWithLogicalExpire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;RedisConstants&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CACHE_SHOP_KEY&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;shop,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;10L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;TimeUnit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content:encoded></item><item><title>Redis相关介绍和命令</title><link>https://aronblake.cloud/posts/redis/redis/</link><guid isPermaLink="true">https://aronblake.cloud/posts/redis/redis/</guid><description>Redis基础，命令相关介绍</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;一 认识 NoSQL&lt;a href=&quot;#一-认识-nosql&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. SQL与NoSQL对比&lt;/strong&gt;&lt;/p&gt;












































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对比项&lt;/th&gt;&lt;th&gt;SQL&lt;/th&gt;&lt;th&gt;NoSQL&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;数据结构&lt;/td&gt;&lt;td&gt;结构化 Structured&lt;/td&gt;&lt;td&gt;非结构化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数据关联&lt;/td&gt;&lt;td&gt;关联的 Relational&lt;/td&gt;&lt;td&gt;无关联的&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;查询方式&lt;/td&gt;&lt;td&gt;SQL 查询&lt;/td&gt;&lt;td&gt;非 SQL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;事务特性&lt;/td&gt;&lt;td&gt;ACID&lt;/td&gt;&lt;td&gt;BASE&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;垂直扩展&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;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;2. NoSQL 类型&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;键值类型&lt;/strong&gt;：Redis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档类型&lt;/strong&gt;：MongoDB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;列类型&lt;/strong&gt;：HBase&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graph 图类型&lt;/strong&gt;：Neo4j&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;二 认识 Redis&lt;a href=&quot;#二-认识-redis&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. 定义&lt;/strong&gt;
Redis 远程字典服务器 基于内存的键值型 NoSQL 数据库&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 常用于：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;缓存&lt;/li&gt;
&lt;li&gt;登录验证码&lt;/li&gt;
&lt;li&gt;Session 共享&lt;/li&gt;
&lt;li&gt;排行榜&lt;/li&gt;
&lt;li&gt;计数器&lt;/li&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;strong&gt;3. Redis特征&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;键值 key-value 类型
&lt;ul&gt;
&lt;li&gt;Redis 以 key-value 的形式存储数据。&lt;/li&gt;
&lt;li&gt;value 支持多种数据结构，功能丰富。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;单线程
&lt;ul&gt;
&lt;li&gt;Redis 主要命令执行是单线程的。&lt;/li&gt;
&lt;li&gt;每个命令具备原子性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;低延迟、速度快
&lt;ul&gt;
&lt;li&gt;Redis 基于内存操作。&lt;/li&gt;
&lt;li&gt;使用 IO 多路复用。&lt;/li&gt;
&lt;li&gt;编码设计良好，所以读写速度快。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;支持数据持久化
&lt;ul&gt;
&lt;li&gt;Redis 虽然主要基于内存，但可以把数据保存到磁盘。&lt;/li&gt;
&lt;li&gt;防止服务器重启后数据全部丢失。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;支持主从集群、分片集群
&lt;ul&gt;
&lt;li&gt;可以通过主从复制提高读能力和可用性。&lt;/li&gt;
&lt;li&gt;可以通过分片集群提升容量和并发能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;支持多语言客户端
&lt;ul&gt;
&lt;li&gt;Java、Python、PHP、Go、Node.js 等语言都可以连接 Redis。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;4. Redis 常见数据类型&lt;/strong&gt;&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;String&lt;/td&gt;&lt;td&gt;字符串类型，最基础类型&lt;/td&gt;&lt;td&gt;缓存、验证码、计数器&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hash&lt;/td&gt;&lt;td&gt;哈希类型，类似 Java 中的 Map&lt;/td&gt;&lt;td&gt;存储对象信息&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;List&lt;/td&gt;&lt;td&gt;列表类型，有序可重复&lt;/td&gt;&lt;td&gt;消息队列、任务列表&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Set&lt;/td&gt;&lt;td&gt;集合类型，无序不重复&lt;/td&gt;&lt;td&gt;去重、共同好友&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZSet&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;strong&gt;5. Redis 和 MySQL 的区别&lt;/strong&gt;&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;NoSQL 数据库&lt;/td&gt;&lt;td&gt;关系型数据库&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数据结构&lt;/td&gt;&lt;td&gt;key-value&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;Redis 命令&lt;/td&gt;&lt;td&gt;SQL 语句&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;较弱&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;strong&gt;6. Redis 的持久化方式&lt;/strong&gt;&lt;br /&gt;
Redis 支持把内存中的数据保存到磁盘，常见方式有：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;RDB
&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;/li&gt;
&lt;li&gt;AOF
&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;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三 Redis配置内容&lt;a href=&quot;#三-redis配置内容&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. 网络与后台运行配置&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 监听的地址，默认是127.0.0.1，会导致只能在本地访问&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 修改为0.0.0.0则可以在任意IP访问，生产环境不要设置为0.0.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bind 0.0.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 守护进程，修改为yes后即可后台运行&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;daemonize yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 密码，设置后访问Redis必须输入密码&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;requirepass 123321&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. 端口、目录、数据库、内存和日志配置&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 监听的端口,Redis 默认端口号是6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;port 6379&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 工作目录，默认是当前目录，也就是运行redis-server时的命令&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 日志、持久化等文件会保存在这个目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dir .&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 数据库数量，设置为1，代表只使用1个库&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 默认有16个库，编号0~15&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;databases 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 设置redis能够使用的最大内存&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;maxmemory 512mb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 日志文件，默认为空，不记录日志，可以指定日志文件名&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;logfile &quot;redis.log&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;四 Redis相关命令&lt;a href=&quot;#四-redis相关命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. 通用命令&lt;/strong&gt;&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;keys *&lt;/td&gt;&lt;td&gt;查看所有 key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;keys user:*&lt;/td&gt;&lt;td&gt;按规则查看 key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;scan 0&lt;/td&gt;&lt;td&gt;渐进式扫描 key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;exists key&lt;/td&gt;&lt;td&gt;判断 key 是否存在&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;del key&lt;/td&gt;&lt;td&gt;删除 key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;type key&lt;/td&gt;&lt;td&gt;查看 key 类型&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;expire key 秒数&lt;/td&gt;&lt;td&gt;设置过期时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ttl key&lt;/td&gt;&lt;td&gt;查看剩余过期时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;persist key&lt;/td&gt;&lt;td&gt;取消过期时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rename oldkey newkey&lt;/td&gt;&lt;td&gt;修改 key 名称&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;randomkey&lt;/td&gt;&lt;td&gt;随机返回一个 key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select 0&lt;/td&gt;&lt;td&gt;切换数据库&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;flushdb&lt;/td&gt;&lt;td&gt;清空当前数据库&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;flushall&lt;/td&gt;&lt;td&gt;清空所有数据库&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;2. String类型&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&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;/td&gt;&lt;td&gt;name = zhangsan&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数字&lt;/td&gt;&lt;td&gt;age = 18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;JSON 字符串&lt;/td&gt;&lt;td&gt;user = {“name”:“zhangsan”,“age”:18}&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;验证码&lt;/td&gt;&lt;td&gt;code = 123456&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;token&lt;/td&gt;&lt;td&gt;token = xxxxxx&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;








































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;set key value&lt;/td&gt;&lt;td&gt;设置值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;get key&lt;/td&gt;&lt;td&gt;获取值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;mset key1 value1 key2 value2&lt;/td&gt;&lt;td&gt;设置多个值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;mget key1 key2&lt;/td&gt;&lt;td&gt;获取多个值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;incr key&lt;/td&gt;&lt;td&gt;自增 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;decr key&lt;/td&gt;&lt;td&gt;自减 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;incrby key 数字&lt;/td&gt;&lt;td&gt;增加指定整数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;decrby key 数字&lt;/td&gt;&lt;td&gt;减少指定整数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;incrbyfloat key 数字&lt;/td&gt;&lt;td&gt;增加小数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;setex key 秒 value&lt;/td&gt;&lt;td&gt;设置值并指定秒级过期时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;setnx key value&lt;/td&gt;&lt;td&gt;key 不存在时才设置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;append key value&lt;/td&gt;&lt;td&gt;追加字符串&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;strlen key&lt;/td&gt;&lt;td&gt;获取字符串长度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getrange key start end&lt;/td&gt;&lt;td&gt;截取字符串&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;setrange key offset value&lt;/td&gt;&lt;td&gt;修改指定位置内容&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getset key value&lt;/td&gt;&lt;td&gt;获取旧值并设置新值&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&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;/td&gt;&lt;td&gt;set user:1 “张三”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;验证码&lt;/td&gt;&lt;td&gt;setex code:1001 60 123456&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;计数器&lt;/td&gt;&lt;td&gt;incr article:readcount:1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;登录 token&lt;/td&gt;&lt;td&gt;setex token:user:1 3600 abc123&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;分布式锁&lt;/td&gt;&lt;td&gt;set lock 1 nx ex 10&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;3. Hash类型&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;key&lt;/th&gt;&lt;th&gt;field&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;td&gt;name&lt;/td&gt;&lt;td&gt;zhangsan&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;td&gt;age&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;td&gt;gender&lt;/td&gt;&lt;td&gt;male&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
























































&lt;table&gt;&lt;thead&gt;&lt;tr&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;hset key field value&lt;/td&gt;&lt;td&gt;设置字段值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hget key field&lt;/td&gt;&lt;td&gt;获取字段值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hmget key field1 field2&lt;/td&gt;&lt;td&gt;获取多个字段值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hgetall key&lt;/td&gt;&lt;td&gt;获取所有字段和值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hdel key field&lt;/td&gt;&lt;td&gt;删除字段&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hexists key field&lt;/td&gt;&lt;td&gt;判断字段是否存在&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hkeys key&lt;/td&gt;&lt;td&gt;获取所有字段名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hvals key&lt;/td&gt;&lt;td&gt;获取所有字段值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hlen key&lt;/td&gt;&lt;td&gt;获取字段数量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hincrby key field 数字&lt;/td&gt;&lt;td&gt;字段整数自增&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hincrbyfloat key field 数字&lt;/td&gt;&lt;td&gt;字段小数自增&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hsetnx key field value&lt;/td&gt;&lt;td&gt;字段不存在时才设置&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&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;/td&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;商品信息&lt;/td&gt;&lt;td&gt;product:1001&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;购物车&lt;/td&gt;&lt;td&gt;cart:user:1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;订单信息&lt;/td&gt;&lt;td&gt;order:1001&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;店铺信息&lt;/td&gt;&lt;td&gt;shop:1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;4. List类型&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&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;/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;/tr&gt;&lt;tr&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;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




























































&lt;table&gt;&lt;thead&gt;&lt;tr&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;lpush key value&lt;/td&gt;&lt;td&gt;从左侧添加元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpush key value&lt;/td&gt;&lt;td&gt;从右侧添加元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lrange key start stop&lt;/td&gt;&lt;td&gt;查看指定范围元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lindex key index&lt;/td&gt;&lt;td&gt;根据下标获取元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;llen key&lt;/td&gt;&lt;td&gt;获取列表长度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lpop key&lt;/td&gt;&lt;td&gt;从左侧弹出元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpop key&lt;/td&gt;&lt;td&gt;从右侧弹出元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lrem key count value&lt;/td&gt;&lt;td&gt;删除指定元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lset key index value&lt;/td&gt;&lt;td&gt;根据下标修改元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ltrim key start stop&lt;/td&gt;&lt;td&gt;截取列表&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;linsert key before/after 元素 新元素&lt;/td&gt;&lt;td&gt;在指定元素前后插入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;blpop key timeout&lt;/td&gt;&lt;td&gt;阻塞式左侧弹出&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;brpop key timeout&lt;/td&gt;&lt;td&gt;阻塞式右侧弹出&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
































&lt;table&gt;&lt;thead&gt;&lt;tr&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;/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;/tr&gt;&lt;tr&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;/tr&gt;&lt;tr&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;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;5. Set类型&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&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;/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;/tr&gt;&lt;tr&gt;&lt;td&gt;支持集合运算&lt;/td&gt;&lt;td&gt;可以求交集、并集、差集&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;sadd key member&lt;/td&gt;&lt;td&gt;添加元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;smembers key&lt;/td&gt;&lt;td&gt;查看所有元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sismember key member&lt;/td&gt;&lt;td&gt;判断元素是否存在&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;scard key&lt;/td&gt;&lt;td&gt;获取集合元素数量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;srem key member&lt;/td&gt;&lt;td&gt;删除指定元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;spop key&lt;/td&gt;&lt;td&gt;随机删除并返回元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;srandmember key&lt;/td&gt;&lt;td&gt;随机返回元素，不删除&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;smove source destination member&lt;/td&gt;&lt;td&gt;移动元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sinter key1 key2&lt;/td&gt;&lt;td&gt;求交集&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sunion key1 key2&lt;/td&gt;&lt;td&gt;求并集&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sdiff key1 key2&lt;/td&gt;&lt;td&gt;求差集&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sinterstore result key1 key2&lt;/td&gt;&lt;td&gt;保存交集结果&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sunionstore result key1 key2&lt;/td&gt;&lt;td&gt;保存并集结果&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sdiffstore result key1 key2&lt;/td&gt;&lt;td&gt;保存差集结果&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&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;/td&gt;&lt;td&gt;利用 Set 不重复特点&lt;/td&gt;&lt;td&gt;用户签到、访问 IP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;共同好友&lt;/td&gt;&lt;td&gt;使用交集&lt;/td&gt;&lt;td&gt;sinter user:1 user:2&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;使用差集&lt;/td&gt;&lt;td&gt;A 关注但 B 未关注&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;标签系统&lt;/td&gt;&lt;td&gt;保存用户标签&lt;/td&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;抽奖&lt;/td&gt;&lt;td&gt;随机获取元素&lt;/td&gt;&lt;td&gt;srandmember users 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;点赞&lt;/td&gt;&lt;td&gt;保存点赞用户 ID&lt;/td&gt;&lt;td&gt;article:1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;6. ZSet/SortedSet&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&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;/td&gt;&lt;td&gt;member 不能重复&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;每个元素有分数&lt;/td&gt;&lt;td&gt;每个 member 都有一个 score&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;按分数排序&lt;/td&gt;&lt;td&gt;Redis 根据 score 进行排序&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;适合排行榜&lt;/td&gt;&lt;td&gt;比如积分榜、热度榜、成绩排名&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




































































&lt;table&gt;&lt;thead&gt;&lt;tr&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;zadd key score member&lt;/td&gt;&lt;td&gt;添加元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrange key start stop&lt;/td&gt;&lt;td&gt;按分数从小到大查询&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrevrange key start stop&lt;/td&gt;&lt;td&gt;按分数从大到小查询&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrange key start stop withscores&lt;/td&gt;&lt;td&gt;查询时带分数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zscore key member&lt;/td&gt;&lt;td&gt;获取元素分数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrank key member&lt;/td&gt;&lt;td&gt;获取从小到大排名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrevrank key member&lt;/td&gt;&lt;td&gt;获取从大到小排名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrangebyscore key min max&lt;/td&gt;&lt;td&gt;按分数范围查询&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrevrangebyscore key max min&lt;/td&gt;&lt;td&gt;按分数范围倒序查询&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zrem key member&lt;/td&gt;&lt;td&gt;删除元素&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zincrby key increment member&lt;/td&gt;&lt;td&gt;增加元素分数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zcard key&lt;/td&gt;&lt;td&gt;获取元素总数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zcount key min max&lt;/td&gt;&lt;td&gt;获取分数范围内元素数量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zremrangebyrank key start stop&lt;/td&gt;&lt;td&gt;按排名范围删除&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;zremrangebyscore key min max&lt;/td&gt;&lt;td&gt;按分数范围删除&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
































&lt;table&gt;&lt;thead&gt;&lt;tr&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;/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;/tr&gt;&lt;tr&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;/tr&gt;&lt;tr&gt;&lt;td&gt;延迟队列&lt;/td&gt;&lt;td&gt;score 可以存时间戳&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;商品销量榜&lt;/td&gt;&lt;td&gt;按销量排序&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五 Key 的层级结构&lt;a href=&quot;#五-key-的层级结构&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Redis 中常用 : 来分隔 key 的层级。&lt;br /&gt;
格式一般是：项目名:业务名: id:字段名&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Key 层级结构示例&lt;/strong&gt;&lt;br /&gt;
假设有一个用户模块，可以这样设计：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:1:name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:1:age&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:1:gender&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:2:name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:2:age&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;user:2:gender&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看所有用户相关 key。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;keys user:*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;查看用户 1 的所有信息。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;keys user:1:*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;常见业务场景写法&lt;/strong&gt;&lt;/p&gt;






















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;/th&gt;&lt;th&gt;Key 示例&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;/td&gt;&lt;td&gt;user:1&lt;/td&gt;&lt;td&gt;Hash&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;商品对象&lt;/td&gt;&lt;td&gt;product:1001&lt;/td&gt;&lt;td&gt;Hash&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;验证码&lt;/td&gt;&lt;td&gt;login:code:手机号&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;登录 token&lt;/td&gt;&lt;td&gt;login:token:user:1&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;购物车&lt;/td&gt;&lt;td&gt;cart:user:1&lt;/td&gt;&lt;td&gt;Hash&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;商品库存&lt;/td&gt;&lt;td&gt;stock:product:1001&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;文章点赞数&lt;/td&gt;&lt;td&gt;article:1001&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;排行榜&lt;/td&gt;&lt;td&gt;rank&lt;/td&gt;&lt;td&gt;ZSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;用户关注列表&lt;/td&gt;&lt;td&gt;follow:user:1&lt;/td&gt;&lt;td&gt;Set&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;</content:encoded></item></channel></rss>