欢迎
欢迎
一个基于Web的规模化部署包含许多机器。在任何时刻,一些机器是健康的,一些机器正在启动,一些机器正在排放,一些机器静静地坏掉。整个集群能够承受这种情况的原因是,每个机器在需要时都能立即回答两个简单的问题:
- /health —— 我当前是否能够处理真实请求?
- /version —— 我正在运行哪个代码?
此外,还有一个指标端点(通常为 /metrics )用于暴露用于监控工具的计数器和刻度仪。
这个课程将教你如何设计这些端点,以便它们实际上反映了现实,在代理层如何将四个黄金信号应用到这些端点上,以及观察到的数据如何驱动容量决策。
课程结束后,你将能够:
- 设计一个 /health 端点,它能够检测到真实的路径失败,而不是仅仅检测到进程的存活
- 设计一个 /version 端点,让你能够验证部署已经生效
- 将四个黄金信号(延迟、流量、错误、饱和度)应用到代理层
- 将观察到的突击指标与容量决策联系起来:何时扩容,何时排放,何时通知
- 理解 SLO 和错误预算消耗率的操作纪律,这背后体现了'我们关注多少'的原则
两种健康检查的类型
存活与就绪
存活:进程是否至少存活?由调度器(如 Kubernetes、systemd)来决定是否重新启动进程。
就绪:进程此时是否准备好处理真实流量?由负载均衡器来决定是否发送请求。
这两个问题是不同的。一个进程如果存活但无法访问数据库,它是存活但不就绪。一个进程如果正在启动,它是存活但尚未就绪。
浅度与深度健康检查
浅度:如果 HTTP 处理器运行,返回 {"status": "ok"} 。简单。只能检测到进程下线。
深度:实际执行真实请求路径。检查数据库连接池是否可以返回连接,缓存是否可达,下游依赖项是否响应。检测功能故障,浅层检查可能会遗漏。
权衡:深度检查需要付出更大的代价(每个检查本质上都是一个合成请求),并且可能导致级联故障(如果每个副本的健康检查都将压力传递给数据库,一個慢数据库将使所有副本不健康,从而将它们从轮换中移除,导致所有容量都被移除)。
最佳实践:对系统存活(快速、廉价,不依赖外部)进行浅层检查,对服务就绪(使用缓存结果,避免hammer下游依赖)进行深度检查。
版本端点
/version 返回 Git 提交、构建时间和服务名称。在部署后,您可以使用 curl https://service.example.com/version 并确认返回的提交与您推送的匹配。如果不匹配,说明部署失败但没有发出警告。
没有 /version,过时的部署可能看起来成功,并隐藏多小时。
最小响应形状:{"service": "my-api", "git_commit": "abc1234", "build_time": "2026-05-19T10:00:00Z"}。
延迟、流量、错误、饱和度
四个数字覆盖大部分操作
从 Google SRE 书籍。四个信号在每个服务层次上进行测量。如果对这四个信号进行良好的计数,您可以在用户做出操作之前捕获大多数生产问题。
延迟:请求花费的时间。报告分布,而不是只报告平均值。p99(99百分位延迟)比平均值更重要,因为尾部延迟是用户感觉为“慢”的原因。一个服务的平均延迟为50毫秒,p99为5000毫秒,虽然最差受影响的1%用户会感到明显,但其他用户可能永远不会注意到。
流量:每秒请求数。总请求数、每个端点、每个状态码、每个区域。基线已知;对异常进行告警(突降为入口问题;突增为涌流或攻击)。
错误:失败请求的速率。将 4xx(客户端错误,不是您的错)与 5xx(服务器错误,是您的错)区分开来。以百分比的流量率跟踪错误率,而不是以绝对数量进行跟踪,以便告警在不同负载水平下有效。
饱和度: 系统有多满? CPU利用率、内存、连接池深度、队列长度。引领指标。饱和度在延迟或错误下降之前会上升。饱和度为90%的层次,只需一分钟就可能导致队列崩溃。
特定于代理层次的内容
每个信号在边缘层次上亮起:
- 代理层次上的延迟: TLS握手持续时间、上游连接时间、请求-响应总时间。因为它们生活在不同部分的路径上,所以分别测量。
- 代理层次上的流量: 总请求/秒、每个后端的分布(热后端表明负载均衡器失调),每个状态码的分解。
- 代理层次上的错误: 从客户端(您的用户访问错误端点)收到的4xx,从后端(您的服务失败)收到的5xx、代理内部错误(502 = 后端无法访问,504 = 后端超时)。
- 代理层次上的饱和度: TLS会话计数、上游连接池深度、代理本身的CPU(TLS终止是CPU密集型)。
小贴士:在502数量骤然上升而后端延迟较低的情况下,意味着后端在响应之前挂起(连接重置、崩溃、内存溢出)。当504数量上升时,意味着后端较慢但仍在回答。阅读错误代码,它会告诉你失败的位置。
阅读信号
您的仪表板显示在过去的10分钟里如下:
- 流量: 大致保持在800 req/s(没有洪水)
- 延迟: p50稳定在40ms,p99从200ms上升到2,500ms,持续上升5分钟
- 错误: 4xx率保持在0.3%(正常背景);5xx率从0.1%上升到1.2%(主要是504 Gateway Timeout)
- 饱和度: 后端CPU从45%上升到78%,在同一时间段内;代理CPU保持在30%。
何时扩展、何时排空、何时报警
能力决策需要触发器
观察指标很容易。知道何时采取行动则是自律。
扩展时:当饱和度持续超过阈值时(例如,后端CPU超过70%持续5分钟),或者队列深度超过目标,或者延迟p99超过SLO。触发器应该在事情破裂之前触发,而不是在破裂时触发。
排空一个副本时:当它始终慢且错误率高,而同伴健康(一个副本运行得很热通常是主机级别的问题,而不是应用程序问题),或者在推出新版本时,或者优雅地将副本逐出。
在人力上报时:当SLO比错误预算能够承受的速度消耗时,或者饱和度触发器在自动扩展无法吸收时触发,或者出现级联模式(错误率和重试率都在攀升)。
不要在:当单个糟糕的分钟自己恢复时,或者背景批处理作业导致期望的周期性波动时,或者噪音超过阈值(阈值是错误的,而不是系统本身)。
SLOs & Error Budget Burn
SLO(服务级别目标)定义了可接受的性能:‘成功率>=99.9%在28天的窗口内’。补充(0.1%)是错误预算。
消耗率:您消耗错误预算的速度。假设您在1小时内消耗了10%的预算,速率为可持续的240倍(1小时是672个28天窗口的1/672;在该窗口内消耗10% = 10% × 672 = 6720%,预计为全窗口,允许100%)。
多窗口消耗速率报警:在短窗口(5分钟,14.4倍速率)和长窗口(1小时,6倍速率)都消耗得比可持续的更快时上报。可以捕捉到快速中断和慢速下降。
为容量而存在:运行在99.9% SLO的服务具有1%的缓冲区可以吸收小波动。运行在99.93%(刚刚满足SLO)的服务只需要一个糟糕的日子就可能会违约。容量决策应该针对一个舒适的SLO边缘,而不是满足它的最小值。
在观察下进行容量决策
您的服务的SLO为28天内成功请求的99.9%。在过去1小时的监控中当前状态为:
- 成功率:99.5%(持续30分钟)
- 后端CPU:整个集群平均82%(目标70%)
- p99延迟:800ms(SLO目标:<500ms)
- 流量:1400 req/s,高于基线1000 req/s(40%高于正常;趋势仍在上升)
- 自动扩展: 配置为在 CPU 超过 80% 持续 5 分钟时添加实例; 当前正在进行扩展操作,预计在 ~90 秒内添加 3 个实例
设计发布可观察性计划
合成
你现在可以设计一个 /health 来捕获真实的故障,一个 /version 来验证部署,四个金色信号仪表板在代理层,以及与 SLO 消耗率相关的容量触发器。
应用所有四个。
你的团队正在发布 search.example.com (从故障模式课程中学习的搜索服务)。该团队希望部署一个能够在用户之前捕获问题的可观察性,并具有明确的记录日志还是不记录决策矩阵。SLO: 99.9% 的请求成功, p99 延迟 < 300 ms,在 28 天的窗口内。
课程总结
课程总结
你已经完成了五个课程:
- 代理与源 :几乎每个公共网络服务都使用的边缘层形状
- 无状态水平扩展 :为什么一个无状态层可以便宜地扩展,以及如何 sizing 它
- 入口与出口分离 :为什么一个盒子变成两个,以及它强制执行的故障模式
- 故障模式与爆炸半径 :SPOFs,链式故障,后勤活动项目
- 可观察性与容量 (这个):需要测量的问题,以便在用户之前出现
主线: 网络级分布式系统不是魔法。它是由一小组模式组成的(反向代理、无状态副本、入口/出口分离、bulkheads & 断路器、四个金色信号),经过深思熟虑的组合。一旦你识别出这些模式,你会在每个生产架构中看到它们。
配套课程: 五个geometry-of-*课程将相同的内容以图论和几何学的形式重新表达。它们可以按照任何顺序学习。
好样的。