<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>南柯一梦</title><description>一梦十二载，代码与方块</description><link>https://www.s9mc.cn/</link><lastBuildDate>2026年10月7日 21:37:23</lastBuildDate><item><title>Java 虚拟线程实战：用同步写法扛住十万并发</title><link>https://www.s9mc.cn/posts/java-virtual-threads/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/java-virtual-threads/</guid><description>虚拟线程让「一请求一线程」重新变得可行。本文从原理、用法到踩坑，讲清楚它在后端服务里该怎么用。</description><pubDate>Mon, 28 Sep 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;传统的 Java 线程是对操作系统线程的一层薄封装，一个线程大约占用 1MB 栈空间，创建和切换成本都不低。于是我们才有了线程池、回调、&lt;code&gt;CompletableFuture&lt;/code&gt;、响应式编程这一整套「为了省线程而牺牲可读性」的方案。&lt;/p&gt;&lt;p&gt;虚拟线程（Virtual Thread，JDK 21 正式）换了个思路：线程由 JVM 调度，成本极低，可以轻松创建几十万个。阻塞时，JVM 会把它从载体线程（carrier thread）上卸下来，让出 CPU。&lt;/p&gt;&lt;p&gt;结论：&lt;strong&gt;可以继续用最直观的同步代码，同时拿到接近异步的吞吐。&lt;/strong&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;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; executor &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;newVirtualThreadPerTaskExecutor&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;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Future&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; futures &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;ArrayList&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;3&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_000&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;4&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; id &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;/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;futures&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;executor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;submit&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;6&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;Duration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofSeconds&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;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;&quot;task-&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;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;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; f &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; futures) {&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;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&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;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;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;在 Spring Boot 中启用&lt;a href=&quot;#在-spring-boot-中启用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Spring Boot 3.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;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;threads&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;virtual&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;enabled&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Tomcat 的请求处理线程、&lt;code&gt;@Async&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;ol&gt;
&lt;li&gt;&lt;strong&gt;不要池化虚拟线程。&lt;/strong&gt; 它们本来就是廉价的，用完即弃。需要限流时用 &lt;code&gt;Semaphore&lt;/code&gt;，而不是缩小线程池。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU 密集型任务没有收益。&lt;/strong&gt; 虚拟线程解决的是「等待」问题，不是「计算」问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小心 &lt;code&gt;synchronized&lt;/code&gt; 造成的 pinning。&lt;/strong&gt; 在 JDK 21 中，虚拟线程在 &lt;code&gt;synchronized&lt;/code&gt; 块里阻塞会钉住载体线程。能换成 &lt;code&gt;ReentrantLock&lt;/code&gt; 就换。可以用 &lt;code&gt;-Djdk.tracePinnedThreads=full&lt;/code&gt; 排查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ThreadLocal 要克制。&lt;/strong&gt; 线程数量暴涨后，每个线程一份 ThreadLocal 的内存开销会被放大。&lt;/li&gt;
&lt;/ol&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;虚拟线程不是银弹，但对大多数 IO 密集的业务后端来说，它能让代码回到最朴素的样子。升级 JDK 21 之后，先把它开在非核心服务上压测一遍，数据会告诉你答案。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>开了十二年服，我总结的 Paper 服务器调优清单</title><link>https://www.s9mc.cn/posts/paper-server-tuning/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/paper-server-tuning/</guid><description>从 JVM 参数到区块加载，从实体清理到定时任务，一份来自十二年运维经验的 Minecraft 服务器调优清单。</description><pubDate>Sun, 20 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;服务器卡，十有八九不是机器不行，而是配置没有调。下面是我这些年踩坑后沉淀出的清单。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. JVM 参数&lt;a href=&quot;#1-jvm-参数&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;内存别给满，留出系统和堆外空间。常用的 G1 参数如下（以 8GB 堆为例）：&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;java&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-Xms8G&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-Xmx8G&lt;/span&gt;&lt;span&gt; &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;-XX:+UseG1GC&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-XX:+ParallelRefProcEnabled&lt;/span&gt;&lt;span&gt; &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;-XX:MaxGCPauseMillis=200&lt;/span&gt;&lt;span&gt; &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;-XX:+UnlockExperimentalVMOptions&lt;/span&gt;&lt;span&gt; &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;-XX:+DisableExplicitGC&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-XX:+AlwaysPreTouch&lt;/span&gt;&lt;span&gt; &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;-XX:G1NewSizePercent=30&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-XX:G1MaxNewSizePercent=40&lt;/span&gt;&lt;span&gt; &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;-XX:G1HeapRegionSize=8M&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-XX:G1ReservePercent=20&lt;/span&gt;&lt;span&gt; &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;-XX:G1HeapWastePercent=5&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-XX:G1MixedGCCountTarget=4&lt;/span&gt;&lt;span&gt; &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;-XX:InitiatingHeapOccupancyPercent=15&lt;/span&gt;&lt;span&gt; &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;-jar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;paper.jar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--nogui&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;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;-Xms&lt;/code&gt; 与 &lt;code&gt;-Xmx&lt;/code&gt; 设置成一样，避免堆扩缩带来的抖动。&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;这是收益最大的一项。在 &lt;code&gt;server.properties&lt;/code&gt; 与 &lt;code&gt;paper-world-defaults.yml&lt;/code&gt; 里：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;view-distance&lt;/code&gt;：保持 8 左右。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;simulation-distance&lt;/code&gt;：降到 4~6，实体和红石只在近处运行。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;玩家几乎感觉不到，但 CPU 压力会明显下降。&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;ul&gt;
&lt;li&gt;限制每个区块的怪物上限与刷怪频率。&lt;/li&gt;
&lt;li&gt;定期清理掉落物，但要给玩家提前提示。&lt;/li&gt;
&lt;li&gt;大型农场（村民交易所、刷怪塔）要单独评估，村民的寻路 AI 是出了名的重。&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;ul&gt;
&lt;li&gt;使用 &lt;code&gt;/chunky&lt;/code&gt; 提前预生成地图，避免玩家探索时实时生成造成卡顿。&lt;/li&gt;
&lt;li&gt;设置世界边界，别让地图无限膨胀。&lt;/li&gt;
&lt;li&gt;定期备份，并且&lt;strong&gt;定期验证备份可恢复&lt;/strong&gt;。没验证过的备份只是一种心理安慰。&lt;/li&gt;
&lt;/ul&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;p&gt;不要凭感觉调参数。Paper 自带的 &lt;code&gt;/spark profiler&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;/spark profiler start&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~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;/spark profiler stop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;看火焰图，找到占用 tick 时间最多的插件或实体，再对症下药。&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;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;h2&gt;小结&lt;a href=&quot;#小结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;调优的本质是：测量、定位、改一处、再测量。十二年下来最大的体会是，&lt;strong&gt;稳定比花哨更重要&lt;/strong&gt;。玩家记得的是流畅的体验，而不是你装了多少插件。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>和 AI 结对编程：我的日常工作流</title><link>https://www.s9mc.cn/posts/ai-pair-programming/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/ai-pair-programming/</guid><description>不是让 AI 替你写代码，而是让它成为你的搭档。分享我在日常开发中使用 AI 工具的几条原则与技巧。</description><pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;过去一年，AI 工具已经深度嵌进了我的日常开发。这里分享几条我自己总结的原则。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;原则一：你来决策，AI 来执行&lt;a href=&quot;#原则一你来决策ai-来执行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;把 AI 当作一位速度很快、但缺乏上下文的搭档。需求怎么拆、边界怎么定、取舍怎么做，这些由人来决定；查文档、写样板代码、补测试、重构，这些交给 AI。&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;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;h2&gt;原则三：小步提交，逐步验证&lt;a href=&quot;#原则三小步提交逐步验证&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;不要一次让 AI 改几十个文件。把任务拆小，每一步都跑测试、看 diff。出现问题时，回滚的成本也很低。&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;/td&gt;&lt;td&gt;让 AI 梳理调用链，我再对照源码确认&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;写单元测试&lt;/td&gt;&lt;td&gt;先给被测方法，让 AI 列出边界用例，再逐个实现&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;排查线上问题&lt;/td&gt;&lt;td&gt;把日志与堆栈贴给 AI，请它给出几个可验证的假设&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;重构&lt;/td&gt;&lt;td&gt;先让 AI 说明改动计划，我确认后再动手&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;写文档与提交信息&lt;/td&gt;&lt;td&gt;直接交给 AI，我只做审阅&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;AI 生成的代码，&lt;strong&gt;你需要对它负责&lt;/strong&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;好的使用方式是「放大自己」而不是「替代自己」。把重复劳动交出去，把精力留给真正需要判断力的地方，这才是 AI 工具最大的价值。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>MySQL 索引与执行计划：从 EXPLAIN 看懂慢查询</title><link>https://www.s9mc.cn/posts/mysql-index-explain/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/mysql-index-explain/</guid><description>学会读 EXPLAIN，理解最左前缀、覆盖索引与索引失效场景，让慢查询无处遁形。</description><pubDate>Sat, 05 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;慢查询是后端工程师绕不开的话题。排查的第一步，永远是 &lt;code&gt;EXPLAIN&lt;/code&gt;。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;读懂 EXPLAIN&lt;a href=&quot;#读懂-explain&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;EXPLAIN &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; user &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt;&lt;span&gt; age &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AND&lt;/span&gt;&lt;span&gt;&lt;span&gt; city &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;Shanghai&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;ul&gt;
&lt;li&gt;&lt;strong&gt;type&lt;/strong&gt;：访问方式。从好到差大致是 &lt;code&gt;const&lt;/code&gt; &amp;gt; &lt;code&gt;ref&lt;/code&gt; &amp;gt; &lt;code&gt;range&lt;/code&gt; &amp;gt; &lt;code&gt;index&lt;/code&gt; &amp;gt; &lt;code&gt;ALL&lt;/code&gt;。出现 &lt;code&gt;ALL&lt;/code&gt; 意味着全表扫描。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;key&lt;/strong&gt;：实际使用的索引。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rows&lt;/strong&gt;：预估扫描行数，越小越好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extra&lt;/strong&gt;：&lt;code&gt;Using index&lt;/code&gt; 表示覆盖索引；&lt;code&gt;Using filesort&lt;/code&gt;、&lt;code&gt;Using temporary&lt;/code&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;(city, age, name)&lt;/code&gt; 可以支撑：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WHERE city = ?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WHERE city = ? AND age = ?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WHERE city = ? AND age = ? AND name = ?&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;但无法有效支撑只写 &lt;code&gt;age&lt;/code&gt; 或 &lt;code&gt;name&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;如果查询的列都在索引里，MySQL 不需要回表：&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;-- 索引 (city, age, 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;SELECT&lt;/span&gt;&lt;span&gt; city, age, &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; user &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt;&lt;span&gt; city &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;Shanghai&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;回表是随机 IO，能避免就避免。&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;ol&gt;
&lt;li&gt;对索引列使用函数或运算：&lt;code&gt;WHERE DATE(create_time) = &apos;2026-01-01&apos;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;隐式类型转换：字符串列用数字去比较。&lt;/li&gt;
&lt;li&gt;以通配符开头的模糊查询：&lt;code&gt;LIKE &apos;%abc&apos;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OR&lt;/code&gt; 连接的条件中，有一边没有索引。&lt;/li&gt;
&lt;li&gt;联合索引没有遵循最左前缀。&lt;/li&gt;
&lt;/ol&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;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;-- 慢：需要扫描并丢弃前 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;SELECT&lt;/span&gt;&lt;span&gt; * &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; orders &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;LIMIT&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1000000&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;20&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;-- 快：利用上一页的最后一个 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;SELECT&lt;/span&gt;&lt;span&gt; * &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; orders &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1000000&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id &lt;/span&gt;&lt;span&gt;LIMIT&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;20&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;优化的流程很朴素：先定位慢 SQL，再看执行计划，然后调整索引或改写查询，最后用真实数据验证。&lt;strong&gt;不要为了加索引而加索引&lt;/strong&gt;，每个索引都会拖慢写入、占用空间。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>Spring Boot 优雅停机：发布时不再丢请求</title><link>https://www.s9mc.cn/posts/spring-boot-graceful-shutdown/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/spring-boot-graceful-shutdown/</guid><description>讲清楚 Spring Boot 的优雅停机机制，以及在 Kubernetes 与负载均衡下如何配合，做到发布零报错。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;每次发布都会收到几条 502 报警？很可能是应用没有「优雅」地停下来。&lt;/p&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;strong&gt;新&lt;/strong&gt;请求；&lt;/li&gt;
&lt;li&gt;等待&lt;strong&gt;进行中&lt;/strong&gt;的请求处理完成（带超时）；&lt;/li&gt;
&lt;li&gt;关闭线程池、连接池等资源；&lt;/li&gt;
&lt;li&gt;进程退出。&lt;/li&gt;
&lt;/ol&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;Spring Boot 2.3+ 内置支持：&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;server&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;shutdown&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;graceful&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;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;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;lifecycle&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;timeout-per-shutdown-phase&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;30s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;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;immediate&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;/li&gt;
&lt;li&gt;等待几秒，让流量完全切走；&lt;/li&gt;
&lt;li&gt;再发送 &lt;code&gt;SIGTERM&lt;/code&gt;，触发优雅停机。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;在 Kubernetes 中可以用 &lt;code&gt;preStop&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;lifecycle&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;preStop&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;exec&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;command&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;&quot;sh&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-c&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;sleep 10&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;terminationGracePeriodSeconds&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;60&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;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;terminationGracePeriodSeconds&lt;/code&gt; 必须大于 &lt;code&gt;preStop&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;@PreDestroy&lt;/code&gt; 或 &lt;code&gt;SmartLifecycle&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;@&lt;/span&gt;&lt;span&gt;PreDestroy&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;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;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;executor&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;4&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;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;&lt;span&gt;!&lt;/span&gt;&lt;/span&gt;&lt;span&gt;executor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;awaitTermination&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;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;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;executor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;shutdownNow&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;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;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;executor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;shutdownNow&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;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;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;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;</content:encoded></item><item><title>Redis 分布式锁：从 SETNX 到 Redisson 的坑</title><link>https://www.s9mc.cn/posts/redis-distributed-lock/</link><guid isPermaLink="true">https://www.s9mc.cn/posts/redis-distributed-lock/</guid><description>一把分布式锁要考虑的事情远比想象中多：原子性、过期时间、误删、续期。本文逐个拆解。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;分布式锁看上去只是「加锁、解锁」两步，实际上一个坑接一个坑。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;第一版：SETNX&lt;a href=&quot;#第一版setnx&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;Boolean&lt;/span&gt;&lt;span&gt; ok &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&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;opsForValue&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;setIfAbsent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;lock:order:1001&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;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;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;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;&lt;span&gt;(ok)&lt;/span&gt;&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;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;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;&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;6&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;span&gt;delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;lock:order:1001&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;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;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;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;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; ok &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&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;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;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;setIfAbsent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;lock:order:1001&quot;&lt;/span&gt;&lt;span&gt;, token, &lt;/span&gt;&lt;span&gt;Duration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ofSeconds&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;30&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;SETNX&lt;/code&gt; 再 &lt;code&gt;EXPIRE&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;假如业务执行超过 30 秒，锁已经过期并被别人拿走，此时你的 &lt;code&gt;delete&lt;/code&gt; 会把别人的锁删掉。&lt;/p&gt;&lt;p&gt;做法：加锁时写入唯一标识（token），解锁时先比较再删除，并且这两步要用 Lua 脚本保证原子性：&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;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;&quot;get&quot;&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;2&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;&quot;del&quot;&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;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;else&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;0&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;/code&gt;&lt;/pre&gt;&lt;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;p&gt;自己实现很容易出错，推荐直接使用 Redisson：&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;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:1001&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;lock&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;&lt;span&gt; &lt;/span&gt;&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;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;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;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;6&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;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;ul&gt;
&lt;li&gt;&lt;strong&gt;主从切换&lt;/strong&gt;：主节点宕机、锁尚未同步到从节点时，可能出现两个客户端同时持锁。对一致性要求极高的场景，不要只依赖 Redis，考虑数据库唯一约束或 ZooKeeper 等方案。&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;/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;</content:encoded></item></channel></rss>