追踪 Discord 的 Elixir 系统(不把所有东西都熔化)
Source: Discord Engineering
背景
在 Discord,我们的目标是让聊天、表情和 meme 发布感觉瞬间完成。我们通过利用 Elixir 强大的并发机制,使每个 Discord 服务器(即“公会”)能够完全独立运行,从而在大规模下实现这一点。
可观测性工作流
当一个公会跟不上用户活动时,可能会出现卡顿或完整的宕机。如果系统的退化程度超过了自我修复的能力,值班工程师会介入并使用我们的可观测性工具来了解原因并防止再次发生。
调查从查看指标和日志开始。我们对大量度量进行仪表化,包括每种用户操作类型的处理频率以及处理耗时。这些指标常常揭示出突发的活动——比如新发布游戏的热潮和大量表情——但它们并不能完整捕捉用户体验。这类似于汽车仪表盘:它可以告诉你发动机温度,但不能说明发动机过热的后果。
公会计时
如果指标没有给出结果,值班工程师会转向我们自研的工具 guild timings。每当公会处理一次操作时,它会记录当前分钟内在每种操作类型上花费的时间,并存入内存存储。该数据比我们的指标详细得多,但其产生的量极大,以至于我们无法全部存储。因此,除最大公会外,数据会被频繁轮转。即使及时检索,这些数据仍然无法提供端到端体验的完整图景,因为它们未捕获下游影响。
分布式追踪
Discord 的其他团队已经从使用分布式追踪(应用性能监控)中获得了巨大的价值,分布式追踪能够展示一次操作的每个组成部分耗时。将追踪加入我们的 Elixir 堆栈需要额外的工作。大多数追踪工具通过元数据层(如 HTTP 头)传播操作信息,但 Elixir 的内置通信工具默认并不具备等价的层。
实现
我们自行构建了一个追踪层,用于在服务之间传播元数据。尽管这改变了服务之间的通信方式,但我们在不产生停机的情况下完成了集成。