
在规模的健康检查。
基础设施(34), 建筑(30)几天前在条纹的每周事件评论中,我们开始讨论一个始终令人惊讶的话题:HealthChecks。我从一直在想着他们,并已经写了我对健康检查的了解。
当我加入优步时,我们依赖了haproxy.路由流程之间的流量。HAProxy在现在所谓的内容中配置为sidecar模式。
我们在每个服务器上运行了一个haproxy实例,并通过检查存储在配置数据库中的元数据来生成服务器的路由配置clusto.,这有一些相似之处领事或者ettd.,但制作两个不同的基地设计选择,采摘(一种)强大的持续可用性和(b)放弃广泛,商业成功。
在CLUSTO中,每个服务声明(1)它应该可以到达的端口,(2)哪种主机应该能够将流量路由到它,(3)它应该运行的托管和(4)其健康检查协议和端点。
来自CLUSTO的聚合元数据编译为每个服务器HAProxy配置,使得在订阅主机类型上运行的进程将直接流量localhost:$ dest_service_port
并将路由到目标服务的健康实例。
每个HAProxy实例都有责任检查其下游服务的健康状况。这是可配置的,但对于绝大多数服务,这意味着发送HTTP请求/健康
并检查响应的状态代码。如果是一个200.
,然后它可用于交通,否则并非如此。
人类和软件都可以通过沿线使用脚本来操纵流程的健康状况身份
和状态
,将由它进行检查/健康
在决定适当的状态代码返回时。
这种方法有一些很好的财产。在网络分区的情况下,它会迅速恢复,没有人为行动。您可以构建任意复杂的工具来操纵身份
工具指示进程不应接收流量,我们的部署工具使用以在升级之前排除流量。此外,在该解决方案中有很少的移动部件,使其易于维持和延伸。
但是,它还具有一些缺点:HealthChecks的数量与服务和主机的数量相结合地执行了比例。粗略地,执行的HealthCheck数量的计算是:
主机数*每个主机的平均服务数*每位服务的平均下游服务数*每位服务的平均实例数
插入某些数字,让我们想象我们有100个主机,每个主机都运行10个服务。每个服务取决于其他3个其他服务。每个服务都有20个实例。
这让我们:
100 * 10 * 3 * 20 =每个时期的60,000个HealthChecks
我们每秒都没有执行HealthChecks,让我们说我们愿意容忍15秒的延迟,然后我们每秒做大约4,000个HealthChecks。请记住,这些非常少。实际上,我们拥有更多的主人,远远超过更多的服务,远远下游和更多的实例。
数字很快很大。
我们在每个服务器上添加了高性能HealthCheck缓存,该服务器在每个服务器上提供缓存的响应,并刷新的Healtheck响应乐队,以减少Python和Node.js等较慢语言所实现的服务器的负载,但最终是网络流量和CPU时间的庞大卷工作的健康检查成为一个瓶颈。
此时,您有三个选项:(1)您可以开始限制发现在POD中运行,(2)您可以卸载到集中或部分集中机制,或者(3)例如,您可以依靠检查流量,例如,被动健康检查,确定健康而不是活跃的健康检查。
优步实验并采用了所有三个的元素,最终我将以适当的规模和复杂程度达到争论,也可以采用所有三个。
Pod范围路由
减少能够互相通信的服务器,我命名为Pod-Scoped路由,具有至少三个不同的优点。
最重要的是,这允许您建立清晰的分离故障域名,使得一个POD可能会失败而不会影响其他豆荚预成型的类似工作。最常见的行业案例是限制高可用性或灾难恢复架构中的跨区域流量。这些单独的故障域成为尤其有效的部署目标,特别是对于通过傀儡或地形执行的较慢的基础设施变化。
POD也允许您最大限度地减少延迟,仅允许到附近主机的流量。具有特别小的POD大小,可以维护与下游进程的建立连接,而没有负载分布偏斜,该负载分布偏斜仅通过建立到下游服务的子集,而且还限制了在连接开销中投入的存储器和CPU。
最后,如果您不小心架构网络流量,则在某种程度上,您的网络成本可能成为您对整体基础架构成本的主要贡献者。Pod感知路由是最小化昂贵的网络流量的有效方法。
作为一个快速的注意,一些人试图通过将每个主机的意识限制对下游随机子集来限制HealthCheck开销。这基本上是一个ad-hoc,难以理解的豆荚。它使部署策略特别难以理解:即使是一个小的,增量的卷展栏可能会删除所有容量一些恰好只意识到这些特定主机的主机。通常,随机子集是一种避免如果可能的方法,尽管它是推销基础架构启动型驱动的一种的最后一个尾声方法。
集中的医疗检查
在某些基础设施复杂性的成本上,对网络分区有所减少,您可以通过集中机密检查责任来避免对健身支配的阻碍。而不是每个HAProxy实例(或者您的选择代理)执行自己的HealthChecks,而是您有一个集中式机制,为您和您提供检查(一种)将健康数据广播到订阅者或(b)提供一种富有表现力的界面,以允许代理快速且廉价地检索其特定兴趣的最新健康数据。
您可以在集中式检查器设计中可以在设计中的设计中具有相当大的最佳情况,以最大限度地减少这种方法的缺陷。例如,您不必必须从数千个代理中查询下游的健康只有一个执行检查的过程。如果检查器降级,您可能希望将每个下游的下游的健康检查三到五个冗余流程检查,以继续正常功能。
大多数以适度规模运营的技术公司最终将实现自己大致相当于的特使方法,但这里的股票市是漂亮的商品和成熟,可以融入较少,常见的实施。
就易于访问的技术来支持这种方法,使者对这种模式有良好的支持。你首先实施一个端点发现服务处理HealthChecking,并且每个Seneoy实例都会检查EDS以进行路由数据,而是执行本地确定。
检查交通
虽然有效的HealthChecks是您更新路由表的主要工具,以反映部署,主机升级或Whatnot等故意转换,但它永远不会忘记沿着以下行业实现绝大多数活动的健康检查:
@route(“/ health”)def healtheck(req):如果存在(“/ etc / status_down”):返回“绝望”,500返回“确定”,200
这种中等无用的标准实施使它们成为该过程的糟糕代表的实际情况。如果您希望有响应的路由,可快速响应劣化的进程,活动的健康检查是不够的。
您需要添加被动的HealthChecks。
在这种情况下,被动的医疗检查可以像检查从下游过程的响应代码一样简单,如果它们超过阈值,则从旋转中移除它们。即使是一个非常严格的阈值,例如在超过50%的请求返回错误时删除旋转下游,令人惊讶地效果很好。特使异常检测机制是一个有趣的现实世界的版本。
被动HealthChecks的价值在最大限度地减少了错误对上游用户和依赖过程的影响。考虑用于验证主机子集上的软件的公共金丝雀部署模式。您将通过将新版本部署到五个主机来启动,以及如果错误速率类似于现有错误率,您将继续您的部署。
如果您的金丝雀部署软件,可能会调用测试环境中存在但不在生产环境中存在的方法,从而通过金丝雀主机处理的100%请求失败。你的/健康
终点不太可能锻炼那个端点,并将继续愉快地给你竖起大拇指,让大公者保持旋转,直到你触发回滚。即使在最佳情况下,回滚通常会花几分钟,如果您必须使用新的构建,测试和部署循环(这是一种反模式,可以肯定),那么它可能会大大更长。
如果金丝雀占1%的流量,并且您依赖于活动的HealthChecks进行路由,那么您将继续失败1%的用户请求,直到恢复完成直到恢复完成。这是一个糟糕的结果,即使您的软件更接近服务有趣的猫视频的社会影响而不是挽救生命。相反,即使是非常保守的被动的医疗工作检查阈值也会将这些主体识别为行为不端,并将它们从旋转中取出不到一分钟。
缓解缓解旋转的不良主机的这种分离 - 从重新修复到更好的版本 - 对于快速恢复并最大限度地减少用户影响至关重要。当您考虑慢速更改(如滚动傀儡配置)时,这更为真实,在生产中进行了新的数据库版本,或者没有,其中转移路由仍然快速但恢复是危险和缓慢的。尽管如此,这允许您在诊断之前恢复,并且在复杂的分布式系统中,诊断通常是最慢的步骤。
一旦下游进程被标记为不健康,恢复沿线断路器模式。你会等一段时间,然后向下游发送一个固定数量的探测请求。如果他们有利响应,那么您将标记为健康并继续发送IT流量。
有时,人们陷入了更新路由配置的复杂性以执行被动健康检查,但这也可以通过扩展您的延长来实现/健康
相当于查看响应代码的本地缓存,并根据最近的结果修改健康状况。这种方法遭受了每次流程定制的诅咒,但确实允许您推出被动健康检查,而无需修改现有的路由和健康检查的基础架构。
优步无效hyperbahn.特别重视被动的医疗检查,消除了完全执行活跃的HealthCheck的代理的概念(尽管如上所述,集中式健康检查系统能够通知其可路由下游的更新代理可以提供活动健康检查的大多数好处)。
相反,它完全依赖于下游进程是否正确响应到传入流量,如果不是,从旋转中删除它们。这与用于IDEMPOTENT操作的自动重试周围的清晰语义可以最大限度地减少故障泄漏到上游。它还旨在使用相同的语义来实现中描述的一些先发制人重试方法尾巴以鳞片虽然我忘了,如果最终实现了实现。
你应该用三个
从长远来看,我非常有信心任何相当大的部署都会发现自己想要执行主动和被动的健康检查,在故障域范围内的POD中路由,并集中工作检查以减少HealthCheck卷。我确信有些人已经设法推迟了很长一段时间的一些人,但每个人都提供了如此多的实用程序,即我建议尽早采用它们而不是以后的方式。