00:00:00这期 Stand Up 节目会格外特别,因为 Casey 要来做开场。
00:00:05Casey,
00:00:06我们今天要聊什么?大家好,
00:00:10欢迎来到 Stand Up。根据最近的某个统计,
00:00:16我们是 Spotify 上第 45、
00:00:206 名最佳科技播客。没错。
00:00:29好吧,
00:00:29抱歉。今天在 Stand Up 上,
00:00:33我想聊一个话题。我会讲讲 10 月份发生的 AWS 宕机事件,
00:00:39但我之所以要讲这个,
00:00:41是因为我想探讨一个更宏大的议题,
00:00:44那就是真正理解某件事,
00:00:46与声称自己理解某件事之间的区别。
00:00:49比如有一种情况经常发生,
00:00:52尤其是对那些职业生涯早期的程序员——如果你是初级程序员之类的,
00:00:59刚入行。我知道我当时肯定也是这样,
00:01:03就是你想显得自己懂东西,
00:01:05对吧?你不想让别人觉得你不明白发生了什么。所以会有很多外部压力,
00:01:13不管这种压力是不是真实存在,
00:01:16你都会觉得应该表现出自己理解了某件事,
00:01:20或者假装理解,
00:01:22即便其实有点模糊或者没完全搞懂。
00:01:26而且即使不是你的错,
00:01:29比如即使那件事本身解释得不清楚,
00:01:33或者缺少重要信息,
00:01:35你仍然会被激励去表现得好像你知道那是什么,
00:01:40对吧?因为这样会让你看起来更聪明,
00:01:44或者至少不会显得很初级,
00:01:47对不对?所以我发现,
00:01:49至少对我来说,
00:01:51随着年龄增长和编程经验的积累,
00:01:55现在我几乎会过度地要求别人解释清楚。比如我会毫不在意看起来笨不笨。
00:02:03我会说,等一下,回去讲一遍。我没理解那部分。你说的是什么意思?或者那个术语是什么意思之类的?因为现在我真的不在乎这些了。
00:02:12我不再那么担心了。而且我想真正搞懂,因为我有太多编程经验,那些我以为自己懂或者假装懂的东西,最后都反过来坑了我。
00:02:22所以我会想,
00:02:23我要真正搞清楚。我想确定,
00:02:26当我对一个 bug 有了解释,
00:02:29或者我认为自己知道性能变慢的原因时,
00:02:32我脑子里总会想,
00:02:34如果我没有真正追根究底,
00:02:36可能是别的原因。可能真正的问题还藏在那里,
00:02:40只是我不知道,
00:02:42因为我没有彻底查清楚。我只是因为方便或者其他原因就继续往前走了。
00:02:48我之所以想谈谈 DynamoDB 这次宕机事件,
00:02:52是因为最近出现了一连串引人注目的高调故障。比如有一次大规模故障导致 Google 宕机,
00:03:00结果发现是因为他们没有处理某个字段为空的情况,
00:03:04对吧?就是他们编程的方式,
00:03:06他们写代码的时候是这样想的:好,
00:03:09我们有这个东西。我们加载一些 JSON,
00:03:12如果 JSON 里什么都没有,
00:03:15我们就直接解引用空指针之类的,
00:03:17对吧?就真的是这么回事,
00:03:19对吧?然后还有 CrowdStrike 那次,
00:03:23他们用蓝屏死机搞垮了全世界。那次他们给出了非常好的解释,
00:03:28真的是很棒的说明。他们说,
00:03:30我们做了某种数组大小设定的操作,
00:03:33然后我们的规则太多了。所以数组就溢出了,
00:03:36对吧?所以这些故障在他们给出所谓的 RCA 或者说根因分析的时候,
00:03:42解释得相当好,
00:03:43对吧?当他们说,
00:03:44这就是我们宕机的原因。当我读到这些的时候,
00:03:48我脑子里没有留下很多未解答的疑问。虽然我可能不知道具体是哪一行代码,
00:03:54因为他们可能没有公布具体的代码片段,
00:03:57但他们给我的信息足够让我说,
00:03:59好的,
00:04:00我理解有人是怎么写出这段代码的,
00:04:02我也理解他们犯的愚蠢错误是什么,
00:04:05对吧?就像,
00:04:06好,
00:04:07别那么做。我明白了。我完全能接受。
00:04:10至于 DynamoDB 那次,
00:04:12因为它在这个播客里被提起了,
00:04:15对吧?我们在那个,
00:04:16那个在吉他中心的哥们儿的时候谈到过,
00:04:20对吧?就是那个说,
00:04:21我在酒吧无意中听到有人在聊,
00:04:24对吧?
00:04:24没错。不可思议。在这里我们看到了难以捉摸的程序员,
00:04:28一种简单的生物,
00:04:30大部分时间独自工作,
00:04:31经常处于黑暗中,
00:04:33但这是什么?有人在互联网上说错话了。我们的程序员立刻采取行动,
00:04:38在亮光模式网站面前达到每分钟 120 个单词的最高速度。
00:04:42这些代码爱好者的天敌震慑住了我们的朋友。追逐被叫停了。我们得下次再抓他们。当不在电脑前时,
00:04:49他们可以花几个小时画一些粗糙的符号,
00:04:52他们称之为白板的东西。研究人员发现了数千种方言,
00:04:56通常一个办公室里就会用到十几种以上。然而,
00:05:00还没有语言学家能破译它们的用途是什么。
00:05:03这些虚荣的生物,
00:05:05他们的身体经过千年进化,
00:05:07能够以不寻常的姿势坐着同时在网上看自己。这种状态通常会持续很多小时,
00:05:14借口是他们在等代码审查,
00:05:17但追问他们为什么这么不活跃时。最后,
00:05:21在一整天几乎毫无成就之后,
00:05:23我们的键盘战士准备睡觉了。快速阅读一下,
00:05:28然后熄灯。
00:05:29晚安,小程序员。
00:05:30那我晚上怎么睡得这么香呢?嗯,
00:05:32我有 Sentry 帮我消灭那些 bug。我说的不是那种,
00:05:37不是那种小小的、
00:05:38微不足道的南达科他州的小虫子,
00:05:41冬天就死掉的那种。我说的是又大又凶的丛林虫子。顺便说一句,
00:05:46我不怕它们中的任何一个,
00:05:48只是,
00:05:48但我可以用 Sentry 的 Seer 压扁那些 bug。所以我当时更有动力去,
00:05:55好吧,
00:05:55让我去看看,
00:05:56他们发布了多少信息。我已经有点读过了,
00:05:59事后他们发布了一个总结,
00:06:01他们发了一个 RCA,
00:06:03非常模糊。就像那个 RCA 真的没怎么解释清楚。然后我注意到他们发布了一个完整的演示,
00:06:10就像在 12 月的 re:Invent 上,
00:06:14他们,
00:06:14或者我猜我不知道 re:Invent 是不是在 12 月,
00:06:19但视频是在 12 月上传的,
00:06:21就是 re:Invent 的演示,
00:06:24他们在里面讲了这次宕机。
00:06:26所以我去看了全部内容。在读完整个 RCA 并看完整个演示之后,
00:06:32我仍然感到困惑。我没看到对这个 bug 的真正解释,
00:06:38对吧?就像我试图弄清楚实际的 bug 是什么,
00:06:43但它从来没有被解释过。
00:06:45所以我想做的就是谈谈这个问题,
00:06:47讲一讲为什么我认为他们没有解释清楚这个 bug 是什么,
00:06:51并以此作为例子说明,
00:06:52我不认为大家应该就这样说,
00:06:54哦,
00:06:55好的,
00:06:55我知道这个 bug 是什么了。因为有人回复我说,
00:06:58哦,
00:06:59让我来给你解释一下这个 bug 是什么。然后他们只是解释了同样的东西。我就想,
00:07:04那不是 bug 所在。对吧。所以每个人都像是被激励着去说,
00:07:08我理解了。因为我读过了,
00:07:09就像是,
00:07:10不,
00:07:10如果你不能告诉我实际的 bug 是什么,
00:07:13那我们还没完。对吧。
00:07:14我们应该有更完整的解释。所以这一切听起来合理吗?我说的话?是的。首先,我只想说,我完全明白你在说什么,Casey。
00:07:23从一开始就明白,对吧。就是立刻。你就像,好的,我知道,我完全明白你在说什么。我这边没有问题。没有障碍。谢谢大家。我很好。
00:07:39明天见,
00:07:39伙计们。你知道的,
00:07:41没问题。我只想说,
00:07:42我真的很喜欢在 Spotify 上听播客时听 Casey 说话,
00:07:48但也包括现在,
00:07:49我可以听你说上一个小时。也要为 Spotify 点个赞。我正想说,
00:07:55我正想说,
00:07:56特别是当你在 Spotify 上听的时候,
00:07:59音质非常棒。你还能得到额外的花絮,
00:08:02对吧?你能听到所有正片前后的闲聊。我们开始在 Spotify 上发布更长、
00:08:08更长的版本,
00:08:09这些版本更像额外内容。是的。更少的是主题之外的内容,
00:08:14但在 Spotify 上会有更多的闲聊,
00:08:17因为现场观众能听到闲聊。
00:08:19他们可以进来这里。他们可以听到关于 trash 和他的宝可梦成瘾症的事,
00:08:24你可能都不知道,
00:08:25因为你没有,
00:08:25你是在 YouTube 上听这个的,
00:08:27对吧?你不会,
00:08:28你听不到所有有趣的东西。这对于 YouTube 视频的前 10 分钟来说是个很难卖出去的卖点。对 YouTube 视频来说这是非常难卖的。就像是,
00:08:37我要看四个人谈论一些我根本不理解的东西。而且它叫 DynamoDB。是的。
00:08:41既然我们要开始播客了,也许我们应该介绍一下 Adam。哦对。这说得很对。
00:08:45我们还完全没有介绍过。你好。跟我们说说你今天为什么来播客吧。
00:08:50因为我在 TJ 家,首先,第一个原因是 TJ 要求所有来他家的人都要上播客。有几次还挺尴尬的。是的。没错。你到底是谁?
00:09:07除了是 AWS 英雄之外。我甚至都不是,我不是 AWS 英雄。好吧。
00:09:13被踢出超级英雄组织。这是怎么回事?你就是不会被续约。
00:09:18我只当了一届英雄,然后他们决定,哦,你,这是个付费的事情吗?你付费成为英雄?
00:09:24不,
00:09:24不是,
00:09:25我只是不太在乎这个了。从来不谈论它。所以他们就想,
00:09:28也许他不再是英雄了。现在他是个反派。Casey 看起来像是某个谋杀悬疑剧的一部分。他站在那里。哦天哪。我们要,
00:09:36我们要看到,
00:09:36呃,
00:09:37就像那个,
00:09:38呃,
00:09:38是什么来着?Nick Hill。就是那个在白板上画画然后展示出来的人。还有 Casey Muratori。你想的就是那个。Muratori。是 Muratori 还是 Muratori?天哪。你要做视觉展示了吗?所以我知道这是最棒的播客。
00:09:54真的,
00:09:55这是最值得参与的一个。呃,
00:09:57我家里人的发音是 Muratori,
00:09:59就像那里有个 Y 一样,
00:10:01像 Muratori,
00:10:03但那是正确的。这其实没什么道理,
00:10:06因为它是意大利语,
00:10:07是个意大利名字。在意大利语中,
00:10:09应该是 Muratori 或 Muratori。
00:10:13说不通。所以为什么会变成 Mur 我完全不知道。那是某种意大利裔美国人移民时发生的事情,
00:10:23我猜。我不知道。好的。所以他们基本上是这样说的。
00:10:28他们有一种叫做 API 端点的东西,
00:10:31但他们就这么称呼它,
00:10:33对吧。这些就是域地址。就像如果你在 DNS 中查找,
00:10:38它就是你要查找的名称,
00:10:40用来知道你应该把你的 DynamoDB 请求发送到哪里。我猜这些东西看起来像这样。
00:10:47Adam 可能可以确认这一点,因为他是或者曾经是英雄。
00:10:53它们看起来像,
00:10:55哦,
00:10:55落后了。是的。我们落后了几秒钟。因为我们的视频在 river 上消失了。哦,
00:11:02好了。所以它们看起来像 dynamodb.us-east-1.api.aws 之类的。我猜这取决于你使用的是 IPv6 还是 IPv4。它们根据不同情况有不同的名称,
00:11:16或者你是否使用特定的,
00:11:18比如他们提到政府使用不同的名称之类的。所以这些名称基本上就是你硬编码到应用程序中的名称,
00:11:25你会说,
00:11:26当我需要对 DynamoDB 做些什么时,
00:11:29我就会去请求这个。这说得通吗?听起来对吗?Adam,
00:11:34因为我不用 AWS 的东西。是的。是的。是的。没问题。
00:11:38所以,你知道,你请求类似这样的东西,然后你要完美地发送。
00:11:42我的意思是,
00:11:43我知道他在说什么。是的。所以这会把你重定向到某个地方,
00:11:49因为显然不会有一台机器来处理整个宇宙中所有的 DynamoDB 流量。即使你按区域细分,
00:11:58你可以在这里看到,
00:12:00你应该选择一个区域。我猜你不会把它发送到某个主地址。你把它发送到一个区域地址,
00:12:08或者也许有一个主地址可以用来搞清楚这个。我不知道。
00:12:13但无论如何,
00:12:14在某个时刻你在与这个通信,
00:12:17而这个需要指向实际上像是一个负载均衡方案。所以这个东西应该指向他们所谓的 DNS 树。
00:12:27尽管他们从来没有真正解释过它的树结构本质。听起来更像是一个加权数组,
00:12:33如果你愿意这么说的话,
00:12:34你只是说,
00:12:35这里有一堆机器,
00:12:36你要根据我们设置的权重来选择这些机器,
00:12:40这样我们就可以进行负载均衡,
00:12:42对吧?所以如果一台机器落后了,
00:12:44也许我们会把它的权重设低一点。如果一台机器看起来比较空闲,
00:12:49我们就把它的权重设高一点。所以他们称它为树。我假设它是一棵树。他们从来没有解释树的部分是什么,
00:12:57但这个名称应该指向。我能打断一秒钟吗?
00:13:00顺便说一下,
00:13:01确实有人因为那棵树获得了 L6 晋升。所以我确实认为下次你应该弄清楚那棵树是什么。因为那对某人来说意义重大。好吧。有一个数据包,
00:13:10工程师们发生了事情。我同意。这棵树可能很重要。只是对于这个 bug 来说不重要。即便如此,
00:13:16所以我要说的是,
00:13:17他们没有必要解释这棵树在做什么。
00:13:19所以我可以接受他们跳过了树是什么。但我也有个小问题。
00:13:25它被称为树是因为这是根本原因分析吗?还是不是?
00:13:29别再开玩笑了。我们太偏题了。对不起。对不起。所以无论如何,这应该指向那个。
00:13:37然后,
00:13:38这种DNS条目的负载均衡方案,
00:13:41他们在演讲中描述的方式是,
00:13:43会使用类似plan145.dynamodb.DDB.AWS这样的东西,
00:13:50对吧?这是那棵树的根节点,
00:13:52我说的不是根因分析,
00:13:54而是像这棵树,
00:13:56它会包含一堆记录,
00:13:57这是一个顶级记录,
00:13:59包含了一堆允许它进行负载均衡的记录。我猜测Route 53有这种负载均衡能力。我是在解读演讲的言外之意,
00:14:09他们没有明说,
00:14:10但我假设Route 53——所有这些都是通过它来完成的,
00:14:15这是他们自己的DNS系统——允许负载均衡通过你在这里设置的内容来实现,
00:14:22设定负载均衡应该如何工作。然后它会根据某种随机化和权重之类的方式选择正确的机器。现在,
00:14:30他们说这个名字确实存在,
00:14:33显然有一个这样的树结构。这个名字只是他们在演讲中使用的,
00:14:38实际上他们从未真正使用过像我这里写的plan145这样人类可读的名字。实际上是某个东西的哈希值,
00:14:47所以实际上会是像0aFE12 9a之类的,
00:14:51对吧,
00:14:52这才是实际的样子。所以如果你去查看,
00:14:55不会看到人类可读的名字,
00:14:57至少在那个时候不会,
00:14:59我猜你不会看到像plan145这样的,
00:15:03只会看到那个哈希值。所以想法是,
00:15:06好的,
00:15:06用户要使用它,
00:15:08他们查询这个名字,
00:15:09Route 53会把他们导向这里。这个东西是某种负载均衡树,
00:15:15Route 53可以使用它,
00:15:18让你到达需要去的地方。最终它会给你一台实际的机器,
00:15:23你可以向它发送流量。再次强调,
00:15:26他们没有描述其中任何细节,
00:15:28所以我完全不知道这是怎么工作的。我从未接触或使用过Route 53,
00:15:35所以我不知道,
00:15:36但我们假设会发生这种情况,
00:15:38因为这对这个bug来说并不重要。
00:15:41我们有一位AWS专家。所以如果你有疑问,可以随时问Adam,他可能会有进一步的见解。我是说,可以问他。
00:15:50Route 53确实有很多不同的方式可以分配流量。是的,加权就是其中之一,听起来就像他们描述的那样。
00:15:57所以他们以某种方式设置了这些记录。他们只是没说具体怎么做的,
00:16:02但是以树格式的某种方式实现了。我猜测可能是有一个加权的,
00:16:06就像树有加权结构,
00:16:07顶部有几个权重,
00:16:08然后分支到更多权重之类的,
00:16:10因为这样处理起来更容易,
00:16:12因为有很多机器或者什么的。
00:16:14谁知道呢?总之,我不知道。重点是,这就是正常情况下应该发生的事情。
00:16:20现在,
00:16:20这里称为plan145的原因,
00:16:23尽管实际上应该是某个哈希码,
00:16:26但他们把它称作plan145,
00:16:28是因为正如你可能想象的,
00:16:30负载均衡必须是持续进行的,
00:16:33因为DynamoDB的机器一直在做各种事情。它们变得越来越过载,
00:16:39有机器宕机或崩溃或者谁知道还有什么,
00:16:42对吧?
00:16:43可能正在发生,
00:16:44被下线。新容量可以被添加进来。所以这些东西必须不断更新,
00:16:50一直都在更新。所以你连接的这个主API端点,
00:16:55它必须不断调整它所指向的那棵树。而他们的做法是创建另一棵树,
00:17:02也就是他们要迁移到的那棵树,
00:17:05对吧?他们会创建类似146号计划之类的东西。然后在这里建立整棵树。当他们准备好的时候,
00:17:15比如这棵树完成了,
00:17:17他们就把这个记录拿出来,
00:17:19不再让它指向那棵旧树,
00:17:22而是指向这棵新树,
00:17:24对吧?所以你先建好新树,
00:17:26然后只需要改变那个名称就能切换过去。现在,
00:17:31出于某种原因,
00:17:33而这个原因并没有真正被解释清楚。
00:17:36他们设置这个流程的方式是把它分成两个部分。有一个叫做规划器的东西,
00:17:43基本上负责计算新树应该长什么样。所以你可以想象有一台叫做规划器的机器。我不知道它是不是真的一台独立机器,
00:17:53还是只是运行在某台同时运行其他东西的机器上的一个进程,
00:17:59谁知道呢。但总之有个叫规划器的东西。据我所知,
00:18:03只有一个,
00:18:04意思是就只有一个规划器坐在那里,
00:18:08计算我们要切换到的新计划应该是什么样子。
00:18:13而且它一直在做这件事。所以它生成145号计划,
00:18:18然后生成146号计划,
00:18:20然后生成147、
00:18:22148、
00:18:23149、
00:18:24150,
00:18:24诸如此类,
00:18:26对吧?它就一直不停地输出计划,
00:18:29直到永远,
00:18:30因为这就是它的工作。现在,
00:18:33显然它从来不会真正创建它们。它的工作不是把它们放进Route 53里。它只是计算如果有人要把它们放进Route 53的话,
00:18:46它们会是什么样子。然后他们有三个执行器。
00:18:50这些执行器从规划器那里获取计划,然后把它放进Route 53里。
00:19:06理解了吗?现在,
00:19:08据我理解,
00:19:09一个规划器,
00:19:10三个执行器。没有解释为什么会是这样的架构。他们说之所以有三个执行器是因为这样设计具有容错性,
00:19:20比如其中一个挂了之类的。但他们从来没有解释为什么不需要三个规划器,
00:19:27因为如果规划器挂了,
00:19:29那执行器就没有东西可执行了。所以这真的说不通。所以在这个演讲里没有解释为什么这个结构是这样设计的。虽然这个结构跟后面的bug其实有点关系,
00:19:43但对bug本身来说并不是特别重要,
00:19:46我们后面会看到。所以我对他们没有解释这一点感到有点奇怪,
00:19:52但没关系。所以希望这部分说得通。我们有一个规划器。我们有三个执行器。这些执行器都在尝试执行这个计划。现在,
00:20:03这里发生的情况是,
00:20:05同样,
00:20:06他们在演讲中唯一给出的理由是这样更容易推理。这是唯一的信息。他们说这样更容易推理。因为这样更容易推理,
00:20:16这些执行器使用了序列化。所以它们不是直接尝试创建记录,
00:20:22如果记录已经存在就不创建或者类似的操作,
00:20:26换句话说,
00:20:27我有三个人在运行。
00:20:29我们都想创建,比如说这个顶层记录,plan146.ddb.aws,对吧?
00:20:36我们都在尝试做这件事。我们中的某个人先完成了。下一个人试图去做,
00:20:43但发现已经完成了或者诸如此类的情况,
00:20:47对吧?我们都在试图创建同一条记录。所以理论上,
00:20:51我们可以让三个人随机地敲打他们试图敲打的计划的任何部分,
00:20:57理论上这应该都能行得通,
00:21:00对吧?虽然演讲者没有明说,
00:21:02但我有点感觉到,
00:21:04我从演讲者那里得到的感觉是他会同意我刚才说的话,
00:21:09也就是说他们本可以让它们任意运行,
00:21:13这样应该是可以的。但是,
00:21:15他说,
00:21:16他们使用序列化来让推理变得更容易。这意味着这些执行器不是像那样随意敲打,
00:21:23而是尝试获取它们试图更新的任何端点的锁。换句话说,
00:21:29如果这个人试图更新其中一个东西,
00:21:32我的感觉是如果你试图更新这个,
00:21:35但也可能是如果你试图更新这个,
00:21:38或者可能两者都是。如果我没记错的话,
00:21:42他们从来没有真正100%说明锁定到底发生在哪里。但锁定的发生方式是他们说,
00:21:50好的,
00:21:50我要创建一个锁,
00:21:52这个锁是一条 DNS 记录。通过利用 Route 53 具有原子操作的概念,
00:22:00也就是说,
00:22:01你知道,
00:22:02我可以做两件事,
00:22:03如果它们不能都成功,
00:22:05那么它就一个都不做。
00:22:08他们基本上创建了一个通过 Route 53 锁定的锁定系统。所以 Route 53 的 DNS 记录实际上就是锁记录,
00:22:19如果这说得通的话。我能问个简单的问题吗?可以。你说它通过序列化来做这件事?我不太理解这是什么意思。因为我以为序列化只是从一种内存表示转换为另一种不同的内存表示。抱歉,
00:22:34是不同的序列化。所以是的,
00:22:36那也是序列化。在这种情况下,
00:22:39我们指的是字面意义上的时间序列化,
00:22:42意思是他们希望这些执行器有某种方式将它们的行为组织成一个顺序,
00:22:48而不是任意的。而他们这样做的方式就是锁定。所以会发生的情况是,
00:22:53这个人不是直接做它要做的事情,
00:22:56比如,
00:22:56好的,
00:22:57我完成了这个,
00:22:58我现在要把这个家伙指向计划 146。它不会那样做,
00:23:03而是尝试获取这个的锁,
00:23:05对吧?如果它没有获得锁,
00:23:07它就不会做出改变。所以在任何给定时间,
00:23:10这些执行器中只有一个可以处于更新这个的过程中。这样说得通吗?嗯哼。现在再说一次,
00:23:18他们试图用那个做什么从来没有解释过。他们只是说让推理变得更容易,
00:23:23然后就那样留着了。所以我不知道他们为什么认为这是一种改进。有趣的是,
00:23:29这正是最终发现 bug 的原因。所以这不是一种改进。如果说有什么的话,
00:23:36这可能还是坏事。但是 Casey,
00:23:39你是说他们没有,
00:23:40他们没有一个好的理由说我们要让执行器几乎像一次运行一个那样?他们为什么要有,
00:23:47为什么要有三个执行器?我不明白。比如,
00:23:51他们为什么不只有一个?他们就是没说这个。我们不知道为什么。而且他们也没有真正解释,
00:23:58比如,
00:23:58我没有真正听到关于你如何拥有三个并发执行器的解释。你预期它们可能会宕机,
00:24:05这就是为什么你有三个。
00:24:07对。但他们在获取锁。所以如果这个家伙获取了锁然后宕机了会怎么样?
00:24:13我的意思是,
00:24:15对于那个问题我也没听到解释。所以这整件事对我来说都很令人困惑。我,
00:24:21我,
00:24:21我并不是把它当作抱怨内容来说,
00:24:24因为它对我们讨论的核心问题并不重要。但作为一个技术演示,
00:24:30我有太多疑问了。我就像是,
00:24:32老实说我完全不明白你为什么要做这些事。对吧。也许,
00:24:37再说一遍,
00:24:38部分原因可能只是我不使用AWS服务。可能如果你是经常使用Route 53之类服务的人,
00:24:46有些事情会很明显,
00:24:48你会想,
00:24:48哦,
00:24:49是因为锁可以设置超时,
00:24:51或者我是说,
00:24:52我不知道。对吧。但不管怎样,
00:24:55是的,
00:24:55所以他们就在做那个。最后发生的事情是,
00:24:59对于这个暴露bug的情况,
00:25:02最终发生的是这些执行器,
00:25:04当它们获取不到锁时,
00:25:06就会进行退避,
00:25:07对吧?基本上就像是,
00:25:09好吧,
00:25:10让我等一下,
00:25:11然后再试一次。所以一个执行器,
00:25:14这个执行器尝试获取锁,
00:25:16但别人已经持有了锁。所以它就等一小会儿。它再次尝试获取锁。就是这样运作的。对吧。他们说发生的情况是遇到了一个所谓的病态案例,
00:25:27其中一个执行器已经执行了某个计划。而那个计划,
00:25:32假设说是相当旧的。我记得他们用110作为例子。所以它执行了计划110。它想要指向,
00:25:39你知道的,
00:25:40就像是,
00:25:41我得把API设置为指向我的110,
00:25:44尝试获取锁来更新dynamodb.use.one或者什么的,
00:25:50但失败了,
00:25:51因为别人正在执行计划111之类的。对吧。或者计划109可能是之前的计划。所以其他执行器在做这个。它做不了。它退避了。对吧。
00:26:02记住这个执行器,我们在110这里。它在尝试,它真的很想执行它。
00:26:07它又试了一次。别人持有锁。现在它再试一次,
00:26:11还是被锁着。这个执行器卡在110上,
00:26:14拼命想要执行。它做不到。显然这种情况发生了太多次,
00:26:18以至于其他执行器和规划器在这整个过程中一直在产出新计划。对吧。
00:26:23其他执行器,
00:26:24它们执行到了145或者146之类的,
00:26:28它们执行的计划比110领先太多了。对吧。而这个家伙仍然卡住了,
00:26:34因为它就是倒霉地一直获取不到锁。对吧。最后,
00:26:39在某个时刻,
00:26:40在计划145已经被某个其他执行器执行并指向之后,
00:26:45计划110,
00:26:46这个仍在尝试的执行器最终获得了锁。我是说,
00:26:50就像是,
00:26:51是的。然后它说,
00:26:53好吧,
00:26:53我们现在指向110了。没错。对吧。
00:26:58所以现在它指向一个超级旧的过期计划,但这真的不应该是个问题。对吧。
00:27:03因为最终下次某个执行器有任务时,会是一个更晚的计划。
00:27:07它们会直接执行计划,
00:27:09你知道,
00:27:09146或147或148之类的。然后我们会重新把它指向这个,
00:27:14我们就又回到新鲜的计划了。所以大家只会有几分钟的糟糕负载均衡,
00:27:18但之后就会好的。对吧。他们确实至少有几分钟的糟糕负载均衡。
00:27:22对。没错。嗯,比那糟糕得多。那是应该发生的情况。对吧。
00:27:30意思是他们也会期望是这样运作的。好吧。问题是,
00:27:35他们也不想让Route 53被所有这些记录堵塞。因为如果就这样放着不管,
00:27:43最终三个月后,
00:27:45你会有大约80亿条记录塞进Route 53,
00:27:49每隔几分钟你就往里面放这个大的权重树之类的东西。他们就想,
00:27:56好吧,
00:27:56在某个时候我们应该清理这些计划。
00:28:00所以执行器也会查找超过一定时长的计划。如果它们超过了一定时长,
00:28:06执行器就会删除它们。所以发生的情况是,
00:28:09它们指向了计划110。这个执行器最终获得了锁。它指向110。另一个执行器看到后就想,
00:28:17哦,
00:28:17天哪,
00:28:18110,
00:28:18太老了。我们应该把它删掉,
00:28:21然后就删除了它。所以现在DynamoDB us-east-1.api.aws指向的是一个无法解析的记录。对吧。这只是,
00:28:31实际上,
00:28:32它不会看起来像计划110。它会看起来像OAFE129A,
00:28:37某个哈希值,
00:28:38点,
00:28:39对吧,
00:28:39DDB.aws。但它指向的是那个名称。如果你查询那个名称,
00:28:45你什么也得不到。
00:28:46所以在那种情况下会发生的是,
00:28:48每个试图获取端点来发送数据的人都会得到一个基本上无法解析的名称。对吧。我真的不知道当这种情况发生时Route 53会发生什么,
00:28:59但你基本上会得到一些你要么无法使用的东西,
00:29:02要么就是乱七八糟的IP,
00:29:04谁知道呢。但无论是什么,
00:29:06如果你真的尝试使用它,
00:29:08你都不会得到响应。对吧。
00:29:10有意思。这是因为AWS没有使用足够的Rust吗?因为这显然是一个释放后使用的漏洞?所以我觉得Rust应该能解决这个问题,
00:29:20对吧?如果你用Rust完全重写Route 53,
00:29:25显然这些问题就都不存在了。不,
00:29:27具体来说,
00:29:28我确实认为在演示中,
00:29:30他们确实说了,
00:29:31不是关于Rust,
00:29:32但他们确实说了具体会发生什么,
00:29:35我记得当你请求这个东西或者这个东西或那个东西时,
00:29:39我不知道他们指的是哪一个,
00:29:41因为我记不太清了,
00:29:43你只会得到一个显示"未找到记录"的东西。所以这就是会发生的最终结果,
00:29:48无论是请求这个还是请求那个,
00:29:51我不确定,
00:29:52但就是会得到"未找到记录"。这就是你在尝试调用那个API时会收到的。所以无论你使用什么库来使用DynamoDB,
00:30:01它都会说,
00:30:02嘿,
00:30:02未找到记录,
00:30:03兄弟。抱歉。对吧。所以,
00:30:05如果你问互联网上的任何人,
00:30:08对吧,
00:30:08他们都会说,
00:30:09是的,
00:30:10他们解释了这个漏洞。这就是漏洞。漏洞就是存在这个竞态条件,
00:30:14对吧?每个人,
00:30:16因为每个人,
00:30:17一旦你说竞态条件,
00:30:18每个人的大脑就关闭了。他们会说,
00:30:21哦,
00:30:21好吧,
00:30:22这是一个竞态条件。完事了。没什么好看的,
00:30:25对吧?所以他们说,
00:30:27这是一个竞态条件。他们解释了。但实际上,
00:30:30不,
00:30:31他们没有解释。因为如果你想想这里会发生什么,
00:30:34在这之后,
00:30:35每个人都得到这个结果,
00:30:37会有一个新的执行器。一个新的执行器会直接执行一个新的,
00:30:42对吧?所以这个漏洞,
00:30:43对吧,
00:30:44就是为什么没有发生那种情况?这才是我想看到的真正的RCA(根本原因分析),
00:30:50为什么下一个执行器没有来修复它?我能提出别的吗?这不也是个漏洞吗?比如为什么要写一个如此老旧以至于应该立即删除的记录?嗯,
00:31:00这不是,
00:31:01是因为这家伙很久以前就写了它。而且它的权重。嗯,
00:31:05我是说,
00:31:06如果你问,
00:31:07为什么他们不用更好的代码编写执行器?是的,
00:31:10那挺酷的。
00:31:11好吧,
00:31:12有道理。感觉如果你要更新到一个应该立即被删除的东西,
00:31:16这不就像,
00:31:17这感觉就是问题所在。你早就做错了什么。是的,
00:31:21即使这实际上并没有真正修复这个东西的理论结构,
00:31:25这个家伙在锁上退避完成后做一个简单的检查,
00:31:29他也许应该检查一下他是否要把这个设置成如果他运行删除代码就会删除的东西,
00:31:36这可能是一个很好的安全措施。但是是的,
00:31:39所以100%同意他的观点。好吧,
00:31:42但执行器非常非常努力地获取那条记录。等了很长时间。哦,
00:31:47它要得到它的宝可梦卡片。
00:31:49曾经等待过的人。所以就让他写记录吧。好吧。所以,所以我想听听那个。
00:31:56不幸的是,如果你查看演示文稿和根因分析报告,你会发现这部分内容根本找不到。
00:32:03演示文稿中至少有一个12秒的小片段,
00:32:08大致说明了bug可能在哪里。让我来解释一下是怎么回事。显然在这个过程中,
00:32:19当你对DynamoDB us-east-1进行操作时,
00:32:27当你将它指向你的计划时,
00:32:30你会同时执行另一个操作。这个操作就是设置回滚记录。
00:32:40我想是DD开头的。是DDB.rollback.AWS吗?我记不清具体是什么了。
00:32:49有一个回滚记录。它会将该记录设置为旧计划的任何内容。所以如果我们之前指向145,
00:32:58现在要指向110,
00:33:01对吧,
00:33:01这个旧的执行器就像是在说「我要移动到110」,
00:33:07它会尝试设置,
00:33:08获取当前的名称,
00:33:10然后移动那个名称——也就是计划145——让回滚地址指向旧计划。
00:33:18对吧。这只是为了调试。或者说,基本上只是为了方便操作人员,对吧?
00:33:24如果他们想回滚到之前的计划或类似的操作,
00:33:28或者如果你只是想知道之前的计划是什么,
00:33:31你可以在这里看到,
00:33:33对吧?这是他们所说的故障模式的第一部分。我想指出一点,
00:33:38这对我来说也说不通。因为我在想,
00:33:41好吧,
00:33:41你告诉我这些东西大概每分钟更新一次。那有一个这样的记录有什么用?等你登录进去的时候,
00:33:48它已经从你想回滚到的那个版本更新到某个新版本了。那实际上是你不想要的计划,
00:33:55因为一切都崩溃了,
00:33:57对吧?就是这样,
00:33:58对吧?如果你不想要这个,
00:34:00你只需要把这些名称放在一个列表里。这样你就可以查「12点30分的时候是哪个版本?」就是那个,
00:34:08对吧?所以这对我来说毫无意义。我完全不明白为什么这样做会有好处,
00:34:14对吧?这听起来并不能实现你真正想要的功能,
00:34:18也就是能够标记一个时间点然后说,
00:34:20我们需要回到下午1点,
00:34:22因为那之后一切都乱套了,
00:34:24对吧?
00:34:26总之,
00:34:27这对我来说说不通。但同样,
00:34:29这跟bug没有直接关系。所以我没有追问为什么,
00:34:33我只是说,
00:34:34好吧,
00:34:34这就是它必须做的事情。你说的意思是它只能回滚一个版本。是的,
00:34:40尽管其他的树确实存在。所以只要知道名称,
00:34:43你完全可以做到。所以这一切只是在给你几乎肯定不关心的东西加上一个人类可读的名称。对吧。但他们真的,
00:34:51他们其实存储不了那么多东西。
00:34:54Casey,
00:34:55我不认为他们真的能,
00:34:56我不知道,
00:34:57Adam,
00:34:58就像这样,
00:34:59他们在那方面没有太大的规模,
00:35:02对吧?那会是很多行数据。如果是我,
00:35:04我会直接用时间戳。如果那是你想要的,
00:35:08对吧?我会说,
00:35:09计划程序什么时候,
00:35:10或者这个人什么时候指向这个东西?比如当你获得锁的时候,
00:35:15你把这个名称改成时间戳,
00:35:17然后在一次原子操作中更新它。这样你就知道如果我想回滚到下午1点,
00:35:22我只需要查找带有时间戳的,
00:35:25你知道的,
00:35:26最早的时间戳,
00:35:27不晚于那个时间。
00:35:28那就是我们当时运行的版本。这就是我会采用的做法。对吧。但我不知道。所以我完全不明白他们为什么这样做。他们做了他们所做的。我,
00:35:35你知道,
00:35:36也许这可能完全说得通。再次强调,
00:35:37我对他们的系统一无所知。所有这些事情,
00:35:40它们可能完全合理。
00:35:41所以我并不是真的,我只是说我不理解它们。我不认为它们一定是坏主意,对吧?
00:35:45如果你了解系统的其他部分,
00:35:47它们可能是好主意。所以总之,
00:35:50他们所说的,
00:35:51这就是我们得到的全部信息,
00:35:54就是这个操作,
00:35:55也就是设置回滚指向旧计划,
00:35:58你知道的,
00:35:59在这种情况下,
00:36:00在某些情况下实际上可能是更新的,
00:36:03对吧?所以它并不真的是之前指向的计划,
00:36:07可能更旧,
00:36:08也可能更新。执行那个活动。
00:36:11如果该计划不再存在,
00:36:13意味着它已被删除,
00:36:14就像这样,
00:36:15那么执行器就会永久停止。所以每次,
00:36:19就像一旦你进入 dynamodb.usc 是那个状态的时候,
00:36:25对吧?我们就会执行我们之前说的整个步骤序列。这个计划会被删除。
00:36:31所以现在这个指向了一个无效的、
00:36:33无法解析的名称,
00:36:34我们无法解析 plan plan-110,
00:36:37实际上是某个十六进制代码。但不管那是什么,
00:36:39我们现在都无法解析它了。
00:36:41一旦这个状态为真,
00:36:43下次执行器来尝试让它指向新计划时,
00:36:47无论那个新计划是什么,
00:36:50它都无法——当它真正执行到这一步并尝试设置回滚时,
00:36:56就会永久崩溃。因此,
00:36:59所有三个执行器现在都会停止,
00:37:02因为最终这三个都会尝试执行新计划。它们会先尝试设置回滚,
00:37:09让它指向旧计划是什么,
00:37:12然后发现那里没有计划。而这显然就是个硬崩溃。哦,
00:37:18太疯狂了。我原以为三个执行器的设计是为了提供冗余。再说一次,
00:37:25这就是为什么我对网上那些回复的人感到恼火。他们说,
00:37:32这是竞态条件。这不是竞态条件。竞态条件对此并非必要。竞态条件只是导致你最终得到这个无法解析的名称的原因。但如果你没有任何代码写得这么糟糕,
00:37:49它本来就能正常工作。
00:37:52你永远不会知道。你可能会有一分钟的 DynamoDB 短暂中断或类似情况,
00:37:58但我猜 DynamoDB 时不时会有一分钟的中断。这不是全球新闻。
00:38:04真正成为全球新闻的是永久性地让它宕机,
00:38:07这就是这里发生的情况。直到真正的人介入并弄清楚这一切,
00:38:12重置它,
00:38:13让这些执行器重新运行,
00:38:14它就是不可用的。它就是永久性地停摆了。所以可能是几个小时。而且在这个案例中,
00:38:21时间长到足以引发级联故障。你本来不会遇到那种情况。这只是短暂的中断。如果有些人短暂地得到了无法解析的名称或没有记录,
00:38:30他们只会重试。通常对于 DNS 来说,
00:38:34就像你的手机穿过隧道一样。本来就只会是这样。
00:38:37所以我想知道这里的代码是什么样的?你是怎么写出这样的东西的——如果这不是一个有效的名称,
00:38:46即使在启动时也不会是,
00:38:48意味着如果你启动这个系统而操作员没有预先配置它,
00:38:53它不会指向任何东西。这是你认为会从默认情况开始的。所以如果你要这样做,
00:39:00你会认为你只需要处理那种情况,
00:39:03因为回滚地址可能根本不指向任何东西。就把这个是什么都拿来。如果它是空的,
00:39:10就把回滚地址设为空。
00:39:12完成。所以他们编写这段代码的方式真的很奇怪。而这才应该是 RCA 中应有的内容。对我来说这才是整个 bug。这只是我们最终让这个东西指向空的场景布置。如果有人不小心删除了这条记录,
00:39:28同样的 bug 也会发生。就像某个操作员只是说,
00:39:33哎呀,
00:39:33糟糕,
00:39:34我把它设成空了。
00:39:35根据这个演示,
00:39:36同样的 bug 也会发生。所以根本原因不是竞态条件。竞态条件只是个旁支。这样说有道理吗?快速问个问题。我正认真思考这个问题。这意味着设置回滚的那个东西可能假设传入了某种带有一堆内存或什么的结构体,
00:39:54做了某种访问。然后它就炸了。或者你认为这是同一种类型的 bug,
00:40:00就是让 Cloudflare 宕机的那一行代码,
00:40:04他们只是假设它在那里然后解包它。
00:40:07这是用 Rust 写的。是内存安全的 Rust。解包它,然后炸了。
00:40:13我真的不知道。我猜测,
00:40:15就像在我脑海中,
00:40:16我在想,
00:40:17我看到人们经常做的什么事情是我总是会想,
00:40:20你为什么要这样做?但这只是因为这是他们学习编程的方式。我在想,
00:40:26如果你用的是那些喜欢为错误条件抛出异常的语言之一,
00:40:31这将是一个很好的例子。所以如果你有这样一种情况,
00:40:35你会想,
00:40:36哦,
00:40:36我去获取这个东西指向的 DNS 记录。
00:40:40而在正常的健全编程环境中,
00:40:43没有人会在那里抛出异常。如果他们什么都没得到,
00:40:46他们只是返回空值。然后当这个人去设置 ddb.robot.js 时,
00:40:52他们就把它设置为空值,
00:40:54这才是正确的行为。就像空值流动,
00:40:56字面意义上的空值在这个流程中正确地流动。所以如果你在编写时考虑到,
00:41:01既然它是一个核心基础服务,
00:41:04假设你试图编写具有容错能力的东西,
00:41:06你永远不会做像抛出异常这样的事情。所以在我的脑海中,
00:41:10我在想,
00:41:11我敢打赌这里发生的是,
00:41:13当你请求这个记录时,
00:41:14他们只是使用了某个库调用或什么东西,
00:41:17当记录不存在时会抛出异常。它就抛出了异常,
00:41:21然后 actor 就结束了。这是我的猜测。我可能完全错了,
00:41:25因为我只是瞎猜。但这就是为什么我想看 RCA。是什么?它可能正是 Trash 所说的那些东西。我的意思是,
00:41:34它可能是 Prime 所说的东西。可能是我刚才说的东西。可能是任何东西。我想知道,
00:41:41因为那才是这里真正的教育所在。避免这种竞态条件完全不重要。这个竞态条件可能一直存在那里。虽然最终修复它很重要,
00:41:50以避免每年一次持续五秒钟左右的奇怪中断,
00:41:53但它实际上不是我们最想学习的东西。我们最想学习的是不要写这种东西。而我们甚至不知道这种东西是什么。那我们怎么不写它呢?这就是为什么我认为这是一个糟糕的 RCA。这有道理吗?有。有。好的。AWS 大部分是用什么写的,
00:42:10Adam?
00:42:11是 Java。我正要说聊天中有人说是 Scala。他们说他们在 AWS 工作了七年,
00:42:19他们说大部分是用 Scala 写的。嗯,
00:42:23从技术上讲那就是多了几步的 Java。这会让他们所有人无休止地生气。所以对我来说就是这样了。
00:42:34这件事让我觉得,
00:42:35我好像没看到解释。而且我实际上觉得听到这个很重要,
00:42:39因为在这个夏天的底层有一个糟糕的编程实践。我想知道它是什么,
00:42:44特别是因为它对像我这样的人有帮助,
00:42:47当我,
00:42:47你知道,
00:42:48我现在并不真正做很多架构教育,
00:42:51但在某个时候我可能想做一些,
00:42:53因为我认为外面有很多糟糕的架构。所以我会试着关注这些事情。比如人们在犯什么样的架构错误?我敢打赌这就是其中之一。对吧。所以我想知道。我想知道。
00:43:04是的。我觉得我至少期望能有一个简单的可复现示例,
00:43:09说明为什么它会炸掉,
00:43:10就像一小段代码片段。这也是你之前提到的,
00:43:14就是我们如何处理这类事情。如果我在审查别人的代码时看到一些奇怪的东西,
00:43:20我总会尽力建一个自己的沙盒环境,
00:43:23验证我的理论。然后实际向他们展示代码,
00:43:27告诉他们这可能就是问题所在,
00:43:29这里有一个简单的可复现步骤。这也能帮我真正理解。因为很多人,
00:43:35就像你说的,
00:43:36会看到某些看起来不对劲的东西,
00:43:38但不知道为什么不对劲,
00:43:40但我不能就此止步。我必须真正把它构建出来,
00:43:44然后理解它。所以这就是我的期望。而且你知道,
00:43:48就像我说的,
00:43:49CrowdStrike 和 Google 的故障报告就做得更好,
00:43:55他们会直接告诉你,
00:43:56看,
00:43:57这是一个空指针解引用,
00:43:59或者是数组越界,
00:44:00因为我们以为只会有 20 个,
00:44:03结果配置文件里放了 21 个。这样我就确切知道是什么样的代码导致了这种问题。而且,
00:44:10进一步说,
00:44:11回到之前的评论,
00:44:13据我所知,
00:44:14所有用 Rust 编程的人之所以用它,
00:44:17就是为了偶尔在看到这种事情时能说一句:"嘿,
00:44:21如果他们用 Rust 写的话,
00:44:24就不会发生这种事了。" 但他们甚至没有得到足够的信息来发表这个评论。
00:44:29公平地说,
00:44:30他们可能还是会这么说,
00:44:32但确实没有得到足够信息。所以 RCA(根因分析)应该遵循的一条规则是:你必须给 Rust 信徒提供足够的信息,
00:44:40让他们在愿意的情况下,
00:44:42能够正确地说出这在 Rust 中是可以被预防的。
00:44:46而这次,我们没有这些信息。我们不知道这在 Rust 中是否能被预防。
00:44:51我们完全不知道。可能不会,
00:44:54但我们不清楚。不过 Casey,
00:44:57我们确实有很大概率,
00:44:58因为它可能根本就发布不出来。所以这样就预防了。
00:45:03没错。我们会有零个制定者,因为我们会一直在设计制定者。是的。
00:45:09CloudFlare 在这方面做得真的很好。他们会深入展示大量代码行,
00:45:16说这就是到底发生了什么,
00:45:18即使问题在上面,
00:45:19这就是由于之前所有这些条件而炸掉的那一行。那是我在拿 Rust 的 unwrap 开玩笑,
00:45:27虽然它实际上并不是真正的问题。但你知道,
00:45:31就是所有这些事情凑在一起发生了。所以他们做得非常好。我很惊讶 AWS 这次做得这么差劲。而且另一件事是,
00:45:40现在这让我对你产生了不必要的怀疑,
00:45:43对吧?
00:45:44当我读到这个的时候,
00:45:45我就在想,
00:45:46你是在隐瞒什么吗?你真的没弄清楚bug是什么吗?你讲了一大堆关于竞态条件的事,
00:45:51但即使从你自己的描述来看,
00:45:53我也能看出竞态条件其实并不重要。那只是导致记录被设置为空的原因,
00:45:58但谁在乎呢,
00:45:58对吧?这种东西适合放在RCA里作为解释,
00:46:01说明为什么这个bug现在出现,
00:46:03而不是在其他时候出现,
00:46:05但这不是bug本身。所以我觉得很奇怪。当我看到一份RCA没有讨论bug本身时,
00:46:10我就会起疑心。对吧。而且这种怀疑是不必要的,
00:46:13因为如果你真的找到了bug,
00:46:15那就直接告诉我,
00:46:16这样我就知道你找到了。对吧。所以我认为这对那些从外部观察、
00:46:20想知道他们能否信任DynamoDB这个东西的人来说,
00:46:24也是一种信心提升。如果看起来你真的找到了bug,
00:46:27我会对你更有信心。如果看起来你根本不知道bug是什么,
00:46:31或者似乎不理解bug是什么,
00:46:33那我就更担心了。所以我认为这也是在RCA中做到这一点的另一个理由。
00:46:37它能给你的客户提供信心。也许这也是他们把Adam的AWS英雄头衔撤掉的原因。
00:46:43也许这一切都是有关联的。有可能。他们不想让他揭露这些不可告人的秘密。
00:46:48是啊。他知道得太多了。他知道得太多了。你能不能简单用三分钟总结一下吉他店的事?就是那个事件揭示了什么?因为我在努力回忆那是什么,
00:46:59因为它涉及到一个单点故障的人,
00:47:02而这次故障他也不在现场。所以我不知道怎么把这两件事联系起来。当然我们也完全不知道。我们完全不知道他们中的任何一个是否在告诉我们真相,
00:47:13对吧?因为这份RCA太糟糕了,
00:47:16我都不知道它是否正确,
00:47:18但对,
00:47:18密码是wishbone 12,
00:47:21我记得是这样。
00:47:22没错。总是想弄死我。反正我是这么记得的。
00:47:26对,
00:47:27那个故事是说,
00:47:28有一个设计用来复制配置的东西。而那个东西已经失控了,
00:47:35无法停止。就像,
00:47:37它只是在完全错误地复制配置,
00:47:40需要被修复或修理什么的。我们没有更多信息,
00:47:45因为这是无意中听到的对话。对吧。那么这和现在的情况吻合吗?嗯,
00:47:53有一点,
00:47:54因为那些执行器确实听起来像是会运行配置复制的那种东西,
00:48:00但另一方面,
00:48:01这并不真的是机器的配置。DNS条目就是DNS条目。它不是,
00:48:08不是真正的配置。所以我会说这两个故事对不太上。
00:48:14所以这也是我有点希望这份RCA更可信一点的另一个原因,
00:48:19因为我想确切地知道那个故事是假的。而基于这份RCA有多糟糕,
00:48:25我仍然不太确定。如果,
00:48:27如果那个人写的用来复制配置的工具就是字面意义上的执行器呢?就像他们把它产品化了,
00:48:34而且他们七年来都没改过。这是我连点成线的理解。他就像在说,
00:48:40伙计们,
00:48:41我写那个是为了让我在本地环境测试东西。而你们竟然决定做三个执行器,
00:48:47把它们并排放在生产环境。我不明白,
00:48:50这是怎么发生的?我不明白。
00:48:53我还有其他的疑问。是的。或者说,
00:48:55会不会是回滚操作出了问题?因为那个操作是负责复制的,
00:48:59比如"嘿,
00:49:00这是之前的版本。"对吧。然后它会复制之前的版本。接着就出现了这个空值问题。然后脚本就像从未遇到过这种情况,
00:49:09或者知识库直接失控了,
00:49:11开始一遍又一遍地反复写入,
00:49:13写到你完全无法操作的地步。我不知道。我只知道,
00:49:16就我从他们的解释中所了解到的,
00:49:19仅凭他们提供的信息来看,
00:49:21我仍然认为竞态条件根本不相关,
00:49:23因为再说一遍,
00:49:24字面意义上对 Route 53 端点的一次意外更新就能立即让所有三个执行器全部下线。因为根据他们的说法,
00:49:32要让它们停止运行只需要一个条件:如果端点指向一个无法解析的名称,
00:49:38仅此而已。所以如果这是真的,
00:49:40字面意义上一个操作员的输入错误就能让整个系统崩溃,
00:49:44根本不需要什么竞态条件。对吧。所以再说一次,
00:49:47这份 RCA 报告根本没能说服我你们真正讨论了真正的 bug 是什么,
00:49:53因为我能想到很多方法可以触发完全相同的问题,
00:49:56而这些方法都不涉及你们在整个 RCA 报告中告诉我的那个竞态条件,
00:50:02但我不认为那才是真正的 bug。所以谢谢你,
00:50:05Casey,
00:50:06为我们带来了这么精彩的演示。说实话,
00:50:09我真的非常嫉妒你那个书写工具。我得弄清楚怎么设置成你那样。那东西太棒了。
00:50:15感谢大家收看。对于那些看了直播的观众,
00:50:17希望你们喜欢开场前的闲聊,
00:50:19可能还有结束后的闲聊。如果你想听完整版以及所有那些不属于主要内容的有趣互动,
00:50:23请前往 Spotify 收听完整播客,
00:50:26那里就是我们闲扯各种话题,
00:50:28我也不知道 Trash 在吃什么零食之类的,
00:50:30节目名叫 More Yapping,
00:50:33More Yapping Again,
00:50:35还有 Casey、
00:50:36TJ 和 Trash。
00:50:42屏幕上的报错,终端里的咖啡,活在梦想里。