
读前须知
不要: 不要认为能学习并理解到事故背后的技术架构全貌。 不要认为能学习并理解某个技术的基础知识。 要: 要认识到官方报告是为了对外做沟通,而不是对内。 要学习如何快速关注事故报告的重点内容,比如TTx、事故影响、处理过程尤其是如何快速缓和事故的步骤,事故发送的根本原因、针对事故发现的缺陷的改进想法,等等。 要学习一个好的事故报告应该准确地包含什么内容。 要保持思考。对哪些做的好,哪些不好要有独立的思考;哪些内容和过去自己的经验相符或不相符,并思考原因;哪些内容能够对现在的工作有所启发;等等。
亚马逊云服务事故报告的简要介绍
除此之外,我觉得AWS PES有一点做得更加比较贴心。PES所使用的语言会考虑事故所影响的地区的当地语言。例如发生东亚地区的事故,除了英文版本,PES页面还有中文、日文和韩文的版本。
了解亚马逊PES#11201
Summary of the Amazon Kinesis Event in the Northern Virginia (US-EAST-1) Region
Amazon Kinesis是什么?
看这篇文章之前我并不知道,于是我快速学习了一下。
这里我想先分享学习事故报告过程或者学习其他技术文章遇到不懂的技术,我们怎么快速了解这些它们?
我想大多人都能想到“搜索”。这确实是可靠的方法,但搜索的效率因人而异,而且差距可能很大。我的习惯是除了搜索它的基本介绍,还会特地地搜索它的替代品或竞争品,比如对于Amazon Kinesis,我会再看看“Amazon Kinesis alternatives”或“Amazon Kinesis competitors”的搜索结果。
于是,我对Amazon Kinesis有一个很简单的认知——AWS提供的一个实时的数据流处理服务,类似Azure的Event Hub。当然,这还需要自己对一些常见技术有一定的了解,比如熟悉Kafka的人会更容易理解Kinesis的关键技术模型。
由于这篇PES是一篇连一个加粗高亮都没有的朴素的诉述式长文,我们需要通读至少一遍全文,才能知道哪些是要点。
我快速通读一遍后,快速了解这篇PES的内容。按照内容顺序,大致如下:
第一部分是关于事故的梗概,以及和事故根因相关的设计实现。
第二部分具体描述了事故从发生到缓解的全过程,以及事故的根本原因。
第三部分介绍了Amazon Kinesis服务的短期和中长期的事后改善措施。
最后一部分简单介绍了依赖于Amazon Kinesis的上层AWS服务(Amazon Cognito, Amazon CloudWatch,Customer communication services)的事故缓解过程和优化措施。
接下来,我们聊聊这次事故的要点。
事故影响总结
2020年11月25日,Amazon Kinesis服务发生宕机,期间无法正确响应服务请求,导致依赖Amazon Kinesis的第三方服务和第一方服务受到严重影响。
受到影响的AWS第一方服务包括Amazon Cognito,Amazon CloudWatch,Amzon EventBridge,以及Amzon的客户沟通服务。这里还没包括依赖这些服务的更上层服务,比如AWS Auto Scaling,AWS Lambda,ECS(Elastic Container Service),EKS(Elastic Kunbernetes Service),等等。
根本原因
要了解根本原因,原文开始的时候介绍了导致事故发生的根本原因背后的设计。这部分描述的足够简单清楚,于是不做二次解读了,直接节选原文并高亮一些要点了。
Kinesis has a large number of “back-end” cell-clusters that process streams. These are the workhorses in Kinesis, providing distribution, access, and scalability for stream processing. Streams are spread across the back-end through a sharding mechanism owned by a “front-end” fleet of servers. A back-end cluster owns many shards and provides a consistent scaling unit and fault-isolation. The front-end’s job is small but important. It handles authentication, throttling, and request-routing to the correct stream-shards on the back-end clusters.
Each server in the front-end fleet maintains a cache of information, including membership details and shard ownership for the back-end clusters, called a shard-map. This information is obtained through calls to a microservice vending the membership information, retrieval of configuration information from DynamoDB, and continuous processing of messages from other Kinesis front-end servers. For the latter communication, each front-end server creates operating system threads for each of the other servers in the front-end fleet. Upon any addition of capacity, the servers that are already operating members of the fleet will learn of new servers joining and establish the appropriate threads. It takes up to an hour for any existing front-end fleet member to learn of new participants.
由于集群机器增加,前端服务器需要创建新的线程,结果总线程数超过了系统配置的最大值,然后Shard-Map不仅构建失败而且还返回一个不可用的实例,导致前端无法分发请求到相应的后端机器,Amazon Kinesis服务便不可用了。
由于扩容把整个集群搞宕机了,看到这里的我直呼“活久见”????????????。
一般来说,增加新的机器导致的事故一般是新的机器由于一些问题没配置好环境,进而分发到新机器的请求都失败了,但是一般来说SLB(Software Load Balancer)能快速检测出问题便缓和了事故(当然,前提是给SLB监听的heartbeat服务能检测环境问题)。
我们接着看看当时Amazon的工程团队是怎么发现和解决这个事故的。
事故发生和缓解过程
先从Kinesis服务的角度说说事故发生和缓解的过程(还附上自己的注释式旁白),之后在补充其他受影响的上层服务的处理过程。
Amazon Kinesis
2:44 AM PST:前端集群开始增加新的机器。
3:47 AM PST:前端集群新机器增加完毕。
5:15 AM PST:首次报警。on-call介入,开始看日志。然而,并无法直接定位问题根因源于扩容,因为日志里有大量与扩容无关的错误信息。虽然不肯定删除新增机器能恢复服务,但是还是决定先这样做了,同时继续研究其他错误,根因分析进展缓慢。
// 谨记:出事故的时候,错误日志多并不一定是好事,错误日志精准才是最重要的,否则只是拖延根因研究进展,尤其当错误日志里有大量“非错误”的正常日志。
7:51 AM PST:根因范围缩小,并确定最有可能的解决方式是重启前端集群。为了加速重启速度,做了一个hot-fix,即给前端服务器增加一个配置,以便重启后重新构建Shard-Map直接根据authoritative metadata store构建,而不需要其他机器的通信信息。
// authoritative metadata store是原文原话。根据之前介绍的Shard-Map构建过程(This information is obtained through calls to a microservice vending the membership information, retrieval of configuration information from DynamoDB, and continuous processing of messages from other Kinesis front-end servers),应该说的是前两部分吧,或者之一。
// 如果大家注意到上面原文的一个小细节(It takes up to an hour for any existing front-end fleet member to learn of new participants),应该会明白为什么构建shard-map的时候不参考其他服务器的信息能更快。
// 这里引出一个问题,为什么需要和其他前端服务器保持通信去维护shard-map呢?我想可能是为了动态地维持服务的高可用性吧,例如在后端出现错误结点的时候能更快速做故障切换。
9:39 AM PST:确认了根因,明确问题不是内存压力导致的,而是系统线程数超过了系统阈值。在这个时候,技术人员决定在缺乏足够测试的时候并不去冒险提高系统配置里的最大线程数,继续保持在删除新增机器之后重启。
// 谨记:在事故处理过程中,能恢复原样就尽量恢复原样,而不是冒险做hot-fix,因为后者可能引入新的问题,而且不进行充分测试我们也很难100%确定hot-fix依赖的功能是否真的可用。所以,我觉得Amazon工程团队当时的决定是非常正确的(这篇PES实在太详尽了,近乎啰嗦,这点细节都说出来了。)
10:07 AM PST:恢复了第一组前端服务器,并继续恢复更多服务器,以每小时几百台的速度。
10:23 PM PST:Kinesis服务恢复正常。
取决于压死骆驼的最后一根稻草(导致宕机的最后一台新机器),有可能是第一台,也可能是最后一台。我想,大概率是最后增加的机器,否则这个情况下应该会更早报警。我想大概率不会新机器增加完毕后才统一开始刷新Shard-Map,应该一台新机器加到集群后就开始正常运转了。
TTE(Time to Engage):不知道,但时间应该不长。
毕竟这个报警大概率是直接给Kinesis组打电话的。
TTM(Time to Mitigate):19h39m
这么基础的服务,在US EAST-1宕机了近20个小时,这肯定是非常糟糕的情况了,可能也是为什么会发布PES的原因吧。
in the early stages:尝试增加容量来增加对Kinesis调用的缓冲区,之后略有改善。
7:01 AM PST:错误率显著提升(坑不住了),工程团队开始做一个改动来减少对Kinesis的依赖。
10:15 AM PST:改动部署,错误率开始下降。(这个时候Kinesis也开始恢复了)
12:15 PM PST:错误率显著下降了 (也许更多是由于Kinesis的恢复)
2:18 PM PST:Cognito服务恢复正常。
5:15 AM PST:开始产生影响了,并报警。(基本和Kinesis自己的报警时间一致)
事后改进
先说说原文里提及的Amazon Kinesis服务相关的改进措施。
第一,将前端服务移到有更大CPU和内存的服务器上,减少集群服务器总数,进而减少事故再发生的机会。// 非常直观的一个改进想法,即有效减少事故再次发生的概率,也有助于提高TTM。
第二,增加更细粒度的线程消耗相关的报警。// 提高TTD
第三,验证增加系统配置里线程数的限制的方法是否能够有效缓和这次的事故,增加未来遇到同类事故的可靠的缓和方式。// 提高TTM
第四,做一系列改动去提高前端服务冷启动时间,比如将缓存Shard-Map放到专门的前端服务器,给一些重要的上层AWS服务配置单独的前端集群分区。我觉得还提高了前端服务的可靠性,至少对于核心的上层服务。// 提高TTM
原文提到,这项工作一直在进行,但尚未成功,还需要较长的时间完成。这点容易理解,毕竟架构的平滑迁移或升级需要谨慎小心,尤其对于现在使用量巨大的服务。
Amazon Cognito改善缓冲区,以确保能容忍更多的Kinesis请求错误,避免用户侧错误。
// 这是一种典型的渐进式部署方案,尤其对于平台或基础设施服务的新功能。
简单总结
其实,原文细节更多,我已经略过了一些内容,例如对ECS(Elastic Continer Service)和EKS(Elastic Kunberntes Service)的影响,对AWS客户沟通流程的影响和改进,等等。
最后,耐心看到这里,觉得这篇文章不错的,记得给个点赞、再看和转发分享????