<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Luozx的数字花园🌳</title>
<link>https://luozx.org/categories/worklog.html</link>
<atom:link href="https://luozx.org/categories/worklog.xml" rel="self" type="application/rss+xml"/>
<description>工作中的思考、问题定位、工程实践和解决办法。</description>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Tue, 04 Nov 2025 08:20:00 GMT</lastBuildDate>
<item>
  <title>引用：关于AWS DynamoDB中断分析</title>
  <dc:creator>Luozx </dc:creator>
  <link>https://luozx.org/posts/quote-aws-dynamodb-outage-stpa.html</link>
  <description><![CDATA[ 

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NVV5S5NQ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->




<blockquote class="blockquote">
<p>The problem isn’t that the issues aren’t obvious. By the metric of “would I understand this is a problem if someone explained it to me”, almost all issues are obvious. The problem is one of directing our attention: we are not great at paying attention to all things that go on to become problems later.</p>
<p>问题不在于这些隐患不够明显。如果以“只要有人解释，我就能理解这是个问题”为标准，那么几乎所有隐患其实都很明显。真正的问题在于注意力分配：我们并不擅长关注所有最终会演变成问题的细节。</p>
</blockquote>
<p>via <a href="https://entropicthoughts.com/aws-dynamodb-outage-stpa">AWS DynamoDB Outage Analysis</a></p>
<p>在我参加的几乎所有的故障复盘会中，讨论的内容往往聚焦在引发事件发生的细节问题上，并且改进提升项也会落在会议中讨论的细节部分。例如，增加某某监控项，调整某某告警精度，延长灰度验证时长，增加某项检测机制…</p>
<p>把注意力放在已经出错的细节，而忽略了导致这些细节失效的更高层次的系统性问题，缺乏自上而下的系统性分析，持续在细节层面修复问题反而会让参与者疲于奔命。</p>
<p>系统理论分析过程（STPA）也许是一种能帮助我们重新分配注意力、从整体视角理解风险的分析方法。</p>
<p>还有一些关于STPA(STAMP)的讨论文章：</p>
<ul>
<li><a href="https://rootly.com/blog/google-sres-are-changing-the-game-again-a-breakdown-of-their-new-approach">Google SREs are changing the game again: a breakdown of their new approach</a></li>
<li><a href="https://surfingcomplexity.blog/2020/08/07/thoughts-on-stamp/">Thoughts on STAMP</a></li>
</ul>
<p>系统的复杂性不会因为更多的监控和告警而减少。重新理解‘控制’的边界，才能在混乱中保持信心。</p>



<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> 回到顶部</a><div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">二次使用</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0</a></div></div></section></div> ]]></description>
  <category>worklog</category>
  <guid>https://luozx.org/posts/quote-aws-dynamodb-outage-stpa.html</guid>
  <pubDate>Tue, 04 Nov 2025 08:20:00 GMT</pubDate>
</item>
<item>
  <title>故障事件回顾中的几个重要时间节点</title>
  <dc:creator>Luozx </dc:creator>
  <link>https://luozx.org/posts/key-timestamps-in-incident-review.html</link>
  <description><![CDATA[ 

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NVV5S5NQ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->




<p>前段时间，在阅读和整理过往记录的故障事件的时候，发现模板只要记录两个时间：</p>
<ul>
<li>故障发生时间</li>
<li>故障恢复时间</li>
</ul>
<p>乍一看，这两个时间充当“故障事件模板” 是足够的。但会让故障的影响时长严重失真，而故障时长是计算MTTR<sup>1</sup> 和估计可用性<sup>2</sup>的重要数据。</p>
<p>一个正在运行的系统，在几乎没有用户（使用）的情况下，对该系统进行了有缺陷的变更动作，直到第一个用户发现了该缺陷，之间的这段时间，应该被当作故障，计算故障时长吗？</p>
<p>我知道你可能会想：进行了有缺陷的变更动作，监控呢？告警呢？变更之后不验证吗？没错，如果一切都做的足够好，很多问题就不再是问题了。</p>
<p>现实情况是：大多数公司都做的不够好。以至于靠最终用户反馈服务异常，不可用，是一个司空见惯的现象。</p>
<p>既然这是不可忽略的事实，也就不应该理所当然的的将「故障恢复时间-故障发生时间」统计为<em>故障时长</em>。所以，我明确将故障时长定义为：「确实影响用户使用的时间段」，并更新了故障模板，额外增加了一个时间点。故障事件中需要的记录时间点就变成了：</p>
<ul>
<li>（问题）发生时间</li>
<li>影响开始时间</li>
<li>影响结束时间</li>
</ul>
<p><span id="eq-1"><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>故</mi><mi>障</mi><mi>时</mi><mi>长</mi><mo>=</mo><mi>影</mi><mi>响</mi><mi>结</mi><mi>束</mi><mi>时</mi><mi>间</mi><mo>−</mo><mi>影</mi><mi>响</mi><mi>开</mi><mi>始</mi><mi>时</mi><mi>间</mi><mspace width="2.0em"></mspace><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> 故障时长 = 影响结束时间 - 影响开始时间  \qquad(1)</annotation></semantics></math></span></p>
<p>(式&nbsp;1)一定程度上解决了MTTR和可用性估计的准确的问题，但是后来又发现，如果仅仅使用上述三个时间节点去还原应急处理的过程，过程中的一些重要数据则会丢失。</p>
<p>例如，执行了某项应急过程，但执行时需要一定时间：变更的回退，服务重启都属于这类情况。另外的一种情况是，应急过程虽然很快执行完毕，但传播生效则需要时间（更改DNS解析属于此类情形）</p>
<p>考虑上述的情况，故障事件中，完整的关键时间点应该是：</p>
<ol type="1">
<li>发生时间：有缺陷的变更开始</li>
<li>发现时间：由内部告警或值班时发生的异常，此时<strong>可能开始</strong>进行应急处置</li>
<li>影响开始时间：外部用户开始反馈的时间，或者拨测明确有业务影响，此时开始应急处置</li>
<li>处置完成：应急处置结束的时间</li>
<li>影响结束时间：用户反馈正常或者由内部验证正常（比如作为用户进行测试）</li>
</ol>
<p>上面的时间点，形成了下图四段时间组合：</p>
<ol type="1">
<li>告警及时性</li>
<li>告警有效性</li>
<li>应急处置时长（虚线部分）</li>
<li>应急处置有效性</li>
</ol>
<p>3和4两个时段，组成了故障事件对外造成影响的总时长（红色部分）</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="https://image.luozx.org/garden/2025/07/fb774f95d2a1e4f46ad85b604781cd68.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="故障事件时间流"><img src="https://image.luozx.org/garden/2025/07/fb774f95d2a1e4f46ad85b604781cd68.png" class="img-fluid figure-img" alt="故障事件时间流"></a></p>
<figcaption>故障事件时间流</figcaption>
</figure>
</div>
<p>还有一件奇怪的事情是：在我参加过的大多数故障复盘的讨论中，讨论的重点最终都落在两件事项上：</p>
<ul>
<li>有没有监控</li>
<li>有没有告警</li>
</ul>
<p>之所以如此，是因为我们自认为或期望，监控告警和真实的业务影响之间有着一致的关联关系，理所当然的认为一旦监控和告警出现了异常，我们可以开始着手执行应急处置。因为我们想在外部影响出现之前提前感知（即图中灰色箭头）。</p>
<p>争取更多的应急处置时长，可能会降低故障影响，但只有当故障事件提前消除，才能算作提升了系统的可用性（即增加了MTBF<sup>3</sup>）。</p>
<p>另外一种策略是，降低故障时长时间（图中红色部分）。加快应急处置的速度，提高应急方案的有效性。</p>
<p>这两种策略，在提高系统可用性上，我认为后者效果会更显著（即降低MTTR）。换句话说，故障复盘时，企图通过改进监控和告警来提升系统可用性，不是一个好的策略。</p>
<p>Google给出的故障复盘的<a href="https://docs.google.com/document/d/1iaEgF0ICSmKKLG3_BT5VnK80gfOenhhmxVnnUcNSQBE/edit?tab=t.0">Checklist</a>中，写道：</p>
<blockquote class="blockquote">
<dl>
<dt>Complete the incident timeline fields for MTTx measures</dt>
<dd>
<small>MTTx: Mean Time to x (x=(detection|escalation|mitigation|resolution)</small>
</dd>
</dl>
</blockquote>
<p>值得注意的是，该项放在「Incident Data Collection」一栏中，并且明确指出是用于计算MTTx的时间线。</p>
<p>我认为这几项MTTx是有优先级的，对于中小型或成长性企业，想要提高系统可用性水平，应当优先考虑记录关于与故障时长有关（图中红色部分）的时间点，提高应急处置的速度及其生效的速度，而不是将监控和告警作为故障复盘的重心和后续举措。</p>




<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> 回到顶部</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">脚注</h2>

<ol>
<li id="fn1"><p>故障修复时长的平均值↩︎</p></li>
<li id="fn2"><p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>可</mi><mi>用</mi><mi>性</mi><mo>=</mo><mfrac><mrow><mi>M</mi><mi>T</mi><mi>B</mi><mi>F</mi></mrow><mrow><mi>M</mi><mi>T</mi><mi>B</mi><mi>F</mi><mo>+</mo><mi>M</mi><mi>T</mi><mi>T</mi><mi>R</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">可用性=\frac{MTBF}{MTBF+MTTR}</annotation></semantics></math>↩︎</p></li>
<li id="fn3"><p>无故障时间的平均值，即故障次数越低值越高↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">二次使用</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0</a></div></div></section></div> ]]></description>
  <category>worklog</category>
  <guid>https://luozx.org/posts/key-timestamps-in-incident-review.html</guid>
  <pubDate>Thu, 10 Jul 2025 02:25:00 GMT</pubDate>
</item>
<item>
  <title>SRE之道</title>
  <dc:creator>Luozx </dc:creator>
  <link>https://luozx.org/posts/the-sre-way.html</link>
  <description><![CDATA[ 

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NVV5S5NQ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->




<p>运维工程师，更传统的名字叫做系统管理员（Sysadmin），是负责维护和管理IT基础设施的核心角色，长期承担着保障系统稳定运行的重要职责。</p>
<p>另一个听起来更时髦的岗位，SRE<sup>1</sup>，因与运维工程师工作内容有重叠，常常被视为“高级运维工程师”，甚至被誉为”运维天花板”。</p>
<p>之所以有这种误解，我认为最主要的原因是那些声称采用了SRE实践的（大）公司，公开分享的内容都专注于如何将<a href="https://sre.google/sre-book/table-of-contents">《Site Reliability Engineering》</a>一书中提出的各种概念应用到自己的环境中，以及对不断涌现的新工具的追逐。<sup>2</sup>这种对“术”的过度关注，让我们忽略了对其本质的思考。</p>
<blockquote class="blockquote">
<p>The closer you look, the less you see.</p>
<p><a href="https://zh.wikipedia.org/zh-cn/%E5%87%BA%E7%A5%9E%E5%85%A5%E5%8C%96">Now You See Me</a></p>
</blockquote>
<details>
<summary>
例子
</summary>
<p>哔哩哔哩：<a href="https://www.bilibili.com/opus/689662861736149026">没有SLO就没有SRE？来看看B站SRE对SLO的实践总结</a></p>
<p>阿里巴巴：<a href="https://mp.weixin.qq.com/s/DUfoMeJa0spHO0d1p0RSdQ">这是阿里技术专家对 SRE 和稳定性保障的理解</a></p>
<p>美团：<a href="https://tech.meituan.com/2017/08/03/meituanyun-sre.html">云端的SRE发展与实践</a></p>
</details>
<p>SRE的本质并不能用简单的一句保障业务稳定性来概括。而《Site Reliability Engineering》带来的新概念和工具<sup>3</sup>，是为了达成软件开发速度与质量之间平衡的结果，不是原因。</p>
<p>是的，SRE的本质，我认为是为了平衡生产制造速度过快<sup>4</sup>而导致最终产品/服务 <sup>5</sup>质量下降的矛盾。</p>
<section id="回到2000年" class="level1">
<h1>回到2000年</h1>
<p>Google是SRE概念的发明者，并且将实践经验总结成《Site Reliability Engineering》一书。 SRE这个词汇也在这本书出版后流行了起来。</p>
<p>彼时（2000年左右）的Google属于初创公司，雅虎是当时的顶流网站。敏捷开发流行，作为技术起家的Google也同样采用Release early, release often文化，很长时间Google的产品都<a href="https://en.wikipedia.org/wiki/History_of_Google">带有BETA标签</a>。新功能快速迭代和新产品的快速上线有助于Google更快的获得更多用户，占领市场<sup>6</sup>。</p>
<p>快速的迭代和发布，意味着引入更频繁的变更，也意味着系统和服务出现错误的概率会更高。</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="https://image.luozx.org/garden/2025/05/0b6a7a8bef26531da0ec8b5cf0c39118.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Distributed system availability"><img src="https://image.luozx.org/garden/2025/05/0b6a7a8bef26531da0ec8b5cf0c39118.png" class="img-fluid figure-img" alt="Distributed system availability"></a></p>
<figcaption><a href="https://docs.aws.amazon.com/whitepapers/latest/availability-and-beyond-improving-resilience/distributed-system-availability.html">Distributed system availability</a></figcaption>
</figure>
</div>
<p>软件系统或服务经常出错，甚至崩溃/不可用，轻则导致用户流失，市场竞争力下降，造成公司经济损失。重则可能会对公共安全和生命安全造成威胁<sup>7</sup>。Google当时所面临的是第一种情况，也是现在大多数互联网公司所面临的情况。</p>
<p>另一方面，用户规模的快速增长，导致增加更多的硬件资源和支撑型的组件，这又会增加额外的复杂性和不确定性，同样会提升系统或服务出错的概率。</p>
<p>Borg，Kubernetes的前身，就是那时开发的<sup>8</sup>。</p>
<p>2003年<sup>9</sup>，正是在这样的背景下，Google的SRE团队成立。我们现在得到的信息是什么？</p>
<ol type="1">
<li>快速迭代和服务质量（可靠）的冲突</li>
<li>市场竞争和用户规模的快速增长的压力</li>
</ol>
<p>在那个时候，还不流行小而美这种不追求规模的创业理念。大家都想变大，Google也是。想要变大就必须在这两者之间寻求一种平衡。 SRE团队要解决的就是高速迭代和高质量服务之间的矛盾。</p>
</section>
<section id="缓冲" class="level1">
<h1>缓冲</h1>
<p>Google选择在这两者之间设置一条缓冲带：当缓冲充足时，让迭代尽可能的快，而当缓冲快要填满时，降低迭代速度，甚至暂停迭代，直到缓冲区有足够的空间，并且给这个缓冲起了一个名字–错误预算（Error Budget）。</p>
<blockquote class="blockquote">
<p>The structural conflict is between pace of innovation and product stability, and as described earlier, this conflict often is expressed indirectly. In SRE we bring this conflict to the fore, and then resolve it with the introduction of an error budget.</p>
<p><a href="https://sre.google/sre-book/introduction/">Tenets of SRE</a></p>
</blockquote>
<p>软件制品的生命周期分两部分：生产和运行。产生阶段通常由产品开发团队负责，部署运行阶段则交由运维团队或者负责。</p>
<p>生产阶段为了更快的推出新功能，往往采用敏捷开发理念，让产品和功能的迭代速度变快。正如上图所描述的，更频繁的变更带来的是服务脆弱的风险。SRE团队则采取”反敏捷”的方式来平衡这种风险。</p>
<p>错误预算让产品每次迭代的质量可度量<sup>10</sup>，Google通过服务等级目标（SLO）来计算错误预算的数值。这里，错误预算和SLO，以及SLO的下级指标SLI都是为了解决速度和质量矛盾的产物。</p>
</section>
<section id="缓冲的两侧" class="level1">
<h1>缓冲的两侧</h1>
<p>左侧，是产品服务的开发侧。右侧，是产品服务的运行侧。</p>
<p>软件工程学科的存在让我们将太多注意力集中在左边，而右边长久以来由松散的脚本和人力经验支撑，直到Google将右边工程化，平衡才得以实现。</p>
<p>非常有趣的是，在有些企业中，当右侧团队尝试用工程思维解决问题时，比如尝试运用数学方法和统计理论构建告警，得到了来自左侧团队的评价是「一个告警而已，搞那么复杂干什么」</p>
<p>更糟糕的情况，左侧团队几乎不使用任何工程化方法和理论进行产品开发工作。</p>
<p>工程化（Engineering），我指的是运用科学理论和数学工具进行产品研发。构建规模化的产品和服务，不能仅仅依靠对编程工具的熟练掌握，更不能期望通过这种方式构建可靠的产品和服务。</p>
</section>
<section id="sre之道" class="level1">
<h1>SRE之道</h1>
<p>寻求创新速度和服务质量间的平衡，正是SRE之道。</p>
<p>实现这种平衡，要求我们采用多种手段<sup>11</sup>：自动化，数据化，可视化…</p>
<p>采用SRE方法之所以困难，一个重要的原因是，我们在进行自动化，数据驱动开发，业务可观测的过程中，常常不记得这么做究竟是为了什么。</p>
<blockquote class="blockquote">
<p>Tools were only components in processes, working alongside chains of software, people, and data. Nothing here tells us how to solve problems universally, but that is the point. Stories like these are far more valuable than the code or designs they resulted in. Implementations are ephemeral, but the documented reasoning is priceless. Rarely do we have access to this kind of insight.</p>
<p><a href="https://sre.google/sre-book/foreword/">via</a></p>
</blockquote>


</section>


<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> 回到顶部</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">脚注</h2>

<ol>
<li id="fn1"><p>Site Reliability Engineering↩︎</p></li>
<li id="fn2"><p>与之相反的思考是：<a href="https://mcfunley.com/choose-boring-technology">Choose Boring Technology</a>↩︎</p></li>
<li id="fn3"><p>SLO，SLI等等↩︎</p></li>
<li id="fn4"><p>有主动的因素也有被动的因素↩︎</p></li>
<li id="fn5"><p>既包含广义的服务也包含开发过程的微服务↩︎</p></li>
<li id="fn6"><p>这个策略至今在竞争市场上依然有效↩︎</p></li>
<li id="fn7"><p>想想如果控制城市的电网系统或者负责民航的指挥系统出问题会怎样↩︎</p></li>
<li id="fn8"><p><a href="https://romanglushach.medium.com/the-evolution-of-kubernetes-from-borg-to-k8s-and-how-it-became-the-standard-for-container-7700dcdf883b">The Evolution of Kubernetes: From Borg to K8s and How it Became the Standard for Container Orchestration</a>↩︎</p></li>
<li id="fn9"><p>2004年，Google IPO↩︎</p></li>
<li id="fn10"><p>也基于两个团队对此的共识↩︎</p></li>
<li id="fn11"><p>甚至是文化变革↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">二次使用</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0</a></div></div></section></div> ]]></description>
  <category>worklog</category>
  <guid>https://luozx.org/posts/the-sre-way.html</guid>
  <pubDate>Wed, 28 May 2025 16:00:00 GMT</pubDate>
</item>
<item>
  <title>裁员, 是一件残忍的事情吗?</title>
  <dc:creator>Luozx </dc:creator>
  <link>https://luozx.org/posts/is-layoff-a-cruel-thing.html</link>
  <description><![CDATA[ 

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NVV5S5NQ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->




<p>和同事们一起吃饭, 聊天时提到一个来公司有很多年的同事, 被裁员了. 让我感到诧异的是, 一起吃饭的一个同事对公司裁员这件事的评价是: “公司很残忍的”</p>
<p>之所以感到惊讶, 是因为我认为公司裁员是再平常不过的一件事, 几乎可以说是一件可以预见的必然事件.</p>
<p>是因为什么, 我们的看法会有如此大的差异呢? 我无法猜测他的想法, 但是我想我或许可以从我的角度来解释为什么我认为裁员并不是一件残忍的事情.</p>
<section id="工作-是同公司合作" class="level2">
<h2 class="anchored" data-anchor-id="工作-是同公司合作">工作, 是同公司合作</h2>
<p>公司雇佣员工, 出发点是为了让员工帮助公司完成一些工作. 是用薪水置换员工的时间, 服务, 劳动力或者专业知识.</p>
<p>在这个过程中, 公司和员工之间建立的是一种合作关系. 你被公司聘用, 是因为公司通过面试过程, 认为你可以完成需要完成的工作. 你接受公司的聘用, 是因为公司为你支付的薪水在你的接受范围.</p>
</section>
<section id="奉献-是自己的选择" class="level2">
<h2 class="anchored" data-anchor-id="奉献-是自己的选择">奉献, 是自己的选择</h2>
<p>员工完成公司支付了薪水部分的工作, 是应该的. 除此之外的工作, 是员工的奉献, 是员工的自由.</p>
<p>选择奉献, 可能会给员工带来超额的回报, 比如更快的涨薪, 更快的升职. 但也可能什么都不会发生. 收益和风险总是并存, 期待获取收益而无视风险, 是危险的.</p>
<p>当员工的利益和公司的利益深度绑定时, 奉献所带来的收益往往才会更客观.</p>
<p>因为自己在公司很多年, 就要求公司必须珍稀自己, 是幼稚的.</p>
</section>
<section id="应该怎么做" class="level2">
<h2 class="anchored" data-anchor-id="应该怎么做">应该怎么做?</h2>
<p>没有人比你更关心你的钱, 也没有人比你更关心你的生活.</p>
<p>除了完成公司付你薪水的工作之外, 你可以选择奉献. 当你在奉献时, 请明白你正在攀爬<a href="https://book.douban.com/subject/35048531/#:~:text=2023%E5%B9%B4%E5%BA%A6%E6%8A%A5%E5%91%8A-,%E7%AC%AC%E4%BA%8C%E5%BA%A7%E5%B1%B1,-%E4%BD%9C%E8%80%85%3A%20%5B%E7%BE%8E">第几座山</a>. 明白奉献的收益和风险, 永远不要把奉献当成是一种义务, 因为你总是在追寻一些东西.</p>
<p>公司作为一个追逐利润的组织, 每个选择都在平衡风险和收益. 自己也应如此.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> 回到顶部</a><div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">二次使用</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0</a></div></div></section></div> ]]></description>
  <category>worklog</category>
  <guid>https://luozx.org/posts/is-layoff-a-cruel-thing.html</guid>
  <pubDate>Sat, 07 Sep 2024 16:00:00 GMT</pubDate>
</item>
<item>
  <title>两个文件的差集</title>
  <dc:creator>Luozx </dc:creator>
  <link>https://luozx.org/posts/difference-of-two-files.html</link>
  <description><![CDATA[ 

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NVV5S5NQ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->




<p>我在工作中,经常遇到这样的问题: 从一个地方抓取数据, 和另外一个地方的数据进行对比, 找出其中的差异. 这很像在求两个集合的差集. 由于大多数时候都面对*nix系统环境, 此时应该首先考虑使用<code>shell</code>工具而不是编程语言(比如<code>python</code>)</p>
<p>因为<code>shell</code>工具更快(谁不喜欢快呢)</p>
<section id="the-senario" class="level1">
<h1>The Senario</h1>
<p>以生产Kuberntes集群中的Deployment为标准, 列出验证环境Kuberntes多余的Deployment.</p>
<p>要解决这个问题, 大致分为下面几步:</p>
<ul>
<li>列出生产环境的Deployment, 保存到文件<code>prod.txt</code></li>
<li>列出验证环境的Deployment, 保存到文件<code>staging.txt</code></li>
<li>结果集 = <code>staging.txt</code> - <code>prod.txt</code></li>
</ul>
<p>每个文件里的内容大概是这样的, 每一行是一个Deployment的名称:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>prod.txt</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" data-filename="prod.txt" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb1-1">frontend-web</span>
<span id="cb1-2">backend-api</span>
<span id="cb1-3">database-mysql</span>
<span id="cb1-4">redis-cache</span>
<span id="cb1-5">elasticsearch-cluster</span>
<span id="cb1-6">auth-service</span>
<span id="cb1-7">logging-fluentd</span></code></pre></div></div>
</div>
<p>唯一不同的是<code>staging.txt</code>里的内容比<code>prod.txt</code>多一些:</p>
<p>要得到<code>staging.txt</code>比<code>prod.txt</code>多出的部分, 计算<code>staging.txt</code>和<code>prod.txt</code>的<em>差集</em><sup>1</sup>是一个符合直觉的做法.</p>
</section>
<section id="before-shell-solution" class="level1">
<h1>Before shell solution</h1>
<p>在Python中可以用<code>set</code>来表示集合, 用<code>-</code>来求差集:</p>
<div id="1cab633e" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">set_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>])</span>
<span id="cb2-2">set_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>])</span>
<span id="cb2-3">difference <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> set_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> set_b</span>
<span id="cb2-4"></span>
<span id="cb2-5">difference</span></code></pre></div></div>
<div class="cell-output cell-output-display" data-execution_count="1">
<pre><code>{1, 2}</code></pre>
</div>
</div>
<p>使用Python完全可以胜任,但是使用*nix环境给你提供的默认工具, 会让这个问题得以优雅的解决.</p>
</section>
<section id="the-shell-solution" class="level1">
<h1>The Shell Solution</h1>
<p><code>grep</code> 是Linux环境下最常见和常用的过滤工具, 我之前没有意识到他在处理这个问题上可以这么优雅.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-vFf</span> prod.txt staging.txt</span></code></pre></div></div>
<p>三个参数:</p>
<ul>
<li><code>-v</code> : 反向匹配, 即只匹配不包含的行</li>
<li><code>-F</code> : 以固定字符串而不是正则表达式进行匹配</li>
<li><code>-f</code> : 从文件中读取匹配模式</li>
</ul>
<p>也就是: 从<code>staging.txt</code>中匹配不包含在<code>prod.txt</code>中的行. 即<code>staging.txt</code>比<code>prod.txt</code>多出的部分.</p>
<p>三个参数中, <code>-v</code> 也许是我使用最多的,因为在筛选某些进程的进程(号)时,并不希望看到<em>grep</em>本身进程的进程(号).</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ps</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-ef</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> nginx <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-v</span> grep</span></code></pre></div></div>


</section>


<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> 回到顶部</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">脚注</h2>

<ol>
<li id="fn1"><p>两个集合的差集: <code>A - B</code> = <code>A</code>里有而<code>B</code>里没有的元素↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">二次使用</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0</a></div></div></section></div> ]]></description>
  <category>worklog</category>
  <category>tome-of-xp</category>
  <guid>https://luozx.org/posts/difference-of-two-files.html</guid>
  <pubDate>Tue, 20 Aug 2024 16:00:00 GMT</pubDate>
</item>
</channel>
</rss>
