<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; 稳定性</title>
	<atom:link href="https://www.phppan.com/tag/%e7%a8%b3%e5%ae%9a%e6%80%a7/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 25 Apr 2026 00:56:17 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>1:29:300！这个「魔鬼定律」正在预告你的下一次线上故障</title>
		<link>https://www.phppan.com/2025/05/129300-devil-rule-online-failure-warning/</link>
		<comments>https://www.phppan.com/2025/05/129300-devil-rule-online-failure-warning/#comments</comments>
		<pubDate>Fri, 16 May 2025 23:40:02 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[海恩法则]]></category>
		<category><![CDATA[稳定性]]></category>
		<category><![CDATA[线上故障]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2370</guid>
		<description><![CDATA[无论是深夜被夺命连环 call，还是眼睁睁看着用户反馈铺天盖地而来，那种感觉，相信大家或多或少都体验过。 当我 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" style="color: #000000;" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">无论是深夜被夺命连环 call，还是眼睁睁看着用户反馈铺天盖地而来，那种感觉，相信大家或多或少都体验过。</p>
<p data-tool="mdnice编辑器">当我们不幸经历了一次「刻骨铭心」的线上故障。痛定思痛，除了常规的复盘，我们也许要从一个更系统、更底层的视角，和团队的同学一起探讨：<strong style="color: #ff3502;">故障，究竟为何而来？我们又该如何防微杜渐？</strong></p>
<p data-tool="mdnice编辑器">今天，我们聊下安全管理领域的「老法师」——<strong style="color: #ff3502;">海恩法则（Heinrich&#8217;s Law）</strong>，以及它的一众「智慧亲友团」。</p>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #3f3f3f;">海恩法则：事故背后的「1:29:300」金字塔</span></h1>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">海恩法则的来历</span></h2>
<p data-tool="mdnice编辑器">海恩法则由美国工业安全先驱<strong style="color: #ff3502;">赫伯特·威廉·海因里希（Herbert William Heinrich）</strong> 在上世纪30年代提出。他在为保险公司工作时，通过分析数千份工伤事故报告，总结出了这个惊人的规律。最初应用于工业安全领域，但其揭示的事故发生规律具有普遍性，早已跨界影响到航空、医疗、乃至我们软件工程等多个领域。</p>
<p data-tool="mdnice编辑器">海恩法则指出：</p>
<blockquote class="custom-blockquote multiquote-1" data-tool="mdnice编辑器"><p><strong style="color: #ff3502;">在一件重大的事故背后，平均有 29 次轻微事故，以及 300 个无伤害的隐患或未遂事件。</strong></p></blockquote>
<p data-tool="mdnice编辑器">这个法则通常以 <strong style="color: #ff3502;">1:29:300</strong> 的金字塔比例来形象展示。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">海恩法则的核心思想</span></h2>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">事故是可以预防的</strong>：严重事故并非天降横祸，而是此前一系列小问题和风险累积、演变的结果。如果我们能有效管理「29」和「300」，就能大概率避免「1」的发生。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">重视「未遂先兆」</strong>：那 300 个「隐患」和 29 个「轻微事故」是重大事故的「报警器」。忽视它们，就等于给灾难开了绿灯。很多时候，我们只关注已经发生的「1」，却对冰山下的「29」和「300」视而不见。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">安全管理需系统化</strong>：事故的发生往往与管理体系的漏洞、流程的缺陷、安全文化的缺失等系统性问题相关。预防事故需要从整个系统的角度出发，进行持续改进。</section>
</li>
</ol>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">海恩法则的应用实例</span></h2>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">工业生产</strong>：工厂通过定期的安全检查、员工安全行为规范、隐患上报奖励等机制，主动排查和消除那「300 个隐患」，处理「29 起轻微事故」，从而避免重大生产安全事故。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">航空安全</strong>：每一次飞行前的详细检查、飞行员的严格培训、对飞行过程中任何微小异常的记录与分析，都是海恩法则的体现。一个螺丝的松动（隐患）如果不被发现，可能导致部件故障（轻微事故），极端情况下甚至引发空难（重大事故）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">医疗安全</strong>：医院对用药错误、手术流程中的小差错等「未遂事件」进行记录和分析，改进流程，以防止严重的医疗事故。</section>
</li>
</ul>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #3f3f3f;">对于线上故障，海恩法则给我们的启发与教训</span></h1>
<p data-tool="mdnice编辑器">海恩法则对于我们维护线上系统稳定性，尤其是复杂的线上应用，具有极其深刻的指导意义。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">教训与经验借鉴：</span></h2>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">「小问题」绝不小觑</strong>：线上一个偶发的 null 指针异常、某个非核心接口超时频率略增、用户反馈的一个「不太影响使用」的小 Bug，都可能是「29」或「300」的信号。如果仅仅是临时「hotfix」或者因为优先级不高而搁置，这些「小债」累积起来，迟早会引发“大雷”。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">「未遂」也是宝贵数据</strong>：一次灰度发布中发现的问题并回滚、一次压力测试暴露的瓶颈、一次配置错误在生效前被发现……这些都是「未遂事件」。它们暴露了流程或系统中的薄弱环节，是改进的绝佳机会，不能因为「没出事」就庆幸了事。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">故障复盘不能止于表面</strong>：发生故障后，不能仅仅定位到直接原因（比如某行代码写错了），更要深挖根本原因：为什么这行错误的代码能上线？测试为何没发现？Code Review 为何遗漏？发布流程是否有问题？这才是触及「300个隐患」层面的思考。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">建立「隐患上报」的文化</strong>：鼓励团队成员主动暴露系统中的潜在风险、不合理的设计、流程上的缺陷，即使这些问题短期内没有引发故障。要营造一个「说出问题是贡献」的安全文化氛围。</section>
</li>
</ol>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">哪些算作「轻微事故」和「隐患」？线上 BUG 怎么算？</span></h2>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">300 个隐患 &#8211; 系统中的「定时炸弹」</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">技术债</strong>：过时的库、临时的硬编码、缺乏注释的复杂代码、糟糕的架构设计。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">配置风险</strong>：配置项繁多且缺乏校验、配置管理混乱、关键配置依赖人工操作。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">监控盲区</strong>：核心业务指标未监控、告警阈值不合理、日志信息不全或格式混乱。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">测试覆盖不足</strong>：单元测试覆盖率低、缺乏有效的集成测试和端到端测试、对异常场景和边缘 Case 考虑不周。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">流程缺陷</strong>：发布流程不规范、变更管理随意、缺乏应急预案或预案未演练。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">知识断层</strong>：核心模块只有少数人懂、文档严重滞后或缺失。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">不规范的操作习惯</strong>：随意在线上环境执行高危操作、密码弱口令或共享。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">线上 BUG，未直接造成服务中断或核心功能严重受损的</strong>：例如，某个页面的 UI 显示错位、某个非核心功能的计算结果在特定条件下不准确但用户感知不强。这些 BUG 本身是问题，也是系统脆弱性的体现，属于「隐患」范畴，若不修复，可能在特定条件下与其他因素叠加，引发更严重问题。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">29 次轻微事故 &#8211; 系统发出的「黄牌警告」</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">短暂的服务抖动</strong>：例如，某个服务实例重启导致短时间部分请求失败。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">部分功能不可用或性能下降</strong>：例如，图片上传功能暂时失败、某个 API 响应时间飙升但未完全超时。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">告警频繁触发但能自动恢复</strong>：例如，CPU 使用率短时超阈值后回落。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">线上 BUG，已造成用户可感知的、轻微的功能异常或体验下降</strong>：例如，用户无法修改头像、搜索结果排序偶现不符合预期但仍可使用。这类 BUG 已经对用户产生了一定影响，属于轻微事故。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">资源超限警告</strong>：数据库连接池满、磁盘空间接近阈值。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">1 次重大故障 &#8211; 系统「拉响红色警报」</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">核心服务长时间中断</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">大面积用户无法使用核心功能</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">数据丢失或严重损坏</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">造成公司声誉或经济重大损失</strong>。</section>
</li>
</ul>
</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="font-weight: normal; color: #3f3f3f;">哪些指标能帮我们「看到」冰山？</span></h2>
<p data-tool="mdnice编辑器">有效的监控和度量是发现「29」和「300」的关键。以下一些指标可以帮助我们感知系统的健康状态：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">线上 BUG 数量与趋势</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">新增 BUG 数/解决 BUG 数</strong>：反映研发质量和修复效率。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">遗留 BUG 数量与等级分布</strong>：高等级 BUG 积压是重大风险。</section>
</li>
<li>
<section style="color: #010101;">BUG 平均解决时长 (MTTR for bugs)。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">代码质量指标</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">圈复杂度</strong>：高圈复杂度的代码往往难以理解和维护，是潜在的 BUG 温床和隐患。持续监控圈复杂度的变化趋势，对超标模块进行重构。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">代码重复率</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">静态代码分析告警数</strong>。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">系统稳定性与性能指标</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;">服务可用性 (SLA/SLO)。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">错误率</strong>：API 错误率、特定业务操作错误率。</section>
</li>
<li>
<section style="color: #010101;">平均响应时间 (Average Response Time) 与分位值 (e.g., P95, P99)。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">资源利用率与饱和度</strong>：CPU、内存、磁盘I/O、网络带宽、数据库连接池等。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">变更与发布相关指标</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">变更成功率</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">因变更引发的故障数</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">发布频率</strong> (高频健康的发布是敏捷和稳定的体现，但需质量保障)。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">告警与事件指标</strong>：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">告警数量与级别分布</strong>：过多低价值告警会造成“告警疲劳”。</section>
</li>
<li>
<section style="color: #010101;">平均故障检测时间 MTTD</section>
</li>
<li>
<section style="color: #010101;">平均故障恢复时间 MTTR</section>
</li>
</ul>
</section>
</li>
</ul>
<h3 data-tool="mdnice编辑器"><span class="content" style="color: #3f3f3f;">海恩法则的「亲友团」：这些智慧异曲同工</span></h3>
<p data-tool="mdnice编辑器">海恩法则并非孤军奋战，在安全管理和系统思维领域，还有许多理论与它遥相呼应，共同构成了我们理解和应对风险的知识体系：</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">墨菲定律</strong>：「凡事只要有可能出错，就一定会出错。」 它提醒我们不要抱有侥幸心理，任何潜在的风险点都可能在某个时刻爆发。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">多米诺理论</strong>：同为海因里希提出，认为事故的发生像一连串倒下的多米诺骨牌，由五个阶段（社会环境/遗传因素 -&gt; 人的失误 -&gt; 不安全行为/条件 -&gt; 事故 -&gt; 伤害）连锁引发。切断其中任何一环，特别是「不安全行为/条件」，就能阻止事故。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">冰山理论</strong>：事故的直接损失（如设备损坏、人员伤亡）只是冰山一角，水面下隐藏着更大的间接损失（如生产延误、声誉受损、员工士气低落等）和深层原因（管理缺陷、安全文化缺失）。与海恩法则的 1:29:300 有异曲同工之妙。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">帕累托法则 80/20 法则</strong>：大约 80% 的事故是由 20% 的原因造成的。这提示我们要集中资源解决那些最关键的风险点和隐患。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">鲍尔法则</strong>：系统越复杂，发生重大事故的概率越高。这警示我们在设计和维护复杂系统（如AIGC应用）时，要格外关注风险的累积和扩散。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">「四不放过」原则</strong>：事故原因不查清不放过、责任人未受到处理不放过、整改措施未落实不放过、相关人员未受到教育不放过。这是事故后处理的铁律，确保从错误中学习，防止重蹈覆辙。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">瑞士奶酪模型</strong>：由詹姆斯·里森（James Reason）提出。系统有多道防线（如代码规范、测试、监控），每道防线都像一片瑞士奶酪，上面有孔洞（缺陷）。当所有孔洞恰好对齐时，风险就会穿透所有防线，导致事故。这强调了单一防线的不足和多层防御的重要性。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #ff3502;">破窗效应</strong>：环境中一个未被修复的「破窗」，会暗示这里无人管理，从而诱发更多的混乱和破坏。对应到系统中，一个小 BUG、一个不规范的操作长期被容忍，会逐渐侵蚀团队的质量意识和纪律，最终导致大问题。</p>
</section>
</li>
</ol>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #3f3f3f;">从「救火」到「防火」：我们的系统性行动指南</span></h1>
<p data-tool="mdnice编辑器">理解了这些法则和理论，我们不能仅仅停留在「哦，原来如此」，更要将其转化为行动，从根本上提升系统的稳定性和韧性。</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">拥抱「小题大做」文化</strong>：对每一个「29」和「300」保持高度警惕，建立快速响应和彻底解决的机制。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">建立并严格执行「故障复盘」机制</strong>：深入挖掘根本原因，落实改进措施，并跟踪效果，形成闭环。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">强化「可观测性」建设</strong>：完善日志、指标、追踪体系，让系统的每一个角落都“透明可见”。利用好我们前面提到的各项指标。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">投资于「看不见的角落」</strong>：积极偿还技术债，优化系统架构，完善自动化测试，加强代码审查，推广混沌工程等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">提升团队的「风险意识」与「系统思维」</strong>：让每个人都成为系统安全的守护者，理解自己的工作如何影响全局。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">持续演练，常备不懈</strong>：完善应急预案，并定期组织真实场景的故障演练，提升团队应急响应能力。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #ff3502;">数据驱动，持续改进</strong>：利用收集到的指标数据，分析趋势，识别瓶颈，指导我们的优化方向。例如，如果线上 BUG 数持续在高位，或圈复杂度高的模块频繁出问题，那就是明确的改进信号。</section>
</li>
</ol>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #3f3f3f;">写在最后</span></h1>
<p data-tool="mdnice编辑器">线上系统的稳定性，是一场没有终点的马拉松，也是一场与熵增（系统混乱度增加的自然趋势）的持续对抗。故障不可怕，可怕的是从故障中一无所获，反复在同一个地方跌倒。</p>
<p data-tool="mdnice编辑器">希望海恩法则和它的「亲友团」能像一盏盏明灯，照亮我们系统中的每一个阴暗角落，指引我们关注那些微小的信号和潜在的风险。通过系统性的思考、数据驱动的决策和持续不懈的改进，我们一定能逐步减少重大故障的发生，为用户提供更稳定、更可靠的服务。</p>
<p data-tool="mdnice编辑器">以上。</p>
</section>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2025/05/129300-devil-rule-online-failure-warning/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>稳住！AIGC 架构中的排队系统与限流策略</title>
		<link>https://www.phppan.com/2025/04/aigc-queue-system-and-rate-limiting-strategies/</link>
		<comments>https://www.phppan.com/2025/04/aigc-queue-system-and-rate-limiting-strategies/#comments</comments>
		<pubDate>Sat, 19 Apr 2025 00:15:22 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[AIGC]]></category>
		<category><![CDATA[排队系统]]></category>
		<category><![CDATA[稳定性]]></category>
		<category><![CDATA[限流]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2357</guid>
		<description><![CDATA[&#160; 我们见过那么多 AIGC 的酷炫功能，文生图、图生视频，……，是不是觉得 AI 特别强大？但你想 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>&nbsp;</p>
<section id="nice" style="color: #000000;" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">我们见过那么多 AIGC 的酷炫功能，文生图、图生视频，……，是不是觉得 AI 特别强大？但你想过没，当成千上万的用户同时涌进来，都想让 AI 帮他们画画、写诗、做视频时，后台那些强大的模型和昂贵的计算资源（比如 GPU）会发生什么？</p>
<p data-tool="mdnice编辑器">如果不加管理，它们很可能瞬间就被「挤爆」了！服务器宕机、用户请求失败、体验直线下降，甚至可能因为资源滥用导致<strong style="color: #0e88eb;">成本失控</strong>。就像一家超火的餐厅，没有排队叫号系统，也没有门口保安/服务员控制人流，那里面肯定乱成一锅粥，谁也吃不好饭，对吧？</p>
<p data-tool="mdnice编辑器">比如年初 DeepSeek 不能用的场景。</p>
<p data-tool="mdnice编辑器">这就是为什么在设计 AIGC 架构时，排队系统和限流是绝对不能少的「定海神针」。它们就像餐厅的叫号系统和门口保安，确保整个服务流程既高效又有序，还能保护好咱们宝贵的「厨房」（计算资源）。</p>
<p data-tool="mdnice编辑器">那当排队系统或限流策略出现的时候，我们的产品可能会有哪些表现呢？或者作为一个用户我们能看到哪些？</p>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">1. 产品表现</span></h1>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">1.1 排队系统的「产品表现」</span></h2>
<p data-tool="mdnice编辑器">排队系统主要是为了处理「来不及马上做」的请求，但让用户知道「我已经收到你的指令了，正在处理中，请稍候」。所以它的表现形式通常和 <strong style="color: #0e88eb;">等待、状态更新、异步通知</strong> 有关。</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">「转圈圈」与进度条:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 你提交一个请求（比如让 AI 生成一张图片），界面上出现一个加载动画或者一个不太精确的进度条，告诉你「正在处理中」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这时候你的请求很可能已经进入了后台的队列，正在等待 GPU 资源。这个动画就是前端在告诉你：「别急，后台在排队/处理呢！」 对于耗时较短、用户愿意在线等待的任务，这是最常见的表现。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">明确的「排队中」或「处理中」状态 :</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 对于耗时较长的任务（比如生成一个几分钟的视频），产品界面可能会更明确地显示任务状态，比如在一个「我的任务」列表里看到：「排队中」 (排队位置 5)”、「处理中 (还剩 3 minutes )」、「已完成」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这直接反映了后台队列和处理单元的状态。用户可以离开页面，稍后再回来看结果。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">异步通知:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 你提交任务后，系统提示「任务已提交，处理完成后会通知您」。然后你该干嘛干嘛去。过了一会儿，你收到一个 App 内推送、邮件、短信或者其他形式的通知，告诉你「你的图片/视频生成好了，快来看看吧！」</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这是典型的异步处理 + 队列的应用。请求入队后，用户界面就响应了，处理完成后，通过通知机制把结果推给用户。用户体验非常好，不用傻等。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">预估等待时间:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 有些产品会根据当前队列的长度和系统的处理速度，给你一个大概的等待时间估计，比如「预计等待时间：约 5 分钟」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 系统监控着队列状态，并基于历史数据或当前负载进行预测，用来管理用户的预期。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">暂时无法提交新任务:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 在极少数极端高峰期，如果队列积压得实在太严重，产品可能会暂时禁止提交新的同类型任务，并提示「系统繁忙，请稍后再试」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这是一种保护机制，防止队列无限增长导致系统崩溃或等待时间过长。虽然体验不好，但有时是必要的。</section>
</li>
</ul>
</section>
</li>
</ol>
<p data-tool="mdnice编辑器">第 5 点的暂时无法提交新任务其实就是触发了限流策略。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">1.2 限流的「产品表现」</span></h2>
<p data-tool="mdnice编辑器">限流是为了保护系统不被过多请求压垮，所以它的表现形式通常和 <strong style="color: #0e88eb;">拒绝服务、错误提示、配额显示</strong> 有关。</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">「太快了，请稍后再试」:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 你在短时间内疯狂点击某个按钮，或者一个脚本高频调用某个 API，突然收到一个错误提示，比如「操作过于频繁，请稍后再试」、「API 调用次数已达上限」、「429 Too Many Requests」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 你触发了限流规则（比如每分钟只能调用 10 次）。服务器拒绝了你超额的请求，并明确告诉你原因。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">需要人机验证:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 在你进行某些敏感操作（如登录、发帖）过于频繁时，突然弹出一个图片验证码、滑动验证或者 reCAPTCHA，要求你证明自己是人类。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这是一种常见的反爬虫、反刷量的限流手段。系统怀疑可能是机器人在高频操作，用人机验证来增加门槛，降低请求频率。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">功能暂时不可用或降级:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 比如在一个免费的 AIGC 工具里，你可能发现每天只能生成 5 张图片，超过之后「生成」按钮就变灰了，或者提示你需要升级到付费版。或者，高峰期时，免费用户生成的图片分辨率会降低。或者，我们在使用一些大模型频繁的时候，会出现<strong style="color: #0e88eb;">降智</strong>的情况。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 这是基于用户身份或套餐的限流策略。通过限制使用次数或降低服务质量来保证核心资源的可用性，并引导用户付费。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">明确的配额/用量显示:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">表现：</strong> 在你的账户设置、API 控制台或者产品界面上，能清楚地看到你的使用额度，比如「本月 API 调用剩余次数：850/1000」、「今日图片生成次数：3/5」、「并行队列：5」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">背后逻辑：</strong> 透明地展示限流规则和当前用量，让用户心里有数，可以合理规划自己的使用，避免突然被拒。</section>
</li>
</ul>
</section>
</li>
</ol>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">1.3 产品表现小结</span></h2>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">排队系统</strong>主要通过<strong style="color: #0e88eb;">管理等待预期</strong>和<strong style="color: #0e88eb;">提供状态反馈</strong>来影响产品表现，目标是让耗时任务的处理过程更平滑、用户体验更好（即使需要等待）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流</strong>则主要通过<strong style="color: #0e88eb;">明确的拒绝或限制</strong>来影响产品表现，目标是保护系统、保证公平性、控制成本，有时也作为商业模式的一部分（区分不同用户等级）。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">限流是入口保安，决定「你能不能进」 以及 「进来的速度有多快」。</p>
<p data-tool="mdnice编辑器">排队系统是等候区管理员，负责管理「已经进来了但需要等待的人（任务）该怎么排队」。</p>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2. 设计考量</span></h1>
<p data-tool="mdnice编辑器">咱们已经知道用户可能会看到「转圈圈」或者「稍后再试」了。但作为产品的设计者和开发者，在决定用什么样的排队和限流策略时，背后有一大堆门道需要考虑。这就像规划一场大型活动，既要保证大家玩得开心（用户体验），又要控制好场地容量和资源消耗（系统稳定性和成本），还得考虑 VIP 客人是不是有特殊通道（公平性与商业模式）。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.1 目标第一：想达到什么效果？</span></h2>
<p data-tool="mdnice编辑器">这绝对是第一步，也是最重要的一步。我们引入排队和限流，到底是为了解决什么核心问题？</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">保命要紧:</strong> 是不是首要目标就是防止系统在高并发下崩溃？比如像 DeepSeek 那样，突然涌入大量用户，如果没有任何防护，服务器可能直接就「躺平」了。这时候，强力的限流和能有效缓冲的队列就是救命稻草。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">控制成本:</strong> AIGC 服务，尤其是 GPU 推理，那是「吞金兽」。是不是想确保资源使用不超预算？限流可以直接控制调用总量，排队也能让我们更平稳地调度昂贵资源，避免为了应对短暂高峰而过度配置。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">用户体验:</strong> 我们希望用户等待多久是可接受的？是希望尽量快地给结果（可能需要更多资源），还是可以接受一定等待但保证任务最终完成？排队系统的设计（比如优先级、等待时间预估）和限流策略（是直接拒绝还是友好提示）都直接影响用户感受。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">公平性与差异化服务:</strong> 是不是所有用户都一视同仁？还是说付费用户、高等级用户应该有更高的请求频率、更短的等待时间？这就需要在限流和排队策略里体现出差异化。比如，给 VIP 用户更高的 QPS 限制和专属的优先队列。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">防止滥用:</strong> 是不是担心有人恶意刷接口、爬数据，或者用脚本进行大规模、低价值的调用？限流（特别是基于 IP、用户 ID 的精细化限流）和人机验证就是重要的防御手段。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">想清楚了主要目标，后面的设计才有了方向。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.2 量体裁衣：系统和业务长啥样？</span></h2>
<p data-tool="mdnice编辑器">没有放之四海而皆准的完美方案，我们的设计必须契合自身的特点：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">任务特性:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">耗时:</strong> AIGC 任务耗时差异很大。文生图可能几秒到几十秒，训练一个模型可能几小时甚至几天。耗时长的任务更适合异步队列处理。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">资源消耗:</strong> 不同任务对 CPU、GPU、内存的需求不同。瓶颈在哪里？是 GPU 显存容易爆，还是 CPU 计算跟不上？这决定了我们的限流和队列应该重点保护哪些资源。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">可并行度:</strong> 某些任务能很好地并行处理，而有些则不行。这影响了你可以同时从队列中取出多少任务来处理。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">流量模式:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">峰值与均值:</strong> 我们的应用流量是比较平稳，还是有明显的潮汐效应（比如白天高峰，晚上低谷）或者突发尖峰（比如搞活动、上热搜）？应对突发尖峰，限流的令牌桶算法和有足够缓冲能力的队列就比较有用。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">用户构成:</strong> 主要用户是 C 端普通用户，还是 B 端开发者通过 API 调用？他们的行为模式和容忍度是不同的。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">技术栈与基础设施:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;">用的是云服务（AWS, Azure, GCP）还是自建机房？云服务通常自带成熟的队列（如 SQS, Pub/Sub）和网关限流功能，用起来方便。</section>
</li>
<li>
<section style="color: #010101;">系统是单体架构还是微服务？微服务架构下，限流可能需要在网关层和具体服务层都做考虑。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">商业模式 (Business Model):</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;">免费增值模式？那免费用户的限流策略和付费用户的肯定不一样。</section>
</li>
<li>
<section style="color: #010101;">按量付费？那精确的用量统计和限额就非常重要。</section>
</li>
</ul>
</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.3 队列怎么玩：策略与选择</span></h2>
<p data-tool="mdnice编辑器">如果决定用排队系统，具体怎么设计呢？</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">队列类型:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">先进先出 (FIFO):</strong> 最简单公平，按顺序处理。适合大部分场景。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">优先级队列:</strong> 可以让付费用户或紧急任务插队。实现起来复杂些，但能满足差异化服务需求。并且可以作为商业化的重要组成。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">延迟队列:</strong> 可以让任务在指定时间后才被处理，比如用于定时任务或重试。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">队列数量:</strong> 是所有任务都进一个大队列，还是按任务类型（文生图、文生文）、用户等级（免费、付费）分成多个队列？分队列可以实现更精细的控制和资源隔离，但管理更复杂。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">消息持久化:</strong> 请求（消息）进入队列后，是否需要保证即使系统重启也不会丢失？对于重要任务，需要选择支持持久化的消息队列（如 Kafka, RabbitMQ 持久化模式, SQS 标准队列）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">死信队列:</strong> 如果一个任务处理失败（比如代码 bug、资源问题），尝试几次后还是不行，总不能一直卡在队列里吧？可以把它移到一个特殊的「死信队列」，后续再人工分析处理。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">消费者逻辑:</strong> 从队列里取任务来处理的「消费者」程序，它的并发数怎么控制？怎么处理任务失败和重试？怎么向用户更新状态？</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.4 限流怎么限：策略与选择</span></h2>
<p data-tool="mdnice编辑器">限流策略的设计同样关键：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流算法:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">令牌桶:</strong> 最常用，允许一定的突发流量（只要桶里有令牌），控制平均速率。比较灵活。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">漏桶:</strong> 强制平滑请求速率，不管来多少请求，处理速度是恒定的。对于需要严格控制下游压力的场景有用。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">固定窗口/滑动窗口计数器:</strong> 实现相对简单，但固定窗口有边界问题，滑动窗口更精确但实现和存储开销稍大。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流维度:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">按用户/API Key:</strong> 最常见，实现差异化服务和防止单一用户滥用。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">按 IP 地址:</strong> 可以限制匿名用户或来自特定 IP 的恶意流量，但可能误伤使用共享 IP（如 NAT、VPN）的正常用户。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">按接口/服务:</strong> 对不同的 API 或服务设置不同的限制，保护核心或资源消耗大的接口。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">按模型:</strong> 模型云厂商中最常见，不同的模型，资源不同，限制的大小也不同。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">全局限流:</strong> 对整个系统设置一个总的入口限制。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流位置:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">网关层:</strong> 统一入口，实现方便，可以拦截大量非法请求。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">服务层:</strong> 更靠近业务逻辑，可以做更精细的控制。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">中间件/库:</strong> 在代码层面集成限流逻辑。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">超出限制后的行为:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">直接拒绝:</strong> 返回错误码（如 429 Too Many Requests）。最简单直接。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">排队等待:</strong> 把超出的请求放入一个短暂的等待队列（注意，这和我们前面说的主要用于异步任务的队列不同，这里的队列更像是限流器内部的一种缓冲机制），如果短时间内有处理能力空出来就处理。体验稍好，但增加了复杂性。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">降级处理:</strong> 比如返回一个缓存的、旧的结果，或者调用一个计算量更小的备用模型（一般称为降智）。</section>
</li>
</ul>
</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.5 用户体验：别让用户一脸懵</span></h2>
<p data-tool="mdnice编辑器">技术实现很重要，但最终是为用户服务的。怎么让这些机制不那么「讨人嫌」？</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">透明度:</strong> 尽可能让用户知道发生了什么。</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">等待时:</strong> 显示明确的状态（排队中、处理中）、进度条（即使不精确）、预估时间。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">被限流时:</strong> 返回清晰、友好的错误信息，说明原因（「操作太频繁」、「今日额度已用完」）以及何时可以重试。提供文档说明 API 的限流规则。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">配额显示:</strong> 在用户界面或账户中心清晰展示当前用量和总额度。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">预期管理:</strong> 通过预估等待时间、明确的配额等，让用户对可能发生的等待或限制有心理准备。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">友好的错误处理:</strong> 即使必须拒绝，也要给用户明确的指引，而不是冷冰冰的错误代码。</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">2.6 监控与迭代：持续观察与调整</span></h2>
<p data-tool="mdnice编辑器">最后，别忘了，这些都不是一成不变的。</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">监控指标:</strong> 你需要实时监控关键指标：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">队列:</strong> 队列长度、消息平均等待时间、消息积压数量、消费者处理速率、死信队列数量。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流:</strong> 请求总数、被限流的请求数、触发限流的规则/用户/IP 分布、响应时间。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">系统:</strong> CPU/GPU 使用率、内存占用、网络带宽、错误率。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">告警:</strong> 当指标超过阈值时（比如队列长度过长、限流拒绝率过高），需要及时收到告警。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">调优:</strong> 根据监控数据和业务变化，不断调整限流阈值、队列优先级、消费者数量等参数。可能需要进行 A/B 测试来验证不同策略的效果。</section>
</li>
</ul>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">3. 技术实现</span></h1>
<p data-tool="mdnice编辑器">聊完了「是什么」和「怎么想」，现在就到了「怎么做」的环节了。要把排队系统和限流策略落地，咱们得选对工具、用对方法。市面上成熟的方案很多，就像工具箱里的各种扳手和螺丝刀，得挑顺手的、合适的才行。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">3.1 排队系统的技术选型与实现</span></h2>
<p data-tool="mdnice编辑器">要搞个靠谱的排队系统，我们通常不会自己从零开始造轮子（那太复杂了！），而是会选用一些成熟的<strong style="color: #0e88eb;">消息队列中间件</strong>。这些中间件就像是专业的「排队调度中心」。</p>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">常见的「排队调度中心」有哪些？</strong></p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">RabbitMQ:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">特点:</strong> 老牌劲旅，功能非常全面，支持多种消息协议（比如 AMQP），路由规则特别灵活（可以搞得很复杂，比如根据消息内容决定发给哪个处理单元），社区成熟，文档丰富。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">适合场景:</strong> 需要复杂的消息路由逻辑、任务分发、对消息可靠性要求高的场景。比如，不同类型的 AIGC 任务（文生图、图生文）需要交给不同的处理集群。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">上手:</strong> 相对来说，配置和管理比 Kafka 简单一些。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">Kafka:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">特点:</strong> 设计目标就是<strong style="color: #0e88eb;">超高吞吐量</strong>！它更像是一个「可持久化的日志流」，数据来了就顺序写盘，消费者可以从任意位置开始读。天生适合分布式、高并发写入和读取。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">适合场景:</strong> 需要处理海量请求（比如用户行为日志、实时数据流）、对消息顺序有要求、能容忍稍高一点的延迟（相比内存队列）、需要消息回溯（重新消费）的场景。AIGC 的请求量如果巨大，或者需要记录详细的请求日志流，Kafka 是个好选择。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">上手:</strong> 集群部署和运维相对复杂一些。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">Redis:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">特点:</strong> Redis 本身是个内存数据库，速度飞快！可以用它的 List 数据结构（<code style="color: #0e8aeb;">LPUSH</code>/<code style="color: #0e8aeb;">RPOP</code>）模拟简单队列，或者用更现代的 Streams 数据类型（5.0 版本后的功能，功能更强，支持消费组、持久化等，有点像迷你版 Kafka）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">适合场景:</strong> 对性能要求极高、队列逻辑相对简单、可以接受一定的数据丢失风险（如果 Redis 挂了且没做持久化或主从）、或者你系统里已经重度使用 Redis，不想引入新组件。很多限流实现也会用到 Redis。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">上手:</strong> 如果你熟悉 Redis，用起来非常方便。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">云服务商提供的 MQ:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">特点:</strong> 云平台提供的托管服务。我们不用关心服务器运维、扩容缩容，按量付费，和云上其他服务（如 Lambda 函数、云存储）集成得非常好。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">适合场景:</strong> 应用部署在云上，想省心省力，快速搭建排队系统。它们通常提供标准队列（保证至少一次送达）和 FIFO 队列（保证顺序）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">上手:</strong> 非常简单，控制台点几下或者几行 SDK 代码就能用起来。</section>
</li>
</ul>
</section>
</li>
</ol>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">怎么选？</strong> 简单说：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">要灵活路由、功能全面？考虑 RabbitMQ。</section>
</li>
<li>
<section style="color: #010101;">要超高吞吐、能接受一定复杂性？考虑 Kafka。</section>
</li>
<li>
<section style="color: #010101;">要简单快速、或者已有 Redis？试试 Redis Streams/List。</section>
</li>
<li>
<section style="color: #010101;">在云上、想省事？用云厂商的 MQ 服务。</section>
</li>
</ul>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">实现时要注意啥？</strong></p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">生产者:</strong> 就是你接收用户请求的那部分服务（比如你的 Web API）。它需要把用户的请求（比如“画一只猫”）包装成一个**消息 (Message)**，扔进选好的队列里。这个消息里得包含足够的信息，比如任务类型、用户输入的提示词 (Prompt)、用户 ID、可能还有优先级等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">消费者</strong> 这是真正干活的「工人」（比如运行 AIGC 模型的 GPU 服务器上的程序）。它会不断地从队列里拉取（Pull）或接收推送（Push）过来的消息，然后根据消息内容执行任务（比如调用模型生成图片）。</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">并发控制:</strong> 你可以启动多个消费者实例来并行处理队列里的任务，提高效率。但要控制好数量，别把 GPU 资源撑爆了。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">任务确认:</strong> 消费者处理完一个任务后，一定要告诉队列：“这个活我干完了（Ack）！”这样队列才会把这个消息彻底删除。如果消费者处理失败或者挂了，没来得及确认，队列通常会把这个消息重新交给其他消费者处理（保证任务不丢失）。处理不了的坏消息，可以考虑扔进<strong style="color: #0e88eb;">死信队列</strong>。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">消息体设计:</strong> 消息里具体放啥内容得设计好。是直接把图片数据放进去（不推荐，太大），还是放一个指向存储的链接？用户 ID 要不要带上，方便后续通知？</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">3.2 限流的技术选型与实现</span></h2>
<p data-tool="mdnice编辑器">限流的实现方式也很多样，可以在不同的地方「设卡」。</p>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">在哪儿「设卡」？</strong></p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">网关层:</strong> 这是最常见的做法。在所有请求进入你系统的大门口（比如 API Gateway）就进行拦截。</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">工具:</strong> Nginx (自带 <code style="color: #0e8aeb;">limit_req</code> 模块)、Kong、Apigee、AWS API Gateway、Google Cloud API Gateway 等。这些网关通常都内置了限流功能，配置一下就行，对后端服务是透明的。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">优点:</strong> 统一管理，效率高，能把大量不合规的请求挡在外面，保护后端服务。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">缺点:</strong> 可能不够灵活，无法基于非常复杂的业务逻辑来限流。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">应用层/代码层:</strong> 直接在你的后端服务代码里加入限流逻辑。</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">工具:</strong></p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">各种语言的库/框架:</strong> 几乎每种流行的编程语言都有现成的限流库。比如 Java 的 Guava RateLimiter，Go 的 <code style="color: #0e8aeb;">golang.org/x/time/rate</code>，Python 的 <code style="color: #0e8aeb;">ratelimiter</code> 或集成在 Web 框架（如 Django/Flask）的插件，Node.js 的 <code style="color: #0e8aeb;">express-rate-limit</code> 等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">Web 框架中间件 (Middleware):</strong> 很多 Web 框架允许你插入中间件，在处理请求前后执行逻辑，非常适合放限流代码。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">优点:</strong> 最灵活，可以根据任意业务逻辑（比如用户等级、请求参数）来定制限流策略。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">缺点:</strong> 需要在每个需要限流的服务里都实现或引入，可能有点重复工作；性能开销比网关层高一点。</section>
</li>
</ul>
</section>
</li>
</ol>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">限流状态存哪儿？(尤其是在分布式系统里)</strong></p>
<p data-tool="mdnice编辑器">限流算法（比如令牌桶、滑动窗口）需要记录当前的状态（比如桶里还有多少令牌、窗口内有多少请求）。在分布式环境下（你有多个服务实例），这个状态必须是共享的。</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">Redis:</strong> <strong style="color: #0e88eb;">绝对的主力！</strong> 因为它：</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">快:</strong> 基于内存，读写速度非常快，对限流这种高频操作很友好。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">原子操作:</strong> Redis 提供了像 <code style="color: #0e8aeb;">INCR</code> (原子加一)、<code style="color: #0e8aeb;">EXPIRE</code> (设置过期时间) 这样的原子命令，这对于并发环境下的计数和状态更新至关重要，避免了竞态条件。很多复杂的限流逻辑可以通过 <strong style="color: #0e88eb;">Lua 脚本</strong> 在 Redis 服务端原子执行，保证一致性。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">适合分布式:</strong> 所有服务实例都可以访问同一个 Redis 来读写限流状态。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">内存</strong> 如果你的服务是单实例部署，或者限流逻辑不要求跨实例共享状态，那么用内存记录状态是最快的。但服务一重启状态就没了，也不适用于分布式系统。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据库:</strong> 理论上也可以，但数据库通常比 Redis 慢，对于限流这种需要快速响应的操作，可能会成为性能瓶颈，所以不太常用。</section>
</li>
</ul>
<p data-tool="mdnice编辑器"><strong style="color: #0e88eb;">算法怎么用代码大概实现一下？(概念性)</strong></p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">令牌桶:</strong></p>
<ol style="color: #000000;">
<li>
<section style="color: #010101;">每个用户/API Key 在 Redis 里对应一个 Key，存当前令牌数 (token count) 和上次添加令牌的时间戳 (last refill timestamp)。</section>
</li>
<li>
<section style="color: #010101;">请求来了，先根据时间差计算需要补充多少令牌（不能超过桶容量），更新令牌数和时间戳。</section>
</li>
<li>
<section style="color: #010101;">检查当前令牌数是否大于 0。</section>
</li>
<li>
<section style="color: #010101;">如果大于 0，令牌数减 1，允许请求通过。</section>
</li>
<li>
<section style="color: #010101;">如果等于 0，拒绝请求。</section>
</li>
</ol>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">关键:</strong> 上述步骤最好用 Lua 脚本在 Redis 里原子执行，防止并发问题。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: #000000;"><strong style="color: #0e88eb;">滑动窗口日志:</strong></p>
<ol style="color: #000000;">
<li>
<section style="color: #010101;">每个用户/API Key 在 Redis 里对应一个 Sorted Set。</section>
</li>
<li>
<section style="color: #010101;">请求来了，用当前时间戳作为 score，请求 ID (或时间戳+随机数) 作为 member，添加到 Sorted Set (<code style="color: #0e8aeb;">ZADD</code>)。</section>
</li>
<li>
<section style="color: #010101;">移除窗口之外的旧记录 (<code style="color: #0e8aeb;">ZREMRANGEBYSCORE</code>，移除时间戳小于 &#8220;当前时间 &#8211; 窗口大小&#8221; 的记录)。</section>
</li>
<li>
<section style="color: #010101;">获取当前窗口内的记录数量 (<code style="color: #0e8aeb;">ZCARD</code>)。</section>
</li>
<li>
<section style="color: #010101;">如果数量小于阈值，允许请求；否则拒绝。</section>
</li>
</ol>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">关键:</strong> 同样，这些操作最好也封装在 Lua 脚本里保证原子性。</section>
</li>
</ul>
</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">3.3 整合到 AIGC 流程</span></h2>
<p data-tool="mdnice编辑器">现在我们有了排队和限流的工具，怎么把它们串到咱们的 AIGC 服务流程里呢？想象一下一个典型的流程：</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">用户请求抵达:</strong> 比如用户在网页上点了“生成图片”按钮，请求发往后端。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">入口限流 (网关/服务):</strong> 请求首先经过<strong style="color: #0e88eb;">限流器</strong>。检查这个用户/IP 的请求频率是否超标。</p>
<ul style="color: #000000;">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">超标:</strong> 直接返回错误（如 429 Too Many Requests），流程结束。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">未超标:</strong> 请求继续往下走。</section>
</li>
</ul>
</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">请求处理与任务提交:</strong> 后端服务（比如 Web API）接收到请求，进行一些基本校验，然后把需要执行的 AIGC 任务（包含提示词、参数等）封装成一个消息。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">进入队列:</strong> 这个消息被发送到<strong style="color: #0e88eb;">消息队列 (MQ)</strong> 中。此时可以告诉用户「任务已提交，正在排队/处理中」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">任务排队等待:</strong> 消息在队列里按照策略（FIFO、优先级等）排队，等待有空闲的「工人」。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">工人处理任务 (消费者):</strong> 后台的 GPU 工作节点（消费者）从队列里拉取消息。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">(可选) 资源访问限流:</strong> 如果这个工人需要访问外部资源（比如调用另一个受限的 API），它内部可能也需要遵守相应的限流规则。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">执行 AIGC 任务:</strong> 工人调用模型，执行计算密集型的生成任务。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">存储结果:</strong> 生成结果（比如图片 URL、生成的文本）被存储到数据库或对象存储中。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">任务完成确认:</strong> 工人向消息队列发送确认信号 (Ack)。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">通知用户:</strong> 通过某种方式（比如 WebSocket 推送、回调 URL、或者用户主动查询状态）告知用户任务已完成，并提供结果。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">从整个流程来看，限流主要作用在<strong style="color: #0e88eb;">入口处（步骤 2）</strong>，有时也可能在<strong style="color: #0e88eb;">资源消耗端（步骤 7）</strong>。而排队系统则承担了<strong style="color: #0e88eb;">削峰填谷、异步解耦（步骤 4-6, 10）</strong> 的核心作用。</p>
<p data-tool="mdnice编辑器">技术实现这块，选型和细节非常多，但核心思路就是这样：根据我们的需求（性能、可靠性、成本、复杂度）选择合适的 MQ 和限流工具/库，然后把它们合理地嵌入到服务流程中，再配上完善的监控。这样，我们的 AIGC 应用就能更从容地应对用户的热情啦！=</p>
<p data-tool="mdnice编辑器">看到这里，你可能会问：排队和限流是不是有点像？它们都管理请求，但侧重点不同，而且经常一起工作：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">限流是「准入控制」</strong>：决定一个请求<strong style="color: #0e88eb;">能不能</strong>进入系统处理流程。它关注的是「速率」和「总量」，防止系统被瞬间打垮。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">排队是「流量整形」和「缓冲」</strong>：处理那些<strong style="color: #0e88eb;">已经被允许进入</strong>，但暂时无法立即处理的请求。它关注的是「平滑度」、「异步性」和「可靠性」。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">想象一下：</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">请求先到达<strong style="color: #0e88eb;">限流器</strong>（保安）。保安检查你的「票」（比如 API Key）以及当前人流速度，决定是否放你进去。</section>
</li>
<li>
<section style="color: #010101;">如果你被允许进入，但「处理台」（GPU）正忙，你就被引导到<strong style="color: #0e88eb;">排队系统</strong>（等候区）等待。</section>
</li>
<li>
<section style="color: #010101;">等处理台空闲了，就从队列里叫下一个号来处理。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">这样一套组合拳下来，AIGC 系统就能在汹涌的请求浪潮中保持稳定、高效、公平地运行啦！</p>
<h1 data-tool="mdnice编辑器"><span class="content" style="color: #0e8aeb;">4. 小结</span></h1>
<p data-tool="mdnice编辑器">对于 AIGC 架构而言，排队系统和限流策略并非「可选件」，而是保障系统<strong style="color: #0e88eb;">稳定性</strong>、<strong style="color: #0e88eb;">可用性</strong>、<strong style="color: #0e88eb;">公平性</strong> 和 <strong style="color: #0e88eb;">成本效益</strong> 的核心组件。在设计阶段就必须充分考虑：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">识别瓶颈：</strong> 哪些环节是资源密集型的？（通常是模型推理）</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">定义策略：</strong> 基于业务目标（用户体验、成本、公平性）设定合理的限流阈值和排队机制（如优先级）。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">选择工具：</strong> 根据技术栈、性能需求、运维复杂度选择合适的限流组件和消息队列。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">监控与调优：</strong> 持续监控队列长度、等待时间、限流触发次数、系统负载等指标，并根据实际运行情况不断调整策略。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">以上。</p>
</section>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2025/04/aigc-queue-system-and-rate-limiting-strategies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于复杂系统的思考：从语雀服务中断想到的</title>
		<link>https://www.phppan.com/2023/12/thinking-about-complex-systems/</link>
		<comments>https://www.phppan.com/2023/12/thinking-about-complex-systems/#comments</comments>
		<pubDate>Sat, 16 Dec 2023 14:06:16 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[SaaS]]></category>
		<category><![CDATA[技术管理]]></category>
		<category><![CDATA[稳定性]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=2126</guid>
		<description><![CDATA[在 10 月 23 日，语雀服务出现了一次重大故障，中断时间超过 7 小时。具体来说，这次故障的起因是在执行系 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #000000;" data-tool="mdnice编辑器"><span class="wx_text_underline">在 10 月 23 日，语雀服务出现了一次重大故障，中断时间超过 7 小时。</span>具体来说，这次故障的起因是在执行系统升级操作期间，新的运维升级工具出现了 bug，导致华东地区生产环境的存储服务器被误下线。由于存储系统使用的机器类别过于陈旧，无法直接将其上线，这导致了恢复过程时间延长。尽管语雀的工程师们立刻进行了恢复工作，但由于数据量大，恢复方案有限，恢复过程耗时 4 小时，数据检验耗时耗时 2 小时。这次故障给用户带来了严重的影响，也让我们重新审视关于本次故障带来的思考。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">我将整个复盘报告输入给到 chatGPT，其给我的回复如下：</p>
<p style="color: #000000;" data-tool="mdnice编辑器">从语雀的这次事故中，我们可以学到以下几个关键的教训：</p>
<ol class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">重视运维工具的测试和质量保证</strong>：在这次事故中，新的运维升级工具的 bug 是导致故障的主要原因。这说明，即使是运维工具，也需要进行足够的测试和质量保证。在实际使用之前，应该在相似的环境中进行充分的测试，确保其稳定性和安全性。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">灾备和恢复系统的重要性</strong>：即使有了数据备份，恢复仍然可能需要花费大量时间，这会导致服务中断时间过长。因此，除了定期备份数据外，还需要建立有效的灾备和恢复系统，以便在灾难发生时，能够快速恢复服务。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">灾难恢复演练的必要性</strong>：定期的灾难恢复演练可以帮助我们在真实的灾难发生时，更快地恢复服务。通过演练，我们可以发现并解决恢复过程中可能存在的问题，提高恢复的效率。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">高可用架构的重要性</strong>：高可用架构可以保证在部分系统组件发生故障时，整个系统仍能继续运行。在这次事故中，由于存储系统的故障，导致了整个服务的中断。如果有高可用架构，即使某个组件发生故障，也可以通过其他的组件提供服务，从而减少服务中断的可能性。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">灾难通信的重要性</strong>：在灾难发生后，应该及时向用户通报情况，说明故障的原因，修复的进度，以及预计的恢复时间。这样可以增加用户的信任度，减少用户的不安。在这次事故中，语雀做了很好的灾难通信，及时向用户报告了故障的详情，以及修复的进度。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">持续改进和学习的重要性</strong>：每次故障都是一次学习的机会。通过分析故障的原因，我们可以找出问题，改进系统，避免类似的故障再次发生。在这次事故中，语雀提出了一系列的改进措施，这表明他们有持续改进和学习的意识。</section>
</li>
</ol>
<p style="color: #000000;" data-tool="mdnice编辑器">但是从复杂系统的角度来看这个事件：<strong style="color: #0e88eb;">复杂系统的性质使得它们在面临故障时，能够以我们意料之外的方式表现出来。尽管我们可能已经在设计和实施阶段做了很多工作来确保系统的稳定性，但是在实际运行中，仍然会出现我们没有预见到的问题。</strong></p>
<p style="color: #000000;" data-tool="mdnice编辑器">高尔在讨论复杂系统时提到：「<strong style="color: #0e88eb;">具备故障防备能力的系统出故障的原因恰恰就是故障防备能力的失灵</strong>」。这是因为在设计防备系统时，我们往往会基于我们对系统的理解来设计，但是实际上，系统的行为可能会超出我们的理解范围。当系统的行为超出我们的预期时，我们的防备措施就可能会失效。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">这与这次语雀服务故障的情况非常相似。尽管语雀设计了一套备份恢复机制，但是在实际的故障中，由于对系统的理解不足，这套机制并没有发挥出应有的效果，反而延长了恢复时间。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">在许多情况下，一些复杂系统的故障并不是单一的、孤立的事件，而是由一系列的因素相互作用、相互影响的结果。这通常包括了系统设计、运维策略、人为错误等多个方面。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">具备故障防备能力的系统，其设计和运营目标是提供连续、稳定的服务，即使在面临内部错误或外部攻击等影响时也能持续运行。这种系统通常包含冗余的组件、自动故障切换机制、灾难恢复策略等措施，以保证系统的正常运行。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">然而，这些故障防备能力本身可能成为系统故障的源头，原因可能有以下几点：</p>
<ol class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">复杂性</strong>：<strong style="color: #0e88eb;">故障防备能力会增加系统的复杂性，复杂性本身就可能带来故障。</strong>例如，冗余的组件需要保持同步，如果同步机制出现问题，可能导致数据不一致，进而产生故障。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">人为错误</strong>：<strong style="color: #0e88eb;">故障防备能力的维护和操作需要人工参与，人为操作错误可能导致防备能力失灵。</strong>如语雀故障案例中，运维工具的 bug 就是人为因素导致的。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">预期和实际的差距</strong>：故障防备能力的设计和实施都是基于对可能故障的预期，但实际发生的故障可能超出了预期，导致防备能力无法应对。</p>
</section>
</li>
</ol>
<p style="color: #000000;" data-tool="mdnice编辑器">面对一个每天都在演化的复杂系统，我们应该做些什么呢？</p>
<p style="color: #000000;" data-tool="mdnice编辑器">面对复杂，我们第一个能想到的原则应该就是 KISS 原则了。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">「KISS」 原则是 「Keep It Simple, Stupid」 的缩写，这是一种广泛应用于工程、设计和决策过程中的设计原则。其最主要的理念就是保持事物的简单性。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">KISS 原则主张：</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">避免不必要的复杂性</section>
</li>
<li>
<section style="color: #010101;">优先选择简单、清晰和直观的解决方案</section>
</li>
<li>
<section style="color: #010101;">不要添加不必要的特性或功能</section>
</li>
<li>
<section style="color: #010101;">简单的设计更易于维护、理解和修改</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">这个原则并不是说所有的事物都必须以最简单的方式来完成，而是鼓励我们在设计和决策过程中，优先考虑最简单和最直接的方法，除非有充分的理由去选择更复杂的方案。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">简单性是一个非常重要的设计目标，因为它可以降低错误的可能性，提高系统的可靠性，减少维护的难度，提高效率，以及其他许多好处。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">我们如果应用了以下的一些建议，应该可以往 KISS 原则靠近一些：</p>
<ol class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">明确需求</strong>：首先明确我们试图解决的问题是什么。这有助于避免在设计和实现过程中添加不必要的功能或复杂性。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">简化设计</strong>：在设计过程中，始终问自己是否可以把事情做得更简单。避免过度设计，只实现真正需要的功能。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">模块化</strong>：把大问题分解成小问题，每个小问题都可以用简单的方式解决。这样，每个模块都保持简单，而整个系统则由这些简单模块组成。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">避免不必要的优化</strong>：过早的优化可能会增加复杂性。除非确定优化会带来显著的好处，否则最好先实现功能，然后再考虑优化。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">使用已有的解决方案</strong>：如果有已经存在的工具或库可以满足我们的需求，那就使用它，而不是从头开始创建。这样可以降低复杂性，同时节省时间。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">代码和设计的清晰性</strong>：代码应该易于理解，设计应该直观。这不仅提高了可维护性，也让其他团队成员更容易理解你的工作。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">定期回顾和重构</strong>：随着时间的推移和需求的变化，我们可能需要调整或简化现有的设计。定期回顾我们的代码和设计可以帮助我们找出可以简化的地方。</p>
</section>
</li>
</ol>
<p style="color: #000000;" data-tool="mdnice编辑器">作为一个技术管理者应该作些什么呢？<strong style="color: #0e88eb;">我认为最应该做的是拒绝那些让系统变得复杂的不合理需求，守好技术实现的大门。</strong></p>
<p style="color: #000000;" data-tool="mdnice编辑器">面对复杂系统，我们需要对系统有深入的理解，尽可能地简化系统，避免不必要的复杂性。通过模块化设计，将复杂系统分解为相对独立的部分，每个部分都可以单独理解和测试。并且设计出健壮的错误处理和恢复机制，同时也需要进行持续的监控和回顾。只有这样，才能提升系统的稳定性，减少服务中断的可能性。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2023/12/thinking-about-complex-systems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>研发管理之生产环境的变更管理</title>
		<link>https://www.phppan.com/2023/12/change-management-of-production-environment-in-rd-management/</link>
		<comments>https://www.phppan.com/2023/12/change-management-of-production-environment-in-rd-management/#comments</comments>
		<pubDate>Sat, 16 Dec 2023 13:58:14 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[必备技能]]></category>
		<category><![CDATA[研发管理]]></category>
		<category><![CDATA[稳定性]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=2112</guid>
		<description><![CDATA[2017 年，Amazon S3 服务在美国东部区域发生了大规模的故障，影响了许多依赖于 S3 的服务和应用。 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #000000;" data-tool="mdnice编辑器">2017 年，Amazon S3 服务在美国东部区域发生了大规模的故障，影响了许多依赖于 S3 的服务和应用。这次故障的根本原因是维护人员在执行一个操作时，错误地将更多的服务器脱机，这超过了系统设计的冗余容量，导致了该区域S3的部分子系统开始备份，进一步扩大了故障的影响。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">2018 年 10 月 31 日 GitHub 通过官方博客发布了 2018 年 10 月 21 日「挂掉」的事件分析。GitHub 指出此次事件发生的原因是在 10 月 21 日 22:52UTC 进行日常维护——更换发生故障的 100G 光学设备时导致美国东海岸网络中心与美国东海岸数据中心之间的连接断开。更具体地 GitHub 分析，虽然两地的连接在 43 秒内恢复，但这次短暂的中断引发了一系列事件，这才导致了长达 24 小时 11 分钟的服务降级。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">2020 年 7 月，Cloudflare 的 DNS 服务遭受了大规模的中断，影响了许多依赖其服务的网站。该故障的原因是 Cloudflare 的路由器中的一个错误配置。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">以上是在网上搜索各大平台的故障描述，可以看到这些故障都是由于生产环境的变更导致的，有些是网络设备变更，有些是配置变更，有些是维护人员在线上执行了某个操作…… 如此种种。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">这些问题最终都是开发人员通过系统化的建设，一个坑一个坑的填完了，但是当我们带着一个团队急速前进时，可能来不及做这些系统化的建设，此时通过流程对生产环境的变更进行管理，快速解决或规避一些问题以控制线上故障的出现。<strong style="color: #0e88eb;"><span class="wx_text_underline wx_text_underline_private">流程能保证的是我们做事的下限</span></strong><span class="wx_text_underline wx_text_underline_private">。</span></p>
<p style="color: #000000;" data-tool="mdnice编辑器">在做生产环境变更管理流程之前一定要明晰生产环境的概念和范围，在团队内达成共识，然后再去做流程，以规避因为对生产环境的概念和范围不一致，导致的误解和乌龙。</p>
<h1 style="color: #000000;" data-tool="mdnice编辑器"><span style="color: #0e88eb;">1 生产环境的概念</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">生产环境，也称为「产品环境」或「线上环境」，是指实际运行并对外提供服务的环境。这个环境中的软件版本、配置和数据都应该是最新的、经过充分测试的，以保证系统的稳定性和性能。线上环境需要提供24小时不间断的服务。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">一个应用或环境是否属于线上环境，主要取决于它是否直接对外提供服务</strong>。例如，如果一个应用接收并处理来自最终用户的请求，那么它就是线上环境的一部分。同样，如果一个环境中的数据被用于生产服务，那么这个环境也应该被视为线上环境。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">通常，生产环境包括以下 4 个部分：</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">硬件资源</strong>：例如服务器、网络设备、云服务中的硬件部分等；</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">软件资源</strong>：包括操作系统、数据库、中间件、云服务中的软件部分等；</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">应用程序</strong>：实际运行的业务代码和与之相关联的部分，如 CI/CD 工具；</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据</strong>：实际的用户数据和业务数据。</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">定义了生产环境，从生产环境衍生出生产环境的变更。</p>
<h1 style="color: #000000;" data-tool="mdnice编辑器"><span style="color: #0e88eb;">2 生产环境变更的概念和分类</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">生产环境的变更是指在生产环境中对任何一部分进行的修改，包括应用程序的更新、配置的修改、硬件设施的更换等。而线上故障大多来源于生产环境的变更，对生产环境的变更进行管理和控制，在较大程度上可以减少对系统稳定性产生影响。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">生产环境的变更从其组成出发，再加上外部流量，可以分为 5 类：</p>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">2.1 硬件资源变更</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">硬件资源变更主要包含所有与物理硬件和云服务硬件配置相关的更换、升级或维护。</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">硬件规格调整</strong>：例如，升级处理器（CPU）、扩充内存（RAM）、更换硬盘等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">网络设备更新</strong>：包括替换路由器、交换机或进行固件更新等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">存储设备变动</strong>：磁盘扩容、存储设备更换等场景会包含在内。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">云服务硬件调整</strong>：如云计算服务中服务器规格的调整、增减虚拟机实例、增减 POD 数、网络设备变更等。</section>
</li>
</ul>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">2.2 软件配置变更</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">软件配置变更涵盖了所有与操作系统、数据库、中间件以及云服务软件设置的修改。</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">操作系统参数调整</strong>：比如，优化操作系统性能通过调整系统参数等。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据库设置变动</strong>：例如，数据库参数调整或修改索引，导致数据库负载提升甚至锁表导致的无法读写等线上事故。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">中间件配置更新</strong>：如修改消息队列的设置，调整缓存策略导致缓存穿越或者缓存雪崩等线上问题时有发生。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">云服务软件配置调整</strong>：包括了云服务的安全规则更新、网络配置变动等。</section>
</li>
</ul>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">2.3 应用程序变更</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">应用程序变更主要包含了所有与业务代码和将业务代码发布到生产环境的 DevOps 工具的更改。</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">代码变更</strong>：代码变更是我们最最常见的变更类型，主要是通过修改代码改变应用程序并通过发布系统发布到生产环境。这也是我们变更管理中风险最大的地方，因为变更的人，变更的位置和逻辑等都是不确定的。除了正常的发布变更，应用的回滚也是应用变更的回滚，因为其改动了线上的应用。实际中，代码变更在逻辑上包括了修复 bug、优化性能、增加新功能等，都需要对应用程序代码进行更新。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">配置变更</strong>：指应用系统的配置变更，一般是通过配置系统来变更，触发线上应用的热更新或滚动，配置如果是写死在代码中，会变为代码变更。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">依赖库更新</strong>：实际业务中需要对应用程序所依赖的库或框架进行更新，有些更新可能需要改代码，或者代码本身已经是这么个逻辑，在构建的时候就会带出去。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">DevOps 工具变更</strong>：例如，升级工具版本，或者对某些功能进行调整。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">DevOps 工具配置变更</strong>：如发布脚本中对于 dev 或 prod 环境的配置修改等等，都是高风险操作，线上有着血淋淋的故障。</section>
</li>
</ul>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">2.4 数据变更</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">数据变更很少被人当作变更处理，因为很多时候就是正常的业务操作，如管理后台的批量操作这些，但是这些批量操作如果发生在高峰时期，可能会对线上业务带来较大的影响，轻则速度变慢，重则线上事故。数据变更可以分为线上数据的清理、迁移、更新等操作。</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据清理</strong>：如定期删除过期数据，清理无效数据节省成本等等，基于不同的目的，将数据清除，除了可能会影响性能，如果清理错了，将会导致用户丢失，以至用户资产的损坏，这将会是很大的线上事故。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据迁移</strong>：如将数据从一个数据库迁移到另一个数据库，或者因为业务升级，数据需要从一种逻辑迁移到另一种逻辑，除了负载压力，更多的可能是数据错乱或者数据丢失，这两种情况都会引发用户投诉。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">数据更新</strong>：如前面说的管理后台批量更新，或者上线新模块在已有的数据库上初始化数据等等，这种最多的情况是其引发的 DB/ES 等存储类中间件的高负载导致服务的异常或引发线上事故。</section>
</li>
</ul>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">2.5 流量变更</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">流量变更和上面四个类别不同，其是从外部来看的，主要包含了流量变化的情况。这里不考虑攻击类的流量。流量一般是带来高负载，或者由高负载引发的链路异常或雪崩，从而导致整体服务异常或线上事故。</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">负载调整</strong>：如对调整负载均衡策略，更改流量路由等由于考虑不周引发某些节点过热或流量过大，引发级联反应，从而出现异常或事故。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">后台投放或大型促销活动</strong>：如没有提前通知的后台投放或大型促销活动、特殊事件导致的流量激增，可能需要进行负载调整或资源扩容等，如果某些链路存在容量上限，或者达到扩容的上限，就会引起线上异常或事故。</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">以上 5 种类型画成简单的脑图，如下：</p>
<p style="color: #000000;"><img class="rich_pages wxw-img" src="https://mmbiz.qpic.cn/sz_mmbiz_png/suE0Ye6UeMz2m4w5J3rgZHdl8Owice3kkO8yKDyup2f4he0D0TbeOdLYQgwibYXCmUicd7nf3CUu6OLicpCkhoRDhw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" crossorigin="anonymous" data-galleryid="" data-ratio="1.3833333333333333" data-s="300,640" data-src="https://mmbiz.qpic.cn/sz_mmbiz_png/suE0Ye6UeMz2m4w5J3rgZHdl8Owice3kkO8yKDyup2f4he0D0TbeOdLYQgwibYXCmUicd7nf3CUu6OLicpCkhoRDhw/640?wx_fmt=png" data-type="png" data-w="1080" data-index="0" data-fail="0" /></p>
<h1 style="color: #000000;" data-tool="mdnice编辑器"><span style="color: #0e88eb;">3 变更管理</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">变更管理是指以可控的方式对线上的服务、配置或基础设施进行变更，从而减少变更对业务和服务质量的影响，快速处理变更可能带来的问题，提升系统的稳定性。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">变更管理，咱们从组织和流程机制两个方面来看。</p>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">3.1 组织</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">一个事情要想有力的执行下去，一定是有一个组织来保障事情的整体节奏和推进。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">从组织的角度，整个变更管理的组织成员角色可以分为以下几种：</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">变更管理主导者</strong>：一般来说，这个角色通常由技术团队的高级管理者来担任，并且这个事情它本身是一个从上向下的事情，需要更上层的负责人来推进事项，一般是 CTO 或 VP，或质量的负责人。他们需要确保变更管理策略和流程的成功实施，对整个变更管理过程负责，并需要对所有的变更决策拥有最后的决定权。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">变更管理委员会</strong>：这是一个跨部门的团队，包括来自业务、开发、运维、质量保证等部门的代表。他们的任务是评审即将进行的变更，评估其对业务的影响，以及是否符合公司的战略目标。他们还负责改进变更管理流程，并对变更管理的效果进行监督和评估。在实际的实施过程中可能没有正式的名称叫委员会，可能叫 XXX 质量小组，或者就是某个研发中心的管理团队兼任。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">变更经理</strong>：这个角色负责确保变更管理流程的日常运行，是实际的变更控制推进者，他们需要协调变更的执行，确保所有的变更都通过了必要的评审，已经准备好了回滚计划，并且变更后的效果已经得到了验证。在实际的实施过程中，变更经理大概率是某个 Leader 或者质量的负责人，或者 PM。</p>
</section>
</li>
<li>
<section style="color: #010101;">
<p style="color: black;"><strong style="color: #0e88eb;">变更执行人</strong>：这个角色负责协调变更的具体实施，例如安排变更的时间，通知相关人员，收集反馈，等等，一般这种变更由一线的开发，SRE 来做，也有大一些的公司有专门的职位。</p>
</section>
</li>
</ul>
<h2 style="color: #000000;" data-tool="mdnice编辑器"><span style="font-weight: bolder; color: #0e88eb;">3.2 流程机制</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">变更管理有一个理想状态的标准流程，其大概如下：</p>
<ol class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">变更申请</strong>：在我们的流程中可能是创建发布记录，或者申请紧急发布</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">变更评审</strong>：变更评审主要是检查变更过程是否完备，以降低变更的风险，其包括如下内容：</section>
<ol class="list-paddingleft-1">
<li>
<section style="color: #010101;">就绪分析：材料是否完备，人员、设备、软件、网络是否就绪，测试是否达到上线要求等。</section>
</li>
<li>
<section style="color: #010101;">风险分析：架构、性能、业务、合规等方面的风险评估，变更内容是否属于需求范围，变更是否可控。</section>
</li>
<li>
<section style="color: #010101;">重要程度：变更属于一般、重要、紧急、标准哪一种。</section>
</li>
<li>
<section style="color: #010101;">变更审查：内容是否满足业务需求，内容是否通过测试，测试是否全面、有效。</section>
</li>
<li>
<section style="color: #010101;">应急管理：变更步骤、应急方案、回滚方案、应急预案是否完备。</section>
</li>
<li>
<section style="color: #010101;">变更实施：变更计划时间如何安排，发布及回退操作步骤是否完备，自动化步骤情况。</section>
</li>
<li>
<section style="color: #010101;">变更验证：变更涉及的业务、技术验证方法与时间安排。</section>
</li>
</ol>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">变更审批</strong>：相关负责人对于变更评审的结果进行确认，并审批通过。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">变更执行</strong></section>
<ol class="list-paddingleft-1">
<li>
<section style="color: #010101;">根据发布计划执行发布操作，一般应该有一个灰度的过程；</section>
</li>
<li>
<section style="color: #010101;">验证线上功能并回归主流程；</section>
</li>
<li>
<section style="color: #010101;">持续灰度，观察用户直到灰度完成。</section>
</li>
</ol>
</li>
<li>
<section style="color: #010101;"><strong style="color: #0e88eb;">变更验收</strong></section>
<ol class="list-paddingleft-1">
<li>
<section style="color: #010101;">对发布的功能进行验收，对于影响范围内的功能进行验收，对业务主流程进行回归验收；</section>
</li>
<li>
<section style="color: #010101;">留守，并观察日志、监控服务负载等，这个操作是为了及时发现验收检查漏掉的问题，或者及时处理隐藏的问题，以减少变更后产生的问题对线上业务的影响。</section>
</li>
</ol>
</li>
</ol>
<p style="color: #000000;" data-tool="mdnice编辑器">我们做这个流程是形式上的安慰，还是僵化的惯性，还是能真正地解决问题，是我们在做这个流程以及执行这个流程中需要着重思考的问题。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">在变更前，即我们变更线上环境前需要自己做 Code Review，以及交叉的检查，以尽量减少问题流转到后面的操作中，节省问题的处理成本。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">在标准流程之外，另外还有两个特别重要的点，一个是周知，一个是盘点。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">周知在形式上可以是邮件、群通知、群消息，通过这些方式，将研发自己做的前面所定义的线上变更周知给相关方：「我们做了 XXX 操作，可能会影响 XXX ，你们看下对你们自己有没有影响，如果有相关告警可以找我。」</p>
<p style="color: #000000;" data-tool="mdnice编辑器">变更虽然有流程，但是流程保证的是过程，对于过程中的问题通过变更盘点的方式，阶段性回顾问题和成果，在变更委员会中达成共识并继续迭代。在每次迭代的时候我们可以问自己如下的一些问题：</p>
<ul class="list-paddingleft-1" style="color: #000000;" data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">与上次回顾相比，变更对线上的影响有更严重吗？有影响到稳定性吗？</section>
</li>
<li>
<section style="color: #010101;">变更流程是否有什么问题，是否需要专项来解决？是否应该解决？</section>
</li>
<li>
<section style="color: #010101;">上次回顾安排的事项落实了吗，对应的情况如何，是否有更新到流程或系统中？</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">以上的回顾操作我们建议以某个管理系统来承载，并且这个管理系统是带有通知等功能，以更好的将变更相关的信息周知出去。当然，也可能直接共享文档+群通知来搞。</p>
<h1 style="color: #000000;" data-tool="mdnice编辑器"><span style="color: #0e88eb;">4 小结</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">上面的变更管理只是流程方面的，对于实际中变更管理最好是能在类似于 DevOps 系统中的落地，最少也是在项目管理或流程系统中落地。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">生产环境的变更管理是一项复杂而重要的任务。通过对生产环境的良好理解，结合有效的组织、流程和系统工具，我们可以实现对生产环境变更的有效管理，保证业务的稳定运行，提升用户的使用体验，同时也提升了我们自身的运维效率和质量。这也是我们做研发管理必须要完成的任务之一。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2023/12/change-management-of-production-environment-in-rd-management/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
