<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>正是修行时</title>
    <link>https://www.qtter.com/</link>
    
    <atom:link href="https://www.qtter.com/rss.xml" rel="self" type="application/rss+xml"/>
    
    <description></description>
    <pubDate>Sun, 01 Mar 2026 13:57:58 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>叹息之墙</title>
      <link>https://www.qtter.com/2026/tanxiqiang/</link>
      <guid>https://www.qtter.com/2026/tanxiqiang/</guid>
      <pubDate>Sat, 28 Feb 2026 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;也许多年之后的人们会发现——&lt;br&gt;当初被当作工具的AI，不知何时起变成了一堵叹息之墙。&lt;br&gt;把人类文明，一分为二。&lt;/p&gt;
&lt;p&gt;它不宣战，也不喧哗。&lt;br&gt;却以指数级进化，把努力变得苍白。&lt;br&gt;你十年寒窗，它瞬间完成；&lt;br&gt;你一生经验，它毫秒推演。&lt;/p&gt;
&lt;p&gt;</description>
        
      
      
      
      <content:encoded><![CDATA[<p>也许多年之后的人们会发现——<br>当初被当作工具的AI，不知何时起变成了一堵叹息之墙。<br>把人类文明，一分为二。</p><p>它不宣战，也不喧哗。<br>却以指数级进化，把努力变得苍白。<br>你十年寒窗，它瞬间完成；<br>你一生经验，它毫秒推演。</p><p>当差距大到无法跨越，<br>叹息之墙真正成形。<br>文明更繁荣，系统更高效，<br>却有越来越多的人，被隔绝在核心之外。</p><p>只有极少数人，与AI融合，重构自身，<br>穿过那堵叹息之墙。<br>而墙外，是沉默的人群。<br>人类没有灭绝——只是被分层。<br>可是，穿过墙的他们，还算是人类吗？</p>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/AI/">AI</category>
      
      
      <comments>https://www.qtter.com/2026/tanxiqiang/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>却道天凉好个秋</title>
      <link>https://www.qtter.com/2025/nothing-to-say/</link>
      <guid>https://www.qtter.com/2025/nothing-to-say/</guid>
      <pubDate>Wed, 22 Oct 2025 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;少年不识愁滋味，爱上层楼。爱上层楼，为赋新词强说愁。&lt;br&gt;而今识尽愁滋味，欲说还休。欲说还休，却道天凉好个秋&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>少年不识愁滋味，爱上层楼。爱上层楼，为赋新词强说愁。<br>而今识尽愁滋味，欲说还休。欲说还休，却道天凉好个秋</p></blockquote><span id="more"></span> <hr><p>最近有了一个习惯：晚上饭点的时候，一个人在公司附近漫无目的闲逛。<br>就是随便选一个方向，开始沿着街道走：<br>IF 绿灯: 就直行;<br>ELSE: 红灯就转弯。<br>把自己当作一个机器人一样什么多余的情绪都不关注，就只是默默走路。</p><p>有时候走累了，就在公园的长椅上坐着。发呆。<br>天气渐渐凉快起来了，公园遛娃、遛弯的人们也多了起来。<br>经常就这么坐着看公园里的人们来来往往，小朋友们叽叽喳喳的跑来跑去，一切热闹而安静。</p><blockquote><p>热闹是他们的，而我什么都没有</p></blockquote><p>那种感觉像是整个人从这个世界里抽离出去，作为一个局外人只能隔着屏障看着。<br>这是一种情绪上的自我隔离，麻木。</p><p>我能感觉到现在的我正在失去了对这个世界上正在发生的各种事情关注的好奇心，失去了生活的热情和勇气，沉溺在巨大无边的压抑里。<br>我只能在每一次快要窒息的边缘，尽量的拉起来一下，尽量多呼吸一会，然后又会沉下去。<br>我很想彻底的从这个情绪里挣脱出来，可是那个旋涡是如此的巨大，大得看不到边。<br>而我，也已经不是曾经的我了。</p><p>从两年前得知爸的病情的那一刻，从我人生第一次如此具象的感知到命运的存在。<br>后来我慢慢意识到，是从那一刻起我已经变成了另外一个人。<br>当你真正看到命运的那一刻，就会明白：从此之后你再也无法体会真正的快乐，余生的底色只剩悲凉。</p><blockquote><p>仅一夜之间，我的心判若两人</p></blockquote><p>以前在网上看到人间失格里的这句话，内心充满了鄙夷，感觉作者就是在哗众取宠而已。<br>而真正轮到自己的时候，才真正体会到当作者写下这句话的时候，内心该是多么的绝望。</p><p>原来一个人的改变真的是在一瞬间完成的。</p><p>上个月接爸出院后，医生告知目前还算稳定，三个月后复查。短暂住了几天之后，爸妈便又回老家静养。<br>回想这两年，看着爸去了不知道多少次医院，做了不知道多少检查，各种并发症，然后一次又一次的手术，不停的吃药，人也一天天的衰老了。<br>期间爸妈来上海检查的时候，姐姐姐夫带着孩子也过来了，弟弟弟媳也在。<br>老婆陪着他们一起坐在客厅沙发上看着电视，聊着各种生活的琐碎事情和八卦，姐姐家的孩子也在抢电视看，二狗和$趴在旁边舔毛。<br>我坐在阳台椅子上看着这画面红着眼，几度情绪失控。这本是我想象中最美好的画面啊！<br>可现在我无时无刻的知道，爸真正一天天的衰老下去。而我什么都帮不上，只能按照医嘱，机械的做着交代的事情。<br>我甚至无法控制自己在不停的想象这些，我只能在每一次情绪失控时屏住呼吸，让自己面无表情。</p><p>其实直到现在我都无法说服自己真正接受这个事实。<br>我无法接受这一切为什么会落到爸的头上，为什么啊！如果真的存在命运，我无法接受这种不公。<br>我在内心无数次的反问着，可到头来又能怎样呢？也只能最后说一个世事无常罢了！</p><p>那种无时无刻的压抑感和焦虑开始慢慢的堆积，不停上涨。<br>很多次，我开车在高架上整个人突然之间情绪直接崩溃，眼泪无法控制，视线瞬间模糊。<br>我从开始的恐慌、停车靠边、不停的大口呼吸逼迫自己冷静下来，到后来熟练的减速、快速眨眼让视线重新清晰，仿佛这个身体是另一个人的，一切都有种陌生而剥离的恶心感。厌恶自己，厌恶工作，厌恶这恶毒的命运，厌恶这世界所有的一切的一切！</p><p>我不知道要怎样才能调整过来，变得越来越沉默寡言，死气沉沉。<br>好几次爸也对我说，年轻人要有点朝气，要多出去走走。<br>可是我已经无法提起这种心气了，我感觉我的每天就只是活着，熬着。一切都没有希望了。<br>好多次周末，还是老婆硬拉着我出去，才有出行的计划。其实也只是在公园里或者商场里逛一逛、走一走<br>其他的时间，我哪里都不想去，就一直宅在家里一言不发，疯狂的打游戏。<br>可我在游戏里就像一个疯子，一言不合就开始疯狂的打字咒骂，仿佛这样才可以把身体里所有的情绪倾泻出来。</p><blockquote><p>少年不识愁滋味，爱上层楼。爱上层楼，为赋新词强说愁。<br>而今识尽愁滋味，欲说还休。欲说还休，却道天凉好个秋</p></blockquote><p>我也知道自己的状态很不好，想找人倾诉。<br>可是啊，要从何说起，又要怎么去描述那种心情呢？<br>这个世界上并没有真正的感同身受。</p><p>所以啊，我也只能一个人不停地走走，仿佛这样就可以把这些情绪一点一点的洒在路上，蒸发在空气里。<br>这样人似乎可以稍微轻松一些，然后继续熬着一天又一天。<br>又或者，写在这个无人问津的博客里。<br>而和朋友聊起来时，仍然不知道如何说出来。很多话到嘴边又突然感觉无从说起。<br>是啊，以前总是不停的抱怨各种生活、工作的不如意，仿佛天塌了一样。可真正的痛苦体会到了之后，却只有无法言说的悲哀。<br>而日子还要熬下去啊，不然能怎样呢。一切也只能交给时间。</p><p>当你开始失去少年心气，失去对生活的热情，失去对美好生活的信仰。<br>当你终于慢慢的接受命运，接受这生活带给你的一切。<br>虽然你在知道一切都还在继续，鼓起勇气在接下来的每天。但是你内心里无比清晰的知道，自己已经永远的变成另一个人了。<br>而有些事，也已经永远无法改变了。<br>最后的最后，每当和人谈起，也只能苦涩的说一句，天气越来越凉了啊！</p>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/%E7%94%9F%E6%B4%BB/">生活</category>
      
      
      <comments>https://www.qtter.com/2025/nothing-to-say/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>基于 OpenAPI + libopenapi-validator 的接口参数统一校验方案</title>
      <link>https://www.qtter.com/2025/libopenapi-validator/</link>
      <guid>https://www.qtter.com/2025/libopenapi-validator/</guid>
      <pubDate>Tue, 14 Oct 2025 16:00:00 GMT</pubDate>
      
      <description>在现代多团队协作的服务体系中，接口标准化、自动化校验和文档同步尤为重要。本文介绍如何基于 OpenAPI + Hertz + libopenapi-validator 实现统一接口参数验证与自动化文档生成。</description>
      
      
      
      <content:encoded><![CDATA[<h2 id="一、背景与问题"><a href="#一、背景与问题" class="headerlink" title="一、背景与问题"></a>一、背景与问题</h2><p>在互联网行业，大型企业或多团队协作的服务体系中，基于 API 接口的协作应该是互联网的产品最常见的方式了。<br>而在这种协作方式下，总是会出现一些大家喜闻乐见，比较有代表性的问题：</p><ul><li><strong>接口定义不一致</strong>：后端实现与文档脱节，调用方依据旧文档开发。</li><li><strong>参数校验逻辑分散</strong>：每个模块独立实现参数验证，重复劳动且易出错。</li><li><strong>文档更新滞后</strong>：手动维护 OpenAPI 文档，常常遗漏更新。</li><li><strong>接口变更风险高</strong>：无法快速检测接口参数与返回值格式的兼容性问题。</li></ul><p>一般的解决思路和做法是：各个团队统一遵守某种api设计和开发风格规范（如果你有一些经验，一定听说过 RESTful、 Schema<br> 这些关键词）来协作。<br>思路没错，但是真正在落地的过程中，往往结果不尽人意。<br>这里面比较典型的就是很多人没有真正搞清楚 RESTful、 OpenAPI、Schema 的区别：</p><h3 id="RESTful、OpenAPI-与-Schema-的关系与区别"><a href="#RESTful、OpenAPI-与-Schema-的关系与区别" class="headerlink" title="RESTful、OpenAPI 与 Schema 的关系与区别"></a>RESTful、OpenAPI 与 Schema 的关系与区别</h3><p>在现代 API 设计中，RESTful、OpenAPI 和 Schema 是三个密切相关但各自定位不同的概念。理解它们的关系有助于在微服务和多团队协作中规范接口设计、自动化文档和参数校验。</p><ul><li><p>定义和本质</p><ul><li>RESTful： 架构风格&#x2F;设计理念，指导如何设计接口，定义资源、URI、HTTP 方法、状态码等规范</li><li>OpenAPI： 标准化接口文档规范，描述整个接口：路径、方法、请求&#x2F;响应参数、认证、状态码等，可用于文档生成、SDK、Mock、校验</li><li>Schema：数据结构描述，定义请求体或响应体的数据结构，包括字段类型、约束、必填项等，可被多个接口复用</li></ul></li><li><p>RESTful → OpenAPI → Schema 是一种自然的层级关系：</p><ul><li>RESTful：告诉你“接口怎么设计”，即资源和方法。</li><li>OpenAPI：告诉你“接口具体长什么样”，包含路径、方法、请求&#x2F;响应等。</li><li>Schema：告诉你“请求&#x2F;响应数据长什么样”，是 OpenAPI 的一部分，用来定义数据模型。  <figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">RESTful (接口设计风格)</span><br><span class="line">    │</span><br><span class="line">    ▼</span><br><span class="line">OpenAPI (接口文档规范)</span><br><span class="line">    ├─ paths</span><br><span class="line">    │    ├─ /users (GET/POST)</span><br><span class="line">    │    └─ /orders (GET/POST)</span><br><span class="line">    └─ components</span><br><span class="line">            └─ schemas</span><br><span class="line">                ├─ User</span><br><span class="line">                └─ Order</span><br></pre></td></tr></table></figure></li></ul></li></ul><p><strong>所以，想要真正的解决上面的问题，就需要基于 OpenAPI 的规范&#x2F;标准 来定义一套 api 接口。</strong></p><p>基于我们自己的技术栈，我们设计并落地了一套基于 <strong>OpenAPI Schema + Hertz 框架 + <a href="github.com/pb33f/libopenapi-validator">pb33f&#x2F;libopenapi-validator</a></strong> 的统一接口校验方案，并通过 <strong>GitHub Action CI 自动化流程</strong> 实现 schema 文件合并与 API 文档生成。</p><hr><h2 id="二、方案总体架构"><a href="#二、方案总体架构" class="headerlink" title="二、方案总体架构"></a>二、方案总体架构</h2><p>整个系统的设计目标是实现 <strong>“接口即规范、文档即代码”</strong>。<br>架构流程如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">┌───────────────────────────────────────┐</span><br><span class="line">│                Client                 </span><br><span class="line">│   (发起 HTTP 请求，请求 JSON 数据)     </span><br><span class="line">└───────────────────────────────────────┘</span><br><span class="line">                      │</span><br><span class="line">                      ▼</span><br><span class="line">         ┌───────────────────────┐</span><br><span class="line">         │     Hertz 框架路由层     </span><br><span class="line">         │ (app.Use(Validator())) </span><br><span class="line">         └───────────────────────┘</span><br><span class="line">                      │</span><br><span class="line">                      ▼</span><br><span class="line">    ┌───────────────────────────────────┐</span><br><span class="line">    │   Validator 中间件 (自定义逻辑) </span><br><span class="line">    │                                </span><br><span class="line">    │ 1. 解析请求路径 + Method       </span><br><span class="line">    │ 2. 根据 OpenAPI Schema 找到对应规则 </span><br><span class="line">    │ 3. 调用 libopenapi-validator   </span><br><span class="line">    │    对请求参数进行验证          </span><br><span class="line">    │ 4. 校验失败返回 400 + 错误信息 </span><br><span class="line">    └───────────────────────────────────┘</span><br><span class="line">                      │</span><br><span class="line">                      ▼</span><br><span class="line">      ┌──────────────────────────────┐</span><br><span class="line">      │       业务 Handler 逻辑        </span><br><span class="line">      │  (若校验通过则正常执行逻辑)   </span><br><span class="line">      └──────────────────────────────┘</span><br><span class="line">                      │</span><br><span class="line">                      ▼</span><br><span class="line">┌───────────────────────────────────────────┐</span><br><span class="line">│           返回响应数据                </span><br><span class="line">│     (可选：libopenapi-validator 校验响应) </span><br><span class="line">└───────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><p>该架构实现了从 <strong>Schema 定义 → 校验 → 文档生成 → 运行时验证</strong> 的完整闭环。</p><hr><h2 id="三、技术选型与组件说明"><a href="#三、技术选型与组件说明" class="headerlink" title="三、技术选型与组件说明"></a>三、技术选型与组件说明</h2><table><thead><tr><th>模块</th><th>技术选型</th><th>说明</th></tr></thead><tbody><tr><td><strong>接口定义</strong></td><td>OpenAPI 3.1 (YAML&#x2F;JSON)</td><td>统一定义接口结构、请求&#x2F;响应参数及约束</td></tr><tr><td><strong>服务框架</strong></td><td><a href="https://www.cloudwego.io/docs/hertz/">Hertz</a></td><td>高性能 HTTP 框架，支持自定义中间件</td></tr><tr><td><strong>Schema 校验</strong></td><td><a href="https://github.com/pb33f/libopenapi-validator">pb33f&#x2F;libopenapi-validator</a></td><td>基于 OpenAPI Schema 的参数与响应验证</td></tr><tr><td><strong>CI 自动化</strong></td><td>GitHub Actions</td><td>自动合并 Schema、生成完整 openapi.yaml、发布文档</td></tr><tr><td><strong>文档生成</strong></td><td>Redoc &#x2F; Swagger UI</td><td>自动化可视化 API 文档，方便协作与审查</td></tr></tbody></table><hr><h2 id="方案细节"><a href="#方案细节" class="headerlink" title="方案细节"></a>方案细节</h2><h3 id="⚙️-自动化生成完整的-OpenAPI-Schema（基于-GitHub-Actions）"><a href="#⚙️-自动化生成完整的-OpenAPI-Schema（基于-GitHub-Actions）" class="headerlink" title="⚙️ 自动化生成完整的 OpenAPI Schema（基于 GitHub Actions）"></a>⚙️ 自动化生成完整的 OpenAPI Schema（基于 GitHub Actions）</h3><p>在实际项目中，我们通常不会把所有接口都写进一个 openapi.yaml 文件。<br>而是会按模块、功能、微服务进行拆分，以便于多人协作与模块化维护，比如：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">openapi/</span><br><span class="line">├── components/</span><br><span class="line">│   ├── schemas/</span><br><span class="line">│   │   ├── user<span class="selector-class">.yaml</span></span><br><span class="line">│   │   ├── tenant<span class="selector-class">.yaml</span></span><br><span class="line">│   │   └── common<span class="selector-class">.yaml</span></span><br><span class="line">│   └── parameters/</span><br><span class="line">│       ├── pagination<span class="selector-class">.yaml</span></span><br><span class="line">│       └── auth<span class="selector-class">.yaml</span></span><br><span class="line">├── paths/</span><br><span class="line">│   ├── users<span class="selector-class">.yaml</span></span><br><span class="line">│   ├── tenants<span class="selector-class">.yaml</span></span><br><span class="line">│   └── health<span class="selector-class">.yaml</span></span><br><span class="line">└── root.yaml</span><br></pre></td></tr></table></figure><p>而 <a href="github.com/pb33f/libopenapi-validator">libopenapi-validator</a> 库要求传入的是一个 完整的、可解析的 OpenAPI 文档。<br>因此，在执行校验前，我们需要一个步骤：把所有分散的 schema 文件合并为一份完整的 openapi.yaml。<br>解决方案：通过 GitHub Actions 在每次schema提交时自动合并为一份完整的 openapi.yaml。</p><h4 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h4><p>可以在 <code>.github/workflows/merge-openapi.yaml</code> 中添加如下配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">Merge</span> <span class="string">OpenAPI</span> <span class="string">Schema</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span> [ <span class="string">main</span>, <span class="string">test</span> ]</span><br><span class="line">  <span class="attr">pull_request:</span></span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">merge-schema:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line"></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Checkout</span> <span class="string">Repository</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/checkout@v4</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Install</span> <span class="string">OpenAPI</span> <span class="string">CLI</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">npm</span> <span class="string">install</span> <span class="string">-g</span> <span class="string">@redocly/cli</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Merge</span> <span class="string">OpenAPI</span> <span class="string">files</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string">          redocly bundle openapi/main.yaml -o dist/openapi.yaml</span></span><br><span class="line"><span class="string">          echo &quot;✅ OpenAPI schema merged successfully.&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Upload</span> <span class="string">artifact</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/upload-artifact@v4</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">name:</span> <span class="string">openapi-schema</span></span><br><span class="line">          <span class="attr">path:</span> <span class="string">dist/openapi.yaml</span></span><br></pre></td></tr></table></figure><p>这样，每次提交或合并请求时，都会自动生成完整的 <code>openapi.yaml</code>，确保校验与文档生成的输入一致。</p><hr><h3 id="📘-GitHub-Action-自动生成-API-文档"><a href="#📘-GitHub-Action-自动生成-API-文档" class="headerlink" title="📘 GitHub Action 自动生成 API 文档"></a>📘 GitHub Action 自动生成 API 文档</h3><p>Redocly CLI 除了支持 bundle 合并外，还可以生成一个完整的 HTML API 文档。 </p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Generate</span> <span class="string">API</span> <span class="string">Docs</span></span><br><span class="line">  <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string">    npx redoc-cli bundle dist/openapi.yaml -o docs/index.html</span></span><br><span class="line"><span class="string">    echo &quot;✅ API docs generated.&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">Docs</span> <span class="string">to</span> <span class="string">GitHub</span> <span class="string">Pages</span></span><br><span class="line">  <span class="attr">uses:</span> <span class="string">peaceiris/actions-gh-pages@v3</span></span><br><span class="line">  <span class="attr">with:</span></span><br><span class="line">    <span class="attr">github_token:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">&#125;&#125;</span></span><br><span class="line">    <span class="attr">publish_dir:</span> <span class="string">./docs</span></span><br></pre></td></tr></table></figure><p>这样，开发者和 QA 可以直接访问统一入口，例如：</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:<span class="regexp">//y</span>our-org.github.io<span class="regexp">/api-docs/</span></span><br></pre></td></tr></table></figure><p>从而实现**“接口定义即文档”**。</p><hr><h3 id="在-Hertz-中接入统一参数校验"><a href="#在-Hertz-中接入统一参数校验" class="headerlink" title="在 Hertz 中接入统一参数校验"></a>在 Hertz 中接入统一参数校验</h3><p>在业务服务中，我们可以在 Hertz 框架中接入 <code>libopenapi-validator</code> 作为中间件，对每个请求进行统一验证。</p><p>示例中间件结构如下：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;context&quot;</span></span><br><span class="line">    <span class="string">&quot;os&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">&quot;github.com/cloudwego/hertz/pkg/app&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/cloudwego/hertz/pkg/app/server&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/pb33f/libopenapi-validator&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    h := server.Default()</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 加载 OpenAPI schema</span></span><br><span class="line">    data, _ := os.ReadFile(<span class="string">&quot;dist/openapi.yaml&quot;</span>)</span><br><span class="line">    validator, _ := libopenapi_validator.NewValidator(data)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 注册中间件</span></span><br><span class="line">    h.Use(<span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, c *app.RequestContext)</span></span> &#123;</span><br><span class="line">        result := validator.ValidateHttpRequest(c.Request)</span><br><span class="line">        <span class="keyword">if</span> !result.Valid &#123;</span><br><span class="line">            c.JSON(<span class="number">400</span>, <span class="keyword">map</span>[<span class="type">string</span>]<span class="type">string</span>&#123;</span><br><span class="line">                <span class="string">&quot;error&quot;</span>: result.Message,</span><br><span class="line">            &#125;)</span><br><span class="line">            c.Abort()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        c.Next(ctx)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    h.Spin()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此中间件在请求进入控制器前执行，确保：</p><ul><li>所有参数符合 OpenAPI 定义；</li><li>缺失字段、类型错误、格式不匹配都会直接拦截；</li><li>响应数据也可在返回前进行 schema 校验，保证契约一致性。</li></ul><hr><h2 id="方案带来的协作价值"><a href="#方案带来的协作价值" class="headerlink" title="方案带来的协作价值"></a>方案带来的协作价值</h2><p>这套方案在公司内部协作层面带来多重正向影响：</p><ol><li><p><strong>后端开发标准化</strong><br>所有接口参数和响应体均有明确的 OpenAPI 定义，不再依赖个人文档习惯。</p></li><li><p><strong>前后端协作提效</strong><br>前端可通过自动生成的 Redoc&#x2F;Swagger 文档直接 Mock 数据，提前并行开发。</p></li><li><p><strong>测试自动化增强</strong><br>QA 团队可以基于 OpenAPI 自动生成测试用例，减少手工校验工作量。</p></li><li><p><strong>变更可追溯</strong><br>每次接口改动都伴随 CI 合并与验证记录，方便回溯与审查。</p></li><li><p><strong>质量保障内建化</strong><br>接口不再仅靠 code review 发现问题，schema 校验成为“自动防线”。</p></li></ol><hr><h2 id="八、总结与展望"><a href="#八、总结与展望" class="headerlink" title="八、总结与展望"></a>八、总结与展望</h2><p>通过 <strong>OpenAPI + Hertz + libopenapi-validator</strong> 的组合，我们实现了：</p><ul><li>统一接口契约定义；</li><li>自动化 Schema 合并与校验；</li><li>在线文档实时同步；</li><li>运行时参数与响应验证；</li><li>协作链路透明化。</li></ul><p>未来可以进一步扩展：</p><ul><li>接入 <strong>API Diff 检测</strong>，在 CI 中检测接口兼容性变化；</li><li>集成 <strong>监控与日志系统</strong>，追踪接口调用与验证失败率；</li><li>在 <strong>多租户场景</strong> 下实现 schema 动态加载。</li></ul><p>这套体系使得接口标准真正成为团队协作的“中枢神经”，让 API 管理和验证进入自动化、标准化的新阶段。</p><hr><blockquote><p>💡 <strong>参考项目：</strong></p><ul><li><a href="https://github.com/pb33f/libopenapi-validator">pb33f&#x2F;libopenapi-validator</a>  </li><li><a href="https://www.cloudwego.io/docs/hertz/">CloudWeGo Hertz</a>  </li><li><a href="https://redocly.com/docs/cli/">Redocly CLI</a></li></ul></blockquote>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/OpenAPI/">OpenAPI</category>
      
      <category domain="https://www.qtter.com/tags/Hertz/">Hertz</category>
      
      <category domain="https://www.qtter.com/tags/Golang/">Golang</category>
      
      <category domain="https://www.qtter.com/tags/libopenapi-validator/">libopenapi-validator</category>
      
      <category domain="https://www.qtter.com/tags/GitHub-Actions/">GitHub Actions</category>
      
      
      <comments>https://www.qtter.com/2025/libopenapi-validator/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>再次鼓起丧失的勇气</title>
      <link>https://www.qtter.com/2025/Soul-Booster%E2%80%8C/</link>
      <guid>https://www.qtter.com/2025/Soul-Booster%E2%80%8C/</guid>
      <pubDate>Sun, 14 Sep 2025 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;再次鼓起丧失的勇气&lt;br&gt;   ——来自振魂石的寄语&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>再次鼓起丧失的勇气<br>   ——来自振魂石的寄语</p></blockquote><span id="more"></span> <p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/soul-booster.jpg" alt="soul-booster"></p><p>2025-09-15 TI14 结束了，属于 dotaer 们的夏天也结束了。</p><p>XG 最终倒在了总决赛，离冠军，离那个让无数中国刀塔玩家魂牵梦绕的不朽盾仅一步之遥。<br>同样的2-3，同样的决胜局的猛犸，同样的AME。<br>很难想象，这样的剧情对于AME而言，已经上演了三次！<br>而离中国队上一次举起不朽盾，也已经是2016年的事了。<br>时隔九年，未尝一冠。</p><p>最后一天的比赛下午4点开始，从半决赛开始之前就有点心神不宁，现在看来，似乎在看到最后的结局之前已经有了不好的预感。<br>期间断断续续的看着 XG 的半决赛峰回路转赢了下来，很惊喜，开始有了一丝希望：难道今年真的有奇迹么？</p><p>而真正的总决赛开始时，心情很复杂，又想看又有点不敢看直播。<br>我开着笔记本，放着直播，然后打开台式机听着直播的声音，自己开始天梯匹配。<br>这是一种有点可笑的、莫名其妙的想法：仿佛只要我不看直播，XG 就不会输，就可以夺冠。<br>最后甚至连直播的声音都不敢听了，在 总决赛 BO5 的 比分 1-1 时，我决定关掉直播，去睡觉。<br>睡前我在期待，一觉醒来 XG 夺冠。</p><p>而最终的结局还是事与愿违，电子竞技的残酷竟和生活本身如此相像。<br>命运，总是喜欢突如其来的开这种功败垂成、勇士倒在黎明曙光前一刻的烂俗玩笑。<br>不管是游戏，还是生活</p><p>我知道今天，有无数个中国DOTA2玩家浑浑噩噩的度过<br>其实想想，这些职业选手和战队是不是夺冠好像对我也没什么影响不是么<br>为什么自己的心情会受到如此大的影响呢？</p><p>仔细想来，可能对我而言，包括也对于大多数玩家而言，这已经不是仅仅是一个游戏了吧<br>一路走来，早已把比赛关联到自己的生活本身了吧，而游戏本身已经变成了生活的投射<br>对DOTA2而言，我们有人在其中释放生活的压力，有人在其中享受和朋友并肩作战的乐趣，有人感受着其中英雄和道具的故事起源而带来的鼓舞和振奋<br>对我而言，倾注越来越多的时间和精力之后，游戏开始慢慢融入到生活的每一个角落，开始潜移默化的影响着我</p><p>仿佛游戏胜利，我们就可以战胜自己的心魔<br>战胜这 或苦闷、压抑，或无趣、平庸，或苦难、绝望的生活<br>仿佛只要他们拿下冠军，举起不朽盾，我们自己的生活也会彻底改变，充满希望。<br>这种关联是如此的没有逻辑，确又如此真实的发生着。</p><p>只是不管如何的不愿意接受，TI14 还是结束了。<br>而生活也还是要继续啊！<br>不管愿不愿意，总是要再次打起精神，新的一局又开始了。<br>比赛之前，我买了DOTA2中的一个道具：振魂石</p><blockquote><p>再次鼓起丧失的勇气</p></blockquote><p>这是振魂石的寄语，也是我为数不多的精神buff。<br>不断告诫自己：不论面对什么样的困境甚至绝境，都可以再次鼓起丧失的勇气<br>为游戏，也为生活！</p><p>去相信吧！就像赛后一个博主说的：<strong>如果结局并不圆满，那就说明这并不是结局！</strong><br>虽然大家这些年一直戏称它为 dead game，但是它并没有死。<br>无数玩家剑心犹在！<br>一切都远没有结束，DOTA2是，生活也是！</p><p>最后：<br>明年，TI15 又一次回到上海举办，到时候一定要去现场！</p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/DOTA/">DOTA</category>
      
      
      <category domain="https://www.qtter.com/tags/TI/">TI</category>
      
      <category domain="https://www.qtter.com/tags/DOTA/">DOTA</category>
      
      
      <comments>https://www.qtter.com/2025/Soul-Booster%E2%80%8C/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>ACME 协议 &amp; Let&#39;s Encrypt 证书申请流程详解</title>
      <link>https://www.qtter.com/2025/acme-protocol/</link>
      <guid>https://www.qtter.com/2025/acme-protocol/</guid>
      <pubDate>Wed, 09 Jul 2025 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;本文主要内容由 ChatGPT 生成&lt;br&gt;伸手党可以直接跳过全文，下载脚本：&lt;a href=&quot;https://github.com/fakerqtter/vibe-coding/tree/main/acme-free&quot;&gt;acme-free&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>本文主要内容由 ChatGPT 生成<br>伸手党可以直接跳过全文，下载脚本：<a href="https://github.com/fakerqtter/vibe-coding/tree/main/acme-free">acme-free</a></p></blockquote><span id="more"></span> <h2 id="📖-什么是-ACME？"><a href="#📖-什么是-ACME？" class="headerlink" title="📖 什么是 ACME？"></a>📖 什么是 ACME？</h2><p>ACME（Automatic Certificate Management Environment）是由 <a href="https://letsencrypt.org/">Let’s Encrypt</a> 提出，并由 <a href="https://datatracker.ietf.org/doc/html/rfc8555">IETF RFC 8555</a> 标准化的协议。</p><p>它允许客户端自动完成 HTTPS 证书的：</p><ul><li>申请（Order）</li><li>域名验证（Authorization &amp; Challenge）</li><li>签发与下载（Certificate）</li></ul><hr><h2 id="🧱-核心概念"><a href="#🧱-核心概念" class="headerlink" title="🧱 核心概念"></a>🧱 核心概念</h2><table><thead><tr><th>概念</th><th>含义</th></tr></thead><tbody><tr><td><strong>Account</strong></td><td>注册者账户，标识用户（通过公钥）</td></tr><tr><td><strong>Order</strong></td><td>一次申请证书的请求，包含多个域名</td></tr><tr><td><strong>Authorization</strong></td><td>每个域名对应的授权验证流程</td></tr><tr><td><strong>Challenge</strong></td><td>实际用于验证的方式，如 DNS-01、HTTP-01、TLS-ALPN-01</td></tr><tr><td><strong>Finalize</strong></td><td>提交 CSR 的步骤，表明已完成所有验证</td></tr><tr><td><strong>Certificate</strong></td><td>最终由 CA 签发的证书内容</td></tr></tbody></table><hr><h2 id="✅-完整的证书申请流程（以-DNS-01-为例）"><a href="#✅-完整的证书申请流程（以-DNS-01-为例）" class="headerlink" title="✅ 完整的证书申请流程（以 DNS-01 为例）"></a>✅ 完整的证书申请流程（以 DNS-01 为例）</h2><h3 id="1-创建账户"><a href="#1-创建账户" class="headerlink" title="1. 创建账户"></a>1. 创建账户</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /acme/new-acct</span><br></pre></td></tr></table></figure><ul><li>客户端生成一对密钥</li><li>使用 JWS（带签名的 JSON）请求创建账户</li><li>返回 <code>Account URL</code></li></ul><hr><h3 id="2-创建-Order（订单）"><a href="#2-创建-Order（订单）" class="headerlink" title="2. 创建 Order（订单）"></a>2. 创建 Order（订单）</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /acme/new-order</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;identifiers&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;dns&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;example.com&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;dns&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;www.example.com&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><ul><li>返回一个 Order 对象，包含：<ul><li><code>Authorization URL</code>（每个域名一个）</li><li><code>Finalize URL</code>（CSR 提交用）</li></ul></li></ul><hr><h3 id="3-获取-Authorization（验证信息）"><a href="#3-获取-Authorization（验证信息）" class="headerlink" title="3. 获取 Authorization（验证信息）"></a>3. 获取 Authorization（验证信息）</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GET /acme/authz/XXX</span><br></pre></td></tr></table></figure><ul><li>包含一个或多个 <code>Challenge</code><ul><li>DNS-01</li><li>HTTP-01</li><li>TLS-ALPN-01</li></ul></li></ul><hr><h3 id="4-响应-Challenge"><a href="#4-响应-Challenge" class="headerlink" title="4. 响应 Challenge"></a>4. 响应 Challenge</h3><p>以 DNS-01 为例：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">记录名：_acme-challenge.example.com</span><br><span class="line">记录值：（token + account key 生成的值）</span><br></pre></td></tr></table></figure><p>客户端发起：</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /acme/challenge/XYZ</span><br></pre></td></tr></table></figure><p>表示“我准备好了”，等待验证生效。</p><hr><h3 id="5-等待验证通过"><a href="#5-等待验证通过" class="headerlink" title="5. 等待验证通过"></a>5. 等待验证通过</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GET /acme/authz/XYZ</span><br></pre></td></tr></table></figure><ul><li>轮询直到状态为 <code>&quot;valid&quot;</code> 或 <code>&quot;invalid&quot;</code></li></ul><hr><h3 id="6-Finalize-订单（提交-CSR）"><a href="#6-Finalize-订单（提交-CSR）" class="headerlink" title="6. Finalize 订单（提交 CSR）"></a>6. Finalize 订单（提交 CSR）</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /acme/finalize/XYZ</span><br></pre></td></tr></table></figure><ul><li>提交你的 CSR（证书签名请求）</li><li>返回的 Order 状态变为 <code>valid</code>，并附带 Certificate URL</li></ul><hr><h3 id="7-下载证书"><a href="#7-下载证书" class="headerlink" title="7. 下载证书"></a>7. 下载证书</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GET /acme/cert/XYZ</span><br></pre></td></tr></table></figure><ul><li>获取 PEM 格式的证书链（包含 leaf cert + CA cert）</li></ul><hr><h2 id="🔄-可恢复流程说明"><a href="#🔄-可恢复流程说明" class="headerlink" title="🔄 可恢复流程说明"></a>🔄 可恢复流程说明</h2><p>ACME 支持流程中断恢复：</p><ul><li>保存 <strong>Account URL</strong>（标识你是谁）</li><li>保存 <strong>Order URL</strong>（可以重复访问）</li><li>保存 <strong>Authorization&#x2F;Challenge 状态</strong></li><li>没有状态超时的步骤可以按需恢复继续执行</li></ul><hr><h2 id="📦-推荐实现方式"><a href="#📦-推荐实现方式" class="headerlink" title="📦 推荐实现方式"></a>📦 推荐实现方式</h2><table><thead><tr><th>Go 实现库</th><th>控制级别</th><th>说明</th></tr></thead><tbody><tr><td><a href="https://github.com/go-acme/lego"><code>lego</code></a></td><td>高</td><td>封装全面，支持多 DNS 服务商</td></tr><tr><td><a href="https://pkg.go.dev/golang.org/x/crypto/acme"><code>golang.org/x/crypto/acme</code></a></td><td>极高</td><td>原生协议控制，适合定制验证流程和持久化恢复等高级功能</td></tr></tbody></table><hr><h2 id="🔄-流程图（简化）"><a href="#🔄-流程图（简化）" class="headerlink" title="🔄 流程图（简化）"></a>🔄 流程图（简化）</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">+---------+      +-------------+     +---------------+</span><br><span class="line">| Client  | ---&gt; | newAccount  | --&gt; |    Account    |</span><br><span class="line">+---------+      +-------------+     +---------------+</span><br><span class="line"></span><br><span class="line">+---------+      +-------------+     +---------------+</span><br><span class="line">| Client  | ---&gt; |  newOrder   | --&gt; |     Order     |</span><br><span class="line">+---------+      +-------------+     +--------+------+</span><br><span class="line">                                            |</span><br><span class="line">                                  +---------v----------+</span><br><span class="line">                                  |   Authorization[]   |</span><br><span class="line">                                  +----------+----------+</span><br><span class="line">                                             |</span><br><span class="line">                                +------------v-------------+</span><br><span class="line">                                |        Challenge[]        |</span><br><span class="line">                                +------------+--------------+</span><br><span class="line">                                             |</span><br><span class="line">                          +------------------v------------------+</span><br><span class="line">                          |    完成验证：DNS/HTTP 上传数据       |</span><br><span class="line">                          +------------------+------------------+</span><br><span class="line"></span><br><span class="line">+---------+      +-------------+     +---------------+</span><br><span class="line">| Client  | ---&gt; |  finalize   | --&gt; |  Order(Ready) |</span><br><span class="line">+---------+      +-------------+     +-------+-------+</span><br><span class="line">                                            |</span><br><span class="line">                                  +---------v----------+</span><br><span class="line">                                  |    Get Certificate  |</span><br><span class="line">                                  +---------------------+</span><br></pre></td></tr></table></figure><hr><h2 id="✅-总结"><a href="#✅-总结" class="headerlink" title="✅ 总结"></a>✅ 总结</h2><p>如果你需要：</p><ul><li>🔄 支持中断恢复</li><li>🎯 精确控制每个步骤</li><li>💾 本地持久化订单、认证、挑战状态</li></ul><p>推荐使用：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;golang.org/x/crypto/acme&quot;</span></span><br></pre></td></tr></table></figure><p>配合手动实现持久化与控制逻辑，可获得最大自由度。</p><h2 id="vibe-coding"><a href="#vibe-coding" class="headerlink" title="vibe coding"></a>vibe coding</h2><p>最后也体验了一把 vibe coding，实现了一个自助申请证书的脚本：<a href="https://github.com/fakerqtter/vibe-coding/tree/main/acme-free">acme-free</a></p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%8A%80%E6%9C%AF/">技术</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%8A%80%E6%9C%AF/">技术</category>
      
      
      <comments>https://www.qtter.com/2025/acme-protocol/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>兰亭集序</title>
      <link>https://www.qtter.com/2025/lantingjixu/</link>
      <guid>https://www.qtter.com/2025/lantingjixu/</guid>
      <pubDate>Sun, 15 Jun 2025 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;永和九年，岁在癸丑，暮春之初，会于会稽山阴之兰亭，修禊事也。&lt;br&gt;群贤毕至，少长咸集。&lt;br&gt;此地有崇山峻岭，茂林修竹，又有清流激湍，映带左右，引以为流觞曲水，列坐其次。&lt;br&gt;虽无丝竹管弦之盛，一觞一咏，亦足以畅叙幽情。  &lt;/p&gt;
&lt;/blo</description>
        
      
      
      
      <content:encoded><![CDATA[<blockquote><p>永和九年，岁在癸丑，暮春之初，会于会稽山阴之兰亭，修禊事也。<br>群贤毕至，少长咸集。<br>此地有崇山峻岭，茂林修竹，又有清流激湍，映带左右，引以为流觞曲水，列坐其次。<br>虽无丝竹管弦之盛，一觞一咏，亦足以畅叙幽情。  </p></blockquote><blockquote><p>是日也，天朗气清，惠风和畅。<br>仰观宇宙之大，俯察品类之盛，所以游目骋怀，足以极视听之娱，信可乐也。  </p></blockquote><blockquote><p>夫人之相与，俯仰一世。<br>或取诸怀抱，悟言一室之内；或因寄所托，放浪形骸之外。<br>虽趣舍万殊，静躁不同，当其欣于所遇，暂得于己，快然自足，不知老之将至；<br>及其所之既倦，情随事迁，感慨系之矣。<br>向之所欣，俯仰之间，已为陈迹，犹不能不以之兴怀，况修短随化，终期于尽！<br>古人云：“死生亦大矣。”<br>岂不痛哉！  </p></blockquote><blockquote><p>每览昔人兴感之由，若合一契，未尝不临文嗟悼，不能喻之于怀。<br>固知一死生为虚诞，齐彭殇为妄作。<br>后之视今，亦犹今之视昔，悲夫！<br>故列叙时人，录其所述，虽世殊事异，所以兴怀，其致一也。<br>后之览者，亦将有感于斯文。  </p></blockquote>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/%E6%9C%89%E6%84%9F/">有感</category>
      
      
      <comments>https://www.qtter.com/2025/lantingjixu/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>勇往直前</title>
      <link>https://www.qtter.com/2025/keep-moving/</link>
      <guid>https://www.qtter.com/2025/keep-moving/</guid>
      <pubDate>Sat, 14 Jun 2025 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;一个看了很多遍的DOTA2 传奇站队的算是记录片吧。&lt;br&gt;很羡慕这些有着顶级天赋的人，这样的人生才能真正说出不枉此生吧！&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>一个看了很多遍的DOTA2 传奇站队的算是记录片吧。<br>很羡慕这些有着顶级天赋的人，这样的人生才能真正说出不枉此生吧！</p></blockquote><span id="more"></span> <iframe src="https://www.bilibili.com/bangumi/play/ep425640/?share_source=copy_web"   scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"   width="640" height="360"> </iframe>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/%E6%B8%B8%E6%88%8F/">游戏</category>
      
      <category domain="https://www.qtter.com/tags/dota2/">dota2</category>
      
      
      <comments>https://www.qtter.com/2025/keep-moving/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Dota2 开场动画</title>
      <link>https://www.qtter.com/dota2/index/</link>
      <guid>https://www.qtter.com/dota2/index/</guid>
      <pubDate>Fri, 12 Jul 2024 07:24:54 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;别说牛逼——&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>别说牛逼——</p></blockquote><span id="more"></span><video width="640" height="360"  controls loop muted>  <source src="https://static.qtter.com/videos/dota/dota2.mp4" type="video/mp4"></video>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%B8%B8%E6%88%8F/">游戏</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%B8%B8%E6%88%8F/">游戏</category>
      
      <category domain="https://www.qtter.com/tags/dota2/">dota2</category>
      
      
      <comments>https://www.qtter.com/dota2/index/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>最后一舞</title>
      <link>https://www.qtter.com/2024/last-dance/</link>
      <guid>https://www.qtter.com/2024/last-dance/</guid>
      <pubDate>Sat, 06 Jul 2024 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;大魔导师，最后一舞&lt;br&gt;30岁，已是英雄迟暮&lt;br&gt;电子竞技的魅力于残酷就在于此吧&lt;br&gt;只是不知道在他心中，利雅得的夏天是否像18年的那个夏天一样&lt;br&gt;充满着炎热的遗憾&lt;br&gt;生活也是如此吧，在逆风的日子里&lt;br&gt;大家默默打钱吧！&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>大魔导师，最后一舞<br>30岁，已是英雄迟暮<br>电子竞技的魅力于残酷就在于此吧<br>只是不知道在他心中，利雅得的夏天是否像18年的那个夏天一样<br>充满着炎热的遗憾<br>生活也是如此吧，在逆风的日子里<br>大家默默打钱吧！</p></blockquote><span id="more"></span><p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/dota/fy.jpg" alt="fy·god"></p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%88%91%E5%BD%93%E7%84%B6%E5%9C%A8%E6%89%AF%E6%B7%A1/">我当然在扯淡</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      <category domain="https://www.qtter.com/tags/2024/">2024</category>
      
      
      <comments>https://www.qtter.com/2024/last-dance/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>一个活在未来的人</title>
      <link>https://www.qtter.com/2024/a-feture-man/</link>
      <guid>https://www.qtter.com/2024/a-feture-man/</guid>
      <pubDate>Wed, 28 Feb 2024 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;我有个朋友，他最近很迷茫。&lt;/p&gt;
&lt;p&gt;最近有个朋友和我聊天，说了他最近的困惑和迷茫的心态，让我颇为感慨。&lt;/p&gt;
&lt;p&gt;他说，他一直觉得自己是一个活在未来的人。&lt;/p&gt;
&lt;p&gt;怎么理解，我问。&lt;/p&gt;
&lt;p&gt;他给的解释是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;</description>
        
      
      
      <enclosure url="https://www.qtter.com/img/bg-2.jpeg" type="image"/>
      
      
      <content:encoded><![CDATA[<p>我有个朋友，他最近很迷茫。</p><p>最近有个朋友和我聊天，说了他最近的困惑和迷茫的心态，让我颇为感慨。</p><p>他说，他一直觉得自己是一个活在未来的人。</p><p>怎么理解，我问。</p><p>他给的解释是这样的：</p><blockquote><p>我一直以来的思考和做事的方式都是以未来为方向的。好像冥冥中我知道自己未来是什么样的。过去和现在所有的一切都只是暂时的，都只是通向那个未来的一个路径而已。</p><p>所以这个过程中的所学所想、所以的经历对于我来说好像都是一个过场一样，而这个过程中我都不会为这些暂时的过程所绊住。因为我的心里无时无刻都有个声音在告诉我：你懂的，这一切都只是暂时的，是个过程而已。</p><p>因为觉得一切都是暂时的，所以可以理解期间所有的困难和阻碍；</p><p>因为觉得一切都是暂时的，所以可以接受期间所有的痛苦和煎熬；</p><p>因为觉得一切都是暂时的，所以可以忍受期间所有的失败和幻灭。</p><p>所有的这一切都是暂时的嘛，那个声音一直这么和我说，所有一切都可以继续着。</p></blockquote><p>我消化了一下他说的话，觉得这种活法是有点奇特，不过好像也没什么。说到底，谁不是这个世间的异类呢？ 我和他说，这样其实也没什么不好，不是么，你这么多年都这么过来了，为什么突然现在就迷茫了呢？</p><p>他一时之间没有回答我。我以为我的话让他更难受了。不过他也只是像喃喃自语一样的在重复着：是啊，这么多年都过来了，为什么突然现在就觉得不对了呢？</p><p>他像是在对我说，又像是在自己分析着，继续说：</p><blockquote><p>因为最近我突然开始意识到，我一直以为自己要到达的那个未来似乎是永远也无法到达的。数学家版本的龟兔赛跑的故事你听说过吧，大概就是那个感觉。<br>因为我永远会根据当前的现状来修正我想象着的那个未来，它是活的，时刻在变化的。</p></blockquote><p>我说：</p><blockquote><p>是啊，很多人也都是这样的啊，给自己设立一个目标，然后为了实现它而不断努力。然后再设立下一个目标，继续去追逐下去。<br>挺正能量的啊，你的这个未来和大多数人的目标其实差不多嘛，就是一个努力的动力，挺好的。</p></blockquote><p>他说：</p><blockquote><p>是啊，看起来也挺好的。可是，如果有一天你发现这个目标或者说这个未来你永远无法实现或到达呢？<br>你可能会说，你只要不断努力，说不定就能实现呢？</p></blockquote><blockquote><p>但是其实你知道的，见识过、经历过足够多的事情之后你就会知道的，有些未来 无论你怎么努力就是注定无法到达的。<br>一旦你意识到这一点，你知道那个未来注定是无法到达了，可是日子还是要一分一秒的过下去的，那么长久以来的生活方式就会让你的每时每刻都变成一种煎熬。</p></blockquote><p>我想我大概理解你的意思了，哀莫大于心死？</p><p>不是，是：知其不可奈何，而仍无法安之若命。因为你听过，见到过，你知道那个未来是真实存在的。只是，你已经无法到达了而已。</p><p>许久，我们都没有再继续说话。我不知道该说些啥，也不知道他在想些啥。</p><p>我突然回味过来，他的这种状态应该就是现在很多人躺平的缘由吧。</p><p>又过来一会后我假装开玩笑的语气问他，那你接下来打算怎么办，要躺平了吗？</p><p>不会，他很快的回答道。他这么肯定的说出来反而让我有些诧异。</p><p>他笑着说，我这个人就是这样悲观却积极的活着。</p><p>即使我悲观的认为那个未来我注定无法到达了。但我也不会躺平，可能让心存侥幸吧。总觉得如果奇迹出现的那一刻，而自己一直都躺着的，可能她也有可能因为没留意地下而看不到我吧。</p><p>说完我们两个都笑了起来。</p><p>挺好的，至少有些事可以继续做，不要让自己陷入虚无就行。我像是宽慰他，也像是告诫自己。</p><p>我突然想到前段时间看到的三一门左若童舍身证道未得，而道心破碎撒手而去的情节，莫名感慨道：看来大盈仙人还没有你的韧性足啊！</p><p>他听后也哈哈笑了起来。只是那笑声很快就融化在空气中。</p><p>最后我还是问出了那个问题：所以，你说的那个未来究竟是什么样的呢？</p><p>不重要了，他笑着说。</p><p>想想也是。</p><p>就像章北海最后说的那句话：没关系的，都一样。</p><p>完。</p>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      <category domain="https://www.qtter.com/tags/%E9%9A%8F%E7%AC%94/">随笔</category>
      
      
      <comments>https://www.qtter.com/2024/a-feture-man/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>2023年flag</title>
      <link>https://www.qtter.com/2023/2023%E5%B9%B4flag/</link>
      <guid>https://www.qtter.com/2023/2023%E5%B9%B4flag/</guid>
      <pubDate>Thu, 26 Jan 2023 16:00:00 GMT</pubDate>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;总想着做些什么，写些什么。却迟迟没有开始过。&lt;br&gt;2023年了，那就做些计划，立些flag吧！&lt;/p&gt;
&lt;/blockquote&gt;</description>
      
      
      
      <content:encoded><![CDATA[<blockquote><p>总想着做些什么，写些什么。却迟迟没有开始过。<br>2023年了，那就做些计划，立些flag吧！</p></blockquote><span id="more"></span><h2 id="每周把自己的内心想法写下来"><a href="#每周把自己的内心想法写下来" class="headerlink" title="每周把自己的内心想法写下来"></a>每周把自己的内心想法写下来</h2><p>一直有一个写小说的想法，之前反反复复开始、放弃了几次。<br>终究明白，对于现在的我，这是一个非常艰难的事情<br>那就写找找感觉吧，本来是想计划每日一篇的，想想有些不切实际，还是慢慢来吧，循序渐进。</p><p>也不用想着什么自媒体不自媒体的，先写起来吧！</p><h2 id="寻找到一个副业，并站稳脚跟"><a href="#寻找到一个副业，并站稳脚跟" class="headerlink" title="寻找到一个副业，并站稳脚跟"></a>寻找到一个副业，并站稳脚跟</h2><p>最好是可以有稳定的收入，可以不用多，能够长期做下去是关键</p><h2 id="换一个工作"><a href="#换一个工作" class="headerlink" title="换一个工作"></a>换一个工作</h2><p>是的，就是这么实际、接地气。<br>奔四了，可能随时会走到职业生涯的最后一站啊。<br>最后再逼自己一把吧！看看是否会有峰回路转。</p><h2 id="出国旅游一次"><a href="#出国旅游一次" class="headerlink" title="出国旅游一次"></a>出国旅游一次</h2><p>带着老婆</p><h2 id="适度健身"><a href="#适度健身" class="headerlink" title="适度健身"></a>适度健身</h2><p>每周跑10公里<br>每周一次，俯卧撑、深蹲之类的搞起来</p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%88%91%E5%BD%93%E7%84%B6%E5%9C%A8%E6%89%AF%E6%B7%A1/">我当然在扯淡</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      <category domain="https://www.qtter.com/tags/2023/">2023</category>
      
      
      <comments>https://www.qtter.com/2023/2023%E5%B9%B4flag/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>我曾经以为日子是过不完的</title>
      <link>https://www.qtter.com/2022/%E6%88%91%E6%9B%BE%E7%BB%8F%E4%BB%A5%E4%B8%BA%E6%97%A5%E5%AD%90%E6%98%AF%E8%BF%87%E4%B8%8D%E5%AE%8C%E7%9A%84/</link>
      <guid>https://www.qtter.com/2022/%E6%88%91%E6%9B%BE%E7%BB%8F%E4%BB%A5%E4%B8%BA%E6%97%A5%E5%AD%90%E6%98%AF%E8%BF%87%E4%B8%8D%E5%AE%8C%E7%9A%84/</guid>
      <pubDate>Thu, 15 Sep 2022 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;我曾经以为日子是过不完的&lt;br&gt;我曾经以为未来是另一个样子&lt;br&gt;如今我就呆在我自己的未来&lt;br&gt;一切好像没有任何变化&lt;br&gt;我现在的梦想还是和小时候一样&lt;br&gt;唯一的区别是&lt;br&gt;我现在无比清晰的知道，我实现不了它了&lt;/p&gt;
&lt;/blockquo</description>
        
      
      
      
      <content:encoded><![CDATA[<blockquote><p>我曾经以为日子是过不完的<br>我曾经以为未来是另一个样子<br>如今我就呆在我自己的未来<br>一切好像没有任何变化<br>我现在的梦想还是和小时候一样<br>唯一的区别是<br>我现在无比清晰的知道，我实现不了它了</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%88%91%E5%BD%93%E7%84%B6%E5%9C%A8%E6%89%AF%E6%B7%A1/">我当然在扯淡</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      <category domain="https://www.qtter.com/tags/2022/">2022</category>
      
      
      <comments>https://www.qtter.com/2022/%E6%88%91%E6%9B%BE%E7%BB%8F%E4%BB%A5%E4%B8%BA%E6%97%A5%E5%AD%90%E6%98%AF%E8%BF%87%E4%B8%8D%E5%AE%8C%E7%9A%84/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>记录viper框架热加载配置文件的一个BUG</title>
      <link>https://www.qtter.com/2022/2022-07-27-viper-conf-bug/</link>
      <guid>https://www.qtter.com/2022/2022-07-27-viper-conf-bug/</guid>
      <pubDate>Tue, 26 Jul 2022 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;“还是老样子，又是一个背景交代。&lt;br&gt;最近公司一直在搞降本增效，各种优化。期间发现一些服务的配置文件热加载经常更新失败，一番分析之后，发现是框架里使用了 viper 的文件监控和热加载的功能，在一些特殊的使用姿势的情况下，会引发更新bug。”&lt;/</description>
        
      
      
      <enclosure url="https://www.qtter.com/https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/bg-1.jpeg" type="image"/>
      
      
      <content:encoded><![CDATA[<blockquote><p>“还是老样子，又是一个背景交代。<br>最近公司一直在搞降本增效，各种优化。期间发现一些服务的配置文件热加载经常更新失败，一番分析之后，发现是框架里使用了 viper 的文件监控和热加载的功能，在一些特殊的使用姿势的情况下，会引发更新bug。”</p></blockquote><h2 id="具体场景"><a href="#具体场景" class="headerlink" title="具体场景"></a>具体场景</h2><p>关于热加载的使用方式，在脱敏之后的代码大概张下面这个样子：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line">package <span class="selector-tag">main</span></span><br><span class="line"></span><br><span class="line">import (</span><br><span class="line">    <span class="string">&quot;encoding/json&quot;</span></span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;net/http&quot;</span></span><br><span class="line">    <span class="string">&quot;time&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">&quot;github.com/fsnotify/fsnotify&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/gin-gonic/gin&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/spf13/viper&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/willas/overseer&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">var</span> (</span><br><span class="line">    FusingConfig cfg</span><br><span class="line">)</span><br><span class="line">type cfg struct &#123;</span><br><span class="line">    Test item</span><br><span class="line">&#125;</span><br><span class="line">type item struct &#123;</span><br><span class="line">    List <span class="selector-attr">[]</span>int</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func <span class="selector-tag">main</span>() &#123;</span><br><span class="line">    serverAddr := fmt<span class="selector-class">.Sprintf</span>(<span class="string">&quot;:8989&quot;</span>)</span><br><span class="line">    overseer<span class="selector-class">.Run</span>(overseer.Config&#123;</span><br><span class="line">        Program: prog,</span><br><span class="line">        Address: serverAddr,</span><br><span class="line">        Debug:   true,</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func <span class="built_in">prog</span>(state overseer.State) &#123;</span><br><span class="line">    confFile := <span class="string">&quot;/data/demo/demo.toml&quot;</span></span><br><span class="line">    fmt<span class="selector-class">.Println</span>(<span class="string">&quot;cfgFile: &quot;</span>, confFile)</span><br><span class="line">    <span class="built_in">LoadConfig</span>(confFile)</span><br><span class="line">    viper<span class="selector-class">.WatchConfig</span>()</span><br><span class="line">    viper<span class="selector-class">.OnConfigChange</span>(<span class="built_in">func</span>(e fsnotify.Event) &#123;</span><br><span class="line">        fmt<span class="selector-class">.Println</span>(<span class="string">&quot;Config file changed:&quot;</span>, e.Op)</span><br><span class="line">        <span class="built_in">LoadConfig</span>(confFile)</span><br><span class="line">    &#125;)</span><br><span class="line">    err := http<span class="selector-class">.Serve</span>(state<span class="selector-class">.Listener</span>, gin<span class="selector-class">.New</span>())</span><br><span class="line">    <span class="keyword">if</span> err != nil &#123;</span><br><span class="line">        fmt<span class="selector-class">.Println</span>(<span class="string">&quot;server start failed&quot;</span>, err)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//等待以上结束</span></span><br><span class="line">    <span class="selector-tag">time</span><span class="selector-class">.Sleep</span>(<span class="selector-tag">time</span>.Second)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func <span class="built_in">LoadConfig</span>(cfgFile string) &#123;</span><br><span class="line">    viper<span class="selector-class">.SetConfigFile</span>(cfgFile)</span><br><span class="line">    err := viper<span class="selector-class">.ReadInConfig</span>() <span class="comment">// Find and read the config file</span></span><br><span class="line">    <span class="keyword">if</span> err != nil &#123;             <span class="comment">// Handle errors reading the config file</span></span><br><span class="line">        fmt<span class="selector-class">.Println</span>(<span class="string">&quot;viper read config error&quot;</span>, err)</span><br><span class="line">        return</span><br><span class="line">    &#125;</span><br><span class="line">    err = viper<span class="selector-class">.Unmarshal</span>(&amp;FusingConfig)</span><br><span class="line">    <span class="keyword">if</span> err != nil &#123;</span><br><span class="line">        fmt<span class="selector-class">.Println</span>(<span class="string">&quot;viper unmarshal error&quot;</span>, err)</span><br><span class="line">        return</span><br><span class="line">    &#125;</span><br><span class="line">    fByte, _ := json<span class="selector-class">.MarshalIndent</span>(FusingConfig, <span class="string">&quot;&quot;</span>, <span class="string">&quot;  &quot;</span>)</span><br><span class="line">    fmt<span class="selector-class">.Println</span>(<span class="string">&quot;changed file content:\n&quot;</span>, <span class="built_in">string</span>(fByte))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><p>其中加载的配置文件内容如下：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[test]</span></span><br><span class="line"><span class="attr">list</span>=[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br></pre></td></tr></table></figure><p>bug的表现场景是：当对list数组元素进行删减时，无法正确的更新删减后的内容</p><h2 id="截图说明"><a href="#截图说明" class="headerlink" title="截图说明"></a>截图说明</h2><ul><li>二图胜千言：<ul><li><p>初次加载配置内容：<br>  <img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/1-1024x403.png" alt="图1"></p></li><li><p>可以看到热加载之后的配置文件内容没有符合预期。</p><p>  <img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/2-1024x587.png" alt="图2"></p></li></ul></li></ul>]]></content:encoded>
      
      
      
      <category domain="https://www.qtter.com/tags/%E6%8A%80%E6%9C%AF/">技术</category>
      
      
      <comments>https://www.qtter.com/2022/2022-07-27-viper-conf-bug/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>道——Linux下的idle进程</title>
      <link>https://www.qtter.com/2022/%E9%81%93%E2%80%94%E2%80%94Linux%E4%B8%8B%E7%9A%84idle%E8%BF%9B%E7%A8%8B/</link>
      <guid>https://www.qtter.com/2022/%E9%81%93%E2%80%94%E2%80%94Linux%E4%B8%8B%E7%9A%84idle%E8%BF%9B%E7%A8%8B/</guid>
      <pubDate>Fri, 08 Jul 2022 16:00:00 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;道生一，一生二，二生三，三生万物&lt;br&gt;        ——老子，道德经&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近公司开始搞各种减成本降配的事情。真是让人感叹世风日下啊！&lt;/p&gt;
&lt;p&gt;但吐槽归吐槽，事情还是要做啊！&lt;/p&gt;
&lt;p&gt;然后在查看</description>
        
      
      
      
      <content:encoded><![CDATA[<blockquote><p>道生一，一生二，二生三，三生万物<br>        ——老子，道德经</p></blockquote><p>最近公司开始搞各种减成本降配的事情。真是让人感叹世风日下啊！</p><p>但吐槽归吐槽，事情还是要做啊！</p><p>然后在查看运维的各种监控指标面板中，就遇到了今天要说的这个东西：idle进程。主要就是用来指示机器的空闲程度。</p><p>之前一直没太留意这玩意，但有2个疑惑：</p><ul><li>为什么这玩意可以表示机器的空闲程度?</li><li>为什么需要这玩意?</li></ul><p>于是查了下 相关介绍 和 相关介绍 算是大概有个了解了，总结下来就是：</p><ul><li>Linux世界诞生之时，只有 0号进程 init_task（这个在最后变成idle进程）</li><li>0号进程经过诸如 start_kernel、rest_init的演化，诞生出1号 内核init线程、2号 kthreadd内核线程</li><li>1号 内核init线程 最终变化为所有用户态程序的根进程，是所有用户态进程的祖先</li><li>2号内核kthreadd内核线程，变为所有内核态其他守护线程的祖先</li><li>……</li></ul><p>看完上面这些，就觉得这个设计的格局有点似曾相识的感觉啊。</p><p>再一品，这 idle 不就是老子所说的 道 吗？！</p><blockquote><p>道生一，一生二，二生三，三生万物</p></blockquote><p>有点玄妙的感觉，Linus Torvalds 是有点东西啊！</p><p>另外值得一提的是：<br>现在的电脑都是多处理器的，主处理器 上的idle由原始进程(pid&#x3D;0)演变而来。从处理器 上的idle由init进程fork得到，但是它们的pid都为0</p><p>至此也解答了我上面的2个疑惑：</p><ul><li><p>为什么这玩意可以表示机器的空闲程度?</p><ul><li>因为这玩意就是在系统空闲的时候运行，所以当然是表示系统的空闲程度</li></ul></li><li><p>为什么需要这玩意呢？</p><ul><li>因为正如亿贫如洗王道长说的：这个世界没有一刻是静止的 ，电脑系统也无法真正完全停止运行，否则这个系统就死了，关机。总要跑点什么吧，那就让idle来吧。</li></ul></li></ul><p>写到这里，突然想到了第一次读到老子的这段话的疑惑：道生一，一生二，二生三，三生万物，那最后道就没了吗？</p><p>原来 道 和 idle 一样，并没有消失，而是为了保证这个世界不会绝对静止，无时无刻、无处不在的运转着。</p><p>【完】。</p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%88%91%E5%BD%93%E7%84%B6%E5%9C%A8%E6%89%AF%E6%B7%A1/">我当然在扯淡</category>
      
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      <category domain="https://www.qtter.com/tags/2022/">2022</category>
      
      
      <comments>https://www.qtter.com/2022/%E9%81%93%E2%80%94%E2%80%94Linux%E4%B8%8B%E7%9A%84idle%E8%BF%9B%E7%A8%8B/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>关于time/rate的一篇水贴</title>
      <link>https://www.qtter.com/2022/%E5%85%B3%E4%BA%8Etime-rate%E7%9A%84%E4%B8%80%E7%AF%87%E6%B0%B4%E8%B4%B4/</link>
      <guid>https://www.qtter.com/2022/%E5%85%B3%E4%BA%8Etime-rate%E7%9A%84%E4%B8%80%E7%AF%87%E6%B0%B4%E8%B4%B4/</guid>
      <pubDate>Sat, 05 Mar 2022 14:55:04 GMT</pubDate>
      
      
      
      
      
      
      <comments>https://www.qtter.com/2022/%E5%85%B3%E4%BA%8Etime-rate%E7%9A%84%E4%B8%80%E7%AF%87%E6%B0%B4%E8%B4%B4/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>2021 年底来扯扯淡（下）</title>
      <link>https://www.qtter.com/2022/2021%E4%B8%8B/</link>
      <guid>https://www.qtter.com/2022/2021%E4%B8%8B/</guid>
      <pubDate>Mon, 21 Feb 2022 09:08:10 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;又是一个上午请假的日子，想起来之前的年底扯扯淡的文章挖了个上、下篇的坑，现在来填上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;日子一天天的过去，转移重心后的生活和工作都仍然在继续。&lt;/p&gt;
&lt;p&gt;尝试 像 2021 年底来扯扯淡（上） 结尾说的那</description>
        
      
      
      
      <content:encoded><![CDATA[<blockquote><p>又是一个上午请假的日子，想起来之前的年底扯扯淡的文章挖了个上、下篇的坑，现在来填上。</p></blockquote><p>日子一天天的过去，转移重心后的生活和工作都仍然在继续。</p><p>尝试 像 2021 年底来扯扯淡（上） 结尾说的那样的方式，遵从自己思考判断来做决定，而不是一味的为了工作里各种各样的公司战略、KPI、绩效而委曲求全着做一些其实毫无意义的事情。吃了很多年的饼之后，我终于意识到并且坚信：这些人并不是一个好的画饼师傅，而绝大数情况下，他们自己也心知肚明。</p><p>而在意识到这个情况之后，我也突然发现之前多年的工作里，一直是“偷懒”式工作，很长的时间里，甚至到了自我感动的地步。那时每天都很忙：</p><p>哇啊，公司又有了新的项目孵化目标了，加油啊，赶紧开发部署；</p><p>是啊，领导又有了新的方向想要尝试了，等不了，赶紧加班上线；</p><p>对啊，产品叕有了新的想法急需验证了，最终版，无脑迭代上架。</p><p>…</p><p>反反复复，无休无止。</p><p>那我就只管努力（偷懒）就好了啊，还思考啥。<br>忙吗？确实忙。可是永远是在为别人忙啊！<br>我就像个兵线上的小兵，永远固定路线、固定速度，被英雄们带着节奏漫无目的的走着、攻击着，然后倒下，最后还是变成别人的升级经验，并且不断重复。<br>就这样，一晃好多年。</p><p><strong>“那能怎么办呢？”</strong></p><p>是啊，那能怎么办呢？很多次和自己、和别人的聊天里，都会有这个疑问。被带着节奏太久了，无脑忙碌太久了，我们已经习惯了，甚至麻木了。太累了，太忙了，不想思考了。<br>只是每每总有那么一个时刻，我看着斧王的巨斧就在想：总有人要成为的英雄，为什么不能是我呢？<br>或者退一步，即使我终究是一个小兵，那我为啥不做一个有自己节奏的小兵呢？<br>那一刻，我的视角终于开始切换。</p><p>于是，我总结出了可能是我的人生迄今为止最重要的一个结论，并决定当做我的人生的第一优先级的奥义：</p><p><strong>不论工作还是生活（当然还有 DOTA ），永远要保持自己的节奏！</strong></p><p>基于自己当前的现状简单的分析之后，确认可能产生的影响和最坏的结果，感觉一切OK，我开始深信不疑的践行。顺带着，啪！我打开了那个情绪开关。<br>所谓树立中心思想，大刀阔斧改革，战略上藐视一切画饼师傅，战术上细化自己的目标和节奏，以此为前提，毫不迟疑的拒绝掉一切不合理的要求。</p><p>“什么，临时有项目需要交接要出差一段时间？”</p><p>“我不去，安排其他同事吧”</p><p>“什么，有个紧急的需求需要支持下？”</p><p>“当前在做需求，直接提个领导排好优先级”</p><p>“什么，项目紧急需要缩短工期加班？”</p><p>“周末有安排，不加班，自己去找领导协调”</p><p>还是那句话，一切的紧急都是基于你的节奏：who TM cares!</p><p>按照这个节奏工作下来，发现真TM爽啊！而且，最后你会发现，其实也不会有什么大影响。甚至于，保持“强硬”的态度之后会发现，之前不好沟通协调的事情竟然也开始变得容易了起来。人性从来就是这样。</p><p>所谓，好好先生并不能让结果事事好好。讨好型人格更是毫无必要。<br>只是，性格潜移默化，改变无法一蹴而就，意识到就好，慢慢改善。<br>工作学习节奏调整好了之后，接下来可能就是发育期吧，一切还是要慢慢来。</p><p>这个时候，我遇见了我的那个她。</p><p>懂得我说的：</p><blockquote><p>“不要回答！ 不要回答！！ 不要回答！！！”</p></blockquote><p>梗的她。</p><p>懂得大刘笔下</p><blockquote><p>“只送大脑！”</p></blockquote><p>的疯狂和浪漫的她。</p><p>这让我不得不感慨缘分的奇妙。甚至后面我回想起来，很难想清楚这是不是得益于我这段时间的想法改变之后整个人生活状态的蜕变。不能早，也不能晚，只能是这个时候的遇见才是最正确的时机。</p><p>回想着不知道从多久远的以前起，初中？高中？，我被每日负面、悲观、绝望的情绪裹挟着。在快要不堪重负而垮掉时，我开始有意识的训练自己的情绪。我想把自己机器化、数字化，想象着自己的大脑中有一个情绪开关。</p><p>啪！关闭它，啊，真好！我不再有任何的情绪了。</p><p>啪！打开它，啊，呼吸，忍受无数汹涌如潮水般的情绪把我吞没！</p><p>就这样，一天一天，不停的关闭、打开，关闭打开…</p><p>经过不知道多少次这样近乎病态式的疯狂训练之后，我觉得我成功了。<br>之后的一些年里，我差不多无限期的关闭着这个开关，这样我觉得生活不那么沉重了，我觉得轻松。如果有个情绪的电图，那这些年我的情绪电图应该几乎是一条长长而乏味的直线。<br>然而人毕竟是人啊，和机器不同啊。如果只是仅仅为了活得轻松而舍弃掉所以的情绪，那又有什么意义呢？</p><p>所以，<strong>做个人吧！</strong> 哈哈哈 🙂</p><p>现在坐在这里，想着遇见她之后这段时间里一起经历的各种各样的事情和看过的风景，竟然也一时间不知道从何讲起。只是这段时间里，我开始感受到我的情绪了。很开心。原来生活或许不如意事十之八九，却依然让我觉得值得和美好！</p><p>总之，感谢生活，感谢大刘，感谢她 🙂</p><p>到这里，2021年底的这篇扯淡基本该结束了。上、下这两篇里算是把我这一年的感悟和改变理了七七八八了。后面的日子里，继续保持这自己的节奏，猥琐发育吧！</p><p>共勉：<strong>永远要保持自己的节奏！</strong></p><p>以上。</p>]]></content:encoded>
      
      
      
      
      <comments>https://www.qtter.com/2022/2021%E4%B8%8B/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>nsq</title>
      <link>https://www.qtter.com/2022/mq/nsq/index/</link>
      <guid>https://www.qtter.com/2022/mq/nsq/index/</guid>
      <pubDate>Wed, 26 Jan 2022 07:36:10 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;关于nsq的问题&quot;&gt;&lt;a href=&quot;#关于nsq的问题&quot; class=&quot;headerlink&quot; title=&quot;关于nsq的问题&quot;&gt;&lt;/a&gt;关于nsq的问题&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/fakerqtt</description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="关于nsq的问题"><a href="#关于nsq的问题" class="headerlink" title="关于nsq的问题"></a>关于nsq的问题</h1><p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/nsq/13257331-ad44d7516e6e53a5.webp" alt="topic,channel和consumer"></p><p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/nsq/13257331-68f2845de0c8dcfa.webp" alt="consumer"></p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/MessageQueue/">MessageQueue</category>
      
      
      
      <comments>https://www.qtter.com/2022/mq/nsq/index/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>kafaka</title>
      <link>https://www.qtter.com/2022/mq/kafka/index/</link>
      <guid>https://www.qtter.com/2022/mq/kafka/index/</guid>
      <pubDate>Wed, 26 Jan 2022 07:35:52 GMT</pubDate>
      
        
        
      <description>&lt;!-- toc --&gt;

&lt;h1 id=&quot;kafka-架构图&quot;&gt;&lt;a href=&quot;#kafka-架构图&quot; class=&quot;headerlink&quot; title=&quot;kafka 架构图&quot;&gt;&lt;/a&gt;kafka 架构图&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.jsdeli</description>
        
      
      
      
      <content:encoded><![CDATA[<!-- toc --><h1 id="kafka-架构图"><a href="#kafka-架构图" class="headerlink" title="kafka 架构图"></a>kafka 架构图</h1><p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/kafka/architecture.png" alt="kafka架构图"></p><h1 id="关于Kafka-的问题"><a href="#关于Kafka-的问题" class="headerlink" title="关于Kafka 的问题"></a>关于Kafka 的问题</h1><h2 id="kafka-是怎么做到-高吞吐率、速度快的？"><a href="#kafka-是怎么做到-高吞吐率、速度快的？" class="headerlink" title="kafka 是怎么做到 高吞吐率、速度快的？"></a>kafka 是怎么做到 高吞吐率、速度快的？</h2><h3 id="顺序读写"><a href="#顺序读写" class="headerlink" title="顺序读写"></a>顺序读写</h3><h4 id="partition-并行处理"><a href="#partition-并行处理" class="headerlink" title="partition 并行处理"></a>partition 并行处理</h4><h3 id="Page-Cache"><a href="#Page-Cache" class="headerlink" title="Page Cache"></a>Page Cache</h3><h3 id="零拷贝"><a href="#零拷贝" class="headerlink" title="零拷贝"></a>零拷贝</h3><p><img src="https://cdn.jsdelivr.net/gh/fakerqtter/blog-static@main/images/kafka/zerocopy.svg" alt="零拷贝原理"></p><h4 id="mmap、sendfile"><a href="#mmap、sendfile" class="headerlink" title="mmap、sendfile"></a>mmap、sendfile</h4><ul><li>Producer生产的数据持久化到broker，采用mmap文件映射</li><li>Customer从broker读取数据，采用sendfile，将磁盘文件读到OS内核缓冲区后，直接转到socket buffer进行网络发送。</li></ul><h4 id="用户缓冲区、内核缓冲区、socket-buffer、NIC-buffer"><a href="#用户缓冲区、内核缓冲区、socket-buffer、NIC-buffer" class="headerlink" title="用户缓冲区、内核缓冲区、socket buffer、NIC buffer"></a>用户缓冲区、内核缓冲区、socket buffer、NIC buffer</h4><h4 id="定期-flush-到磁盘"><a href="#定期-flush-到磁盘" class="headerlink" title="定期 flush 到磁盘"></a>定期 flush 到磁盘</h4><h3 id="分区分段-索引"><a href="#分区分段-索引" class="headerlink" title="分区分段+索引"></a>分区分段+索引</h3><h3 id="数据压缩"><a href="#数据压缩" class="headerlink" title="数据压缩"></a>数据压缩</h3><h3 id="批量读写"><a href="#批量读写" class="headerlink" title="批量读写"></a>批量读写</h3><h2 id="kafka-如何保证不重复消费又不丢失数据？"><a href="#kafka-如何保证不重复消费又不丢失数据？" class="headerlink" title="kafka 如何保证不重复消费又不丢失数据？"></a>kafka 如何保证不重复消费又不丢失数据？</h2><p>首先我们要了解的是message delivery semantic 也就是消息传递语义。</p><p>这是一个通用的概念，也就是消息传递过程中消息传递的保证性。</p><p>分为三种：</p><ul><li><p>最多一次（at most once）:</p><p>消息可能丢失也可能被处理，但最多只会被处理一次。<br>可能丢失 不会重复</p></li><li><p>至少一次（at least once）: 消息不会丢失，但可能被处理多次。<br>可能重复 不会丢失</p></li><li><p>精确传递一次（exactly once）: 消息被处理且只会被处理一次。</p><p>不丢失 不重复 就一次</p></li></ul><p>而kafka其实有两次消息传递，一次生产者发送消息给kafka，一次消费者去kafka消费消息。</p><p>两次传递都会影响最终结果，</p><p>两次都是精确一次，最终结果才是精确一次。</p><p>两次中有一次会丢失消息，或者有一次会重复，那么最终的结果就是可能丢失或者重复的。</p><h3 id="分布式存储"><a href="#分布式存储" class="headerlink" title="分布式存储"></a>分布式存储</h3><h3 id="producer-端"><a href="#producer-端" class="headerlink" title="producer 端"></a>producer 端</h3><h4 id="幂等的producer（idempotent-producer）"><a href="#幂等的producer（idempotent-producer）" class="headerlink" title="幂等的producer（idempotent producer）"></a>幂等的producer（idempotent producer）</h4><h4 id="Kafka-的-ISR-机制"><a href="#Kafka-的-ISR-机制" class="headerlink" title="Kafka 的 ISR 机制"></a>Kafka 的 ISR 机制</h4><p>所以如果要让写入 Kafka 的数据不丢失，你需要保证如下几点：</p><ul><li><p>每个 Partition 都至少得有 1 个 Follower 在 ISR 列表里</p></li><li><p>每次写入数据的时候，都要求至少写入 Partition Leader 成功，同时还有至少一个 ISR 里的 Follower 也写入成功，才算这个写入是成功了。</p></li></ul><p>如果不满足上述两个条件，那就一直写入失败，让生产系统不停的尝试重试，直到满足上述两个条件，然后才能认为写入成功。</p><p>按照上述思路去配置相应的参数，才能保证写入 Kafka 的数据不会丢失。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><p><a href="https://zhuanlan.zhihu.com/p/120967989">Kafka为什么吞吐量大、速度快？</a></p></li><li><p><a href="https://zhuanlan.zhihu.com/p/78335525">Kafka零拷贝</a></p></li><li><p><a href="https://zhuanlan.zhihu.com/p/183808742">终于知道Kafka为什么这么快了！</a></p></li><li><p><a href="https://www.cnblogs.com/gxyandwmm/p/11432598.html">Kafka如何保证百万级写入速度以及保证不丢失不重复消费</a></p></li></ul>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/MessageQueue/">MessageQueue</category>
      
      
      
      <comments>https://www.qtter.com/2022/mq/kafka/index/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>2021 年底来扯扯淡（上）</title>
      <link>https://www.qtter.com/2021/2021%E4%B8%8A/</link>
      <guid>https://www.qtter.com/2021/2021%E4%B8%8A/</guid>
      <pubDate>Fri, 10 Dec 2021 04:50:44 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;最近可能由于工（刀）作（塔）过于辛苦，导致我今天早上闹钟响的时候，只有手醒了。&lt;br&gt;于是睡过头了。&lt;br&gt;然后顺手请个半天假。&lt;br&gt;一套操作感觉就是这么行云流水。&lt;/p&gt;
&lt;p&gt;所以现在有时间坐在电脑旁来扯这个淡。&lt;/p&gt;
&lt;p&gt;想想2021年马上就要过去了，时间真快啊</description>
        
      
      
      
      <content:encoded><![CDATA[<p>最近可能由于工（刀）作（塔）过于辛苦，导致我今天早上闹钟响的时候，只有手醒了。<br>于是睡过头了。<br>然后顺手请个半天假。<br>一套操作感觉就是这么行云流水。</p><p>所以现在有时间坐在电脑旁来扯这个淡。</p><p>想想2021年马上就要过去了，时间真快啊！<br>仔细回顾下今年都经历了啥呢？好像大的分界点是从年中6月份项目组解散开始的吧。如果是在小说里，这个一定是一个很好的故事展开线，哈哈。<br>6月份的时候，在大家刚结束了上周末的一次常规加班之后的一个周一，领导不出所料的突然宣布：项目组原地爆炸。现在我回过头来看感觉很魔幻。那种感觉就像，你们一队人正在和对面开团：<br>我方斧王先手果断跳吼直接控住对面所有人！<br>宙斯直接开大！<br>sven开大跳上去，准备团灭对面！<br>然后，停电了！！！<br>沉默了一会后，大家揪着的一颗心总算了放了下来。因为真实的情况是，斧王sven其实在对面:)。<br>接下来差不多一个月的时间里，事情的发展和大多数无节操的的IT公司的剧情没什么太大区别：临时抽调一个经验丰富的HR来挨个找大家言辞亲切的谈话，大概的内容也很明白：要么流放到其他项目组，要么自己滚，别想着N+1。<br>本想着争取一下的，无奈发现孤立无援，领导也来劝：公司也不容易啊。<br>大家相视而笑，悟了。<br>再后面的一段时间里，大家有的自谋出路走了，有的迫于无奈接受流放，有的不知所踪。最终，大家都有了光明的穷途。</p><p>然后时间就到了7月份。我开始了我长达半年的流放的日子，而且似乎看起来结束的日子还是遥遥无期。</p><p>现在细细回想起来，有点塞翁失马的感觉。</p><p>这下半年的时间可以说是我从毕业工作到现在，业务工作最少的一段时间了。正是因为这样，我有了大把大把的时间来思考、反思、总结。</p><p>最后反思下来的结论是：人不能太闲啊！真的好讽刺啊！  </p><p><strong>这个时代的节奏过于碎片和快速，使得你渐渐变得已经无法系统性的思考问题。</strong></p><p>我们总是为了这样那样的事情左右，为了眼前的问题寻找临时性的救火方案。这是一个漩涡陷阱，让所有深陷其中的人终日疲于奔命，无法停下，也无法逃脱。而这就是我这近十年的工作和生活状态啊！<br>每年，每月，每一天，我就在这个漩涡中努力的前进着以保持自己不会被吞噬。这样的日子不停歇的循环往复着，就像那个一日囚里的人一样。庆幸的是，心里也一直有着挣脱的期盼和希望，总觉得这些都是暂时的，会有那么一天事情会迎来转机。这些年的日子里，竟然就是靠着这个近乎盲目的信念支撑着走了过来。</p><p>而且，似乎还要这么走下去。<br>这就是生活的真相啊！一切并不会想电影里演的那样励志：突然有一天，主角有了奇遇一切都开挂般的好了起来。一切似乎都没么变化。<br>然后，项目黄了。这个漩涡似乎？竟然？真的停了下来。<br>经过短暂的眩晕之后，我发现自己很快的适应了起来。<br>这期间，我也终于第一次完整的看完了一届TI。当然，其中详情就不去过多描述了，总之全村的希望最后败给了一个颠勺的大厨，就是这么简单。<br>然后，经过了几天的短暂抑郁之后，我发现好像悟了！<br>因为，我突然发现我姓张，张三的张。</p><p><strong>张三说：人要接受自己的有限性。</strong></p><p>这种感觉很奇妙。这个事情对我来说，就好像是我在打野的时候突然插了个眼在高台上。我感觉自己的生活突然明亮了起来，视野清晰！<br>人甚至一下子变得洒脱起来，一种莫名其妙的自信油然而生！我感觉自己浑身充满了能量！<br>我隐隐的感觉到：我到6了！  </p><p>于是，我开始试着把重心从工作转移到生活中去。我发现没有996，没有那些感动自己、缓解领导焦虑的加班，天也没有塌下来。我开始慢慢体会到了什么是真实感。<br>生活，也慢慢的变得美好起来。  </p><p>未完，待续。</p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/%E6%88%91%E5%BD%93%E7%84%B6%E5%9C%A8%E6%89%AF%E6%B7%A1/">我当然在扯淡</category>
      
      
      <category domain="https://www.qtter.com/tags/2021/">2021</category>
      
      <category domain="https://www.qtter.com/tags/%E6%89%AF%E6%B7%A1/">扯淡</category>
      
      
      <comments>https://www.qtter.com/2021/2021%E4%B8%8A/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>golang断言：一个蛋疼的处理场景</title>
      <link>https://www.qtter.com/2021/go-type-assertion/</link>
      <guid>https://www.qtter.com/2021/go-type-assertion/</guid>
      <pubDate>Wed, 24 Nov 2021 07:33:57 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;这一切都来源于一个蛋疼的需求场景处理：&lt;/p&gt;
&lt;p&gt;因为历史原因，一个需要用到的JSON数据被整个缓存进Redis的一个key中，大概如下：&lt;/p&gt;
&lt;figure class=&quot;highlight swift&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;</description>
        
      
      
      
      <content:encoded><![CDATA[<p>这一切都来源于一个蛋疼的需求场景处理：</p><p>因为历史原因，一个需要用到的JSON数据被整个缓存进Redis的一个key中，大概如下：</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">6379</span><span class="operator">&gt;</span> <span class="keyword">get</span> dt</span><br><span class="line"><span class="string">&quot;&#123;<span class="subst">\&quot;</span>address<span class="subst">\&quot;</span>:[&#123;<span class="subst">\&quot;</span>duration<span class="subst">\&quot;</span>:90,<span class="subst">\&quot;</span>format<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>mp4<span class="subst">\&quot;</span>,<span class="subst">\&quot;</span>url<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>xxx.mp4<span class="subst">\&quot;</span>,<span class="subst">\&quot;</span>ext<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>&#123;<span class="subst">\\</span><span class="subst">\&quot;</span>key<span class="subst">\\</span><span class="subst">\&quot;</span>:<span class="subst">\\</span><span class="subst">\&quot;</span>val<span class="subst">\\</span><span class="subst">\&quot;</span>&#125;<span class="subst">\&quot;</span>&#125;,&#123;<span class="subst">\&quot;</span>duration<span class="subst">\&quot;</span>:90,<span class="subst">\&quot;</span>format<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>mp4<span class="subst">\&quot;</span>,<span class="subst">\&quot;</span>url<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>xxx.mp4<span class="subst">\&quot;</span>,<span class="subst">\&quot;</span>ext<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>&#123;<span class="subst">\\</span><span class="subst">\&quot;</span>key<span class="subst">\\</span><span class="subst">\&quot;</span>:<span class="subst">\\</span><span class="subst">\&quot;</span>val<span class="subst">\\</span><span class="subst">\&quot;</span>&#125;<span class="subst">\&quot;</span>&#125;],<span class="subst">\&quot;</span>value<span class="subst">\&quot;</span>:<span class="subst">\&quot;</span>web<span class="subst">\&quot;</span>&#125;&quot;</span></span><br><span class="line"><span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">6379</span><span class="operator">&gt;</span></span><br></pre></td></tr></table></figure><p>这里还是做了脱敏处理，实际的情形JSON的层级更深…<br>格式化显示的JSON结构大概是这样：  </p><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="string">&quot;address&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;xxx.mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;xxx.mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&quot;value&quot;</span>: <span class="string">&quot;web&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>现在要做的是： address 里的每个元素的 url 字段需要更新。</p><p>现在知道的是：address 的值 是一个数组，数组的每个元素是一个map[string]interface{} 类型，map里的元素除了 <strong>“url”: “xxx.mp4”</strong>, 其他的数量不确定</p><p>实现代码大概如下（方便展示，省略了Redis读写的步骤）：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">detailByte := []<span class="type">byte</span>(<span class="string">`&#123;&quot;address&quot;:[&#123;&quot;duration&quot;:90,&quot;format&quot;:&quot;mp4&quot;,&quot;url&quot;:&quot;xxx.mp4&quot;,&quot;ext&quot;:&quot;&#123;\&quot;key\&quot;:\&quot;val\&quot;&#125;&quot;&#125;,&#123;&quot;duration&quot;:90,&quot;format&quot;:&quot;mp4&quot;,&quot;url&quot;:&quot;xxx.mp4&quot;,&quot;ext&quot;:&quot;&#123;\&quot;key\&quot;:\&quot;val\&quot;&#125;&quot;&#125;],&quot;value&quot;:&quot;web&quot;&#125;`</span>)</span><br><span class="line">detail := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">string</span>]<span class="keyword">interface</span>&#123;&#125;, <span class="number">0</span>)</span><br><span class="line">json.Unmarshal(detailByte, &amp;detail)</span><br><span class="line">formatJson, _ := json.MarshalIndent(detail, <span class="string">&quot;&quot;</span>, <span class="string">&quot;    &quot;</span>)</span><br><span class="line">fmt.Println(<span class="string">&quot;before: &quot;</span>, <span class="type">string</span>(formatJson))</span><br><span class="line"><span class="keyword">if</span> address, ok := detail[<span class="string">&quot;address&quot;</span>]; ok &#123;</span><br><span class="line"><span class="keyword">if</span> item, ok2 := address.([]<span class="keyword">interface</span>&#123;&#125;); ok2 &#123;</span><br><span class="line"><span class="keyword">for</span> index, value := <span class="keyword">range</span> item &#123;</span><br><span class="line"><span class="keyword">if</span> vMap, ok3 := value.(<span class="keyword">map</span>[<span class="type">string</span>]<span class="keyword">interface</span>&#123;&#125;); ok3 &#123;</span><br><span class="line"><span class="keyword">if</span> _, ok4 := vMap[<span class="string">&quot;url&quot;</span>];ok4 &#123;</span><br><span class="line">vMap[<span class="string">&quot;url&quot;</span>] = <span class="string">&quot;wtf.mp4&quot;</span></span><br><span class="line">&#125;</span><br><span class="line">item[index] = vMap</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">detail[<span class="string">&quot;address&quot;</span>] = item</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">formatJson, _ = json.MarshalIndent(detail, <span class="string">&quot;&quot;</span>, <span class="string">&quot;    &quot;</span>)</span><br><span class="line">fmt.Println(<span class="string">&quot;after: &quot;</span>, <span class="type">string</span>(formatJson))</span><br></pre></td></tr></table></figure><p>运行结果：</p><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="params">before:</span>  &#123;</span><br><span class="line">    <span class="string">&quot;address&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;xxx.mp4&quot;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;xxx.mp4&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&quot;value&quot;</span>: <span class="string">&quot;web&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="params">after:</span>  &#123;</span><br><span class="line">    <span class="string">&quot;address&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;wtf.mp4&quot;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;duration&quot;</span>: <span class="number">90</span>,</span><br><span class="line">            <span class="string">&quot;ext&quot;</span>: <span class="string">&quot;&#123;<span class="char escape_">\&quot;</span>key<span class="char escape_">\&quot;</span>:<span class="char escape_">\&quot;</span>val<span class="char escape_">\&quot;</span>&#125;&quot;</span>,</span><br><span class="line">            <span class="string">&quot;format&quot;</span>: <span class="string">&quot;mp4&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: <span class="string">&quot;wtf.mp4&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&quot;value&quot;</span>: <span class="string">&quot;web&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>怎么说呢，实现了感觉又没有真正实现…</p><p>哎，蛋疼。</p>]]></content:encoded>
      
      
      <category domain="https://www.qtter.com/categories/Golang/">Golang</category>
      
      <category domain="https://www.qtter.com/categories/%E6%8A%80%E6%9C%AF/">技术</category>
      
      
      
      <comments>https://www.qtter.com/2021/go-type-assertion/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
