笔记。 翻译。:XNUMX月初,红帽公开谈论解决其服务用户在前几个月遇到的可访问性问题 (它基于容器镜像注册表,该公司在购买 CoreOS 时收到了该镜像)。 无论您对这项服务本身感兴趣如何,该公司的 SRE 工程师诊断和消除事故原因所采取的路径都是有启发性的。

19 月 XNUMX 日凌晨(东部夏令时间,EDT),quay.io 服务崩溃。 此次事故影响了 quay.io 消费者和使用 quay.io 作为构建和分发软件平台的开源项目。 红帽非常重视双方的信任。
SRE工程师团队立即介入,试图尽快稳定Quay服务。 然而,当他们这样做时,客户失去了推送新图像的能力,并且只有偶尔才能拉取现有图像。 由于某种未知原因,quay.io 数据库在将服务扩展到满容量后被阻止。
«有哪些变化?“ - 这是在这种情况下通常会问的第一个问题。 我们注意到,在问题发生前不久,OpenShift Dedicated 集群(运行 quay.io)开始更新到版本 4.3.19。 由于 quay.io 在 Red Hat OpenShift Dedicated (OSD) 上运行,因此定期更新是例行公事,从来不会造成问题。 此外,在过去的六个月里,我们对 Quay 集群进行了多次升级,没有出现任何服务中断。
当我们尝试恢复服务时,其他工程师开始使用之前版本的软件准备一个新的 OSD 集群,以便在出现问题时可以在其上部署所有内容。
根本原因分析
故障的主要症状是数以万计的数据库连接雪崩,导致 MySQL 实例实际上无法运行。 这使得诊断问题变得困难。 我们对客户端的最大连接数设置了限制,以帮助 SRE 团队评估问题。 我们没有注意到数据库有任何异常流量:事实上,大多数请求都是读取的,只有少数请求是写入的。
我们还尝试识别数据库流量中可能导致这种雪崩的模式。 但是,我们在日志中找不到任何模式。 在等待 OSD 4.3.18 的新集群准备就绪时,我们继续尝试启动 quay.io pod。 每次集群达到满负荷时,数据库就会冻结。 这意味着除了所有 quay.io Pod 之外,还需要重新启动 RDS 实例。
到了晚上,我们将服务稳定在只读模式,并禁用了尽可能多的非必要功能(例如命名空间垃圾收集),以减少数据库的负载。 冻结已经停止 但一直没有找到原因。 新的 OSD 集群已准备就绪,我们迁移了服务、连接了流量并继续进行监控。
Quay.io 在新的 OSD 集群上稳定工作,因此我们返回到数据库日志,但找不到可以解释阻塞的相关性。 OpenShift 工程师与我们合作,了解 Red Hat OpenShift 4.3.19 中的更改是否会导致 Quay 出现问题。 然而什么也没发现,而且 在实验室条件下无法重现该问题.
第二次失败
28 月 XNUMX 日,美国东部时间中午前不久,quay.io 再次崩溃,症状相同:数据库被阻止。 我们再次全力投入调查。 首先,需要恢复服务。 然而 这次重新启动 RDS 并重新启动 quay.io pod 没有执行任何操作:另一场雪崩般的联系已经压垮了基地。 但为什么?
Quay 是用 Python 编写的,每个 Pod 都作为一个整体容器运行。 容器运行时同时运行许多并行任务。 我们使用图书馆 gevent 下 gunicorn 处理网络请求。 当请求进入 Quay(通过我们自己的 API,或通过 Docker 的 API)时,它会被分配一个 gevent Worker。 通常,该工作人员应该联系数据库。 第一次失败后,我们发现 gevent 工作人员正在使用默认设置连接到数据库。
鉴于 Quay Pod 数量巨大且每秒有数千个传入请求,理论上,大量数据库连接可能会压垮 MySQL 实例。 通过监控,Quay 平均每秒处理 5 个请求。 数据库连接数大致相同。 5 个连接完全在我们的 RDS 实例的能力范围内(不能说是数万个)。 由于某种原因,连接数出现意外峰值但是,我们没有注意到与传入请求有任何关联。
这次我们决心找到并消除问题的根源,而不是局限于重启。 到 Quay 代码库 进行了更改以限制每个工作人员与数据库的连接数量 事件。 这个数字成为配置中的一个参数:可以动态更改它,而无需构建新的容器映像。 为了找出实际可以处理多少个连接,我们在临时环境中运行了多次测试,设置不同的值以了解这将如何影响负载测试场景。 结果发现 当连接数超过 502 时,Quay 开始抛出 10 错误。
我们立即将这个新版本部署到生产中,并开始监控数据库连接计划。 过去,基地在大约20分钟后就被封锁。 经过 30 分钟的无忧无虑后,我们有了希望,一个小时后,我们有了信心。 我们恢复了网站的流量并开始事后分析。
设法绕过导致阻塞的问题, 我们还没有找到其真正原因。 经确认,这与 OpenShift 4.3.19 中的任何更改无关,因为版本 4.3.18 上也发生了同样的情况,该版本之前与 Quay 配合使用没有任何问题。
显然,集群中还潜藏着其他东西。
详细研究
Quay.io 使用默认设置连接数据库六年没有出现任何问题。 发生了什么变化? 很明显,quay.io 上的流量一直在稳定增长。 在我们的例子中,看起来好像已经达到了某个阈值,这会触发大量连接。 第二次失败后,我们继续研究数据库日志,但没有发现任何模式或明显的关系。
与此同时,SRE 团队一直致力于改进 Quay 的请求可观察性和整体服务运行状况。 已部署新的指标和仪表板,显示码头的哪些部分最受客户欢迎。
Quay.io 在 9 月 XNUMX 日之前一直运行良好。 今天早上(美国东部时间),我们再次看到数据库连接数量显着增加。 这次没有停机,因为新参数限制了它们的数量并且不允许它们超过 MySQL 的吞吐量。 然而,在大约半个小时的时间里,许多用户注意到 quay.io 的性能缓慢。 我们使用添加的监控工具快速收集了所有可能的数据。 突然出现了一种模式。
就在连接激增之前,向 AppRegistry API 发出了大量请求。 应用程序注册表是 quay.io 的一个鲜为人知的功能。 它允许您存储诸如 Helm 图表和具有丰富元数据的容器之类的内容。 大多数 quay.io 用户不使用此功能,但 Red Hat OpenShift 积极使用它。 OperatorHub 作为 OpenShift 的一部分,将所有运算符存储在应用程序注册表中。 这些操作员构成了 OpenShift 工作负载生态系统和以合作伙伴为中心的操作模型(第 2 天操作)的基础。
每个 OpenShift 4 集群都使用内置 OperatorHub 中的 Operator 来发布可供安装的 Operator 目录,并为已安装的 Operator 提供更新。 随着OpenShift 4的日益普及,全球其上的集群数量也随之增加。 每个集群都会下载 Operator 内容来运行内置的 OperatorHub,并使用 quay.io 内的应用程序注册表作为后端。 在寻找问题根源的过程中,我们忽略了这样一个事实:随着 OpenShift 逐渐流行,很少使用的 quay.io 功能之一的负载也随之增加。.
我们对应用程序注册表请求流量进行了一些分析,并查看了注册表代码。 缺点立即暴露出来,因为数据库的查询没有以最佳方式形成。 当负载较低时,它们不会造成任何麻烦,但当负载增加时,它们就会成为问题的根源。 应用程序注册表结果有两个有问题的端点,它们不能很好地响应不断增加的负载:第一个端点提供了存储库中所有包的列表,第二个端点返回了包的所有 blob。
消除原因
在接下来的一周里,我们花了很多时间优化应用程序注册表本身的代码及其环境。 明显无效的 SQL 查询被重新设计,不必要的命令调用被消除 tar (每次检索 blob 时都会运行),尽可能添加缓存。 然后,我们进行了广泛的性能测试,并比较了更改前后应用程序注册表的速度。
以前需要半分钟的 API 请求现在只需几毫秒即可完成。 下周我们将更改部署到生产中,从那时起 quay.io 一直稳定运行。 在此期间,应用程序注册表端点上的流量出现了几次急剧峰值,但所做的改进避免了数据库中断。
我们学到了什么?
显然,任何服务都试图避免停机。 就我们而言,我们相信最近的中断有助于使 quay.io 变得更好。 我们吸取了一些重要的经验教训并愿意与大家分享:
- 有关谁使用您的服务以及如何使用您的服务的数据永远不会是多余的。 因为 Quay“正常工作”,所以我们无需花时间优化流量和管理负载。 所有这些都造成了一种错误的安全感,认为服务可以无限扩展。
- 当服务出现故障时, 让它恢复并运行是当务之急。。 由于 Quay 在第一次中断期间继续遭受数据库锁定的困扰,因此我们的标准程序没有达到预期效果,我们无法使用它们恢复服务。 这导致了这样一种情况:必须花时间分析和收集数据,以期找到根本原因,而不是集中精力恢复功能。
- 评估每个服务功能的影响。 客户很少使用应用程序注册表,因此这不是我们团队的优先事项。 当某些产品功能很少被使用时,它们的错误很少出现,开发人员就会停止监控代码。 人们很容易陷入这样的误解,认为事情本来就该如此——直到突然间,该功能发现自己成为了重大事件的中心。
接下来是什么?
确保服务稳定性的工作从未停止,我们也在不断改进。 随着 quay.io 上的流量持续增长,我们认识到我们有责任尽一切努力不辜负客户的信任。 因此,目前我们正在开展以下工作:
- 部署只读数据库副本,以帮助服务在主 RDS 实例出现问题时处理适当的流量。
- 更新RDS实例。 当前版本本身不是问题。 相反,我们只是想删除错误的踪迹(我们在失败期间遵循的踪迹); 保持软件最新将消除未来发生中断时的另一个因素。
- 整个集群的额外缓存。 我们继续寻找缓存可以减少数据库负载的领域。
- 添加 Web 应用程序防火墙 (WAF) 以查看谁连接到 quay.io 以及原因。
- 从下一个版本开始,红帽 OpenShift 集群将放弃应用程序注册表,转而使用基于 quay.io 上提供的容器映像的操作员目录。
- 应用程序注册表的长期替代可能是对开放容器计划 (OCI) 工件规范的支持。 它目前作为本机 Quay 功能实现,并将在规范本身最终确定后提供给用户。
上述所有内容都是红帽对 quay.io 持续投资的一部分,因为我们正在从小型“初创型”团队转变为成熟的 SRE 驱动平台。 我们知道,我们的许多客户在日常工作中都依赖 quay.io(包括红帽!),我们会尽力对最近的中断和持续的改进工作保持透明。
译者PS
另请阅读我们的博客:
- «“;
- «“;
- «“。
来源: habr.com
