Bioyino - 分布式、可扩展的指标聚合器

所以你收集指标。 正如我们一样。 我们还收集指标。 当然是做生意所必需的。 今天我们要讲的是我们监控系统的第一个环节——兼容statsd的聚合服务器 生物伊诺,我们为什么写它以及为什么我们放弃布鲁贝克。

Bioyino - 分布式、可扩展的指标聚合器

从我们之前的文章(1, 2)您可以发现,直到某个时候我们使用以下方式收集分数 布鲁贝克。 它是用 C 语言编写的。从代码的角度来看,它就像一个插件一样简单(当您想要做出贡献时,这一点很重要),最重要的是,它可以在峰值时处理每秒 2 万个指标 (MPS) 的数据量没有任何问题。 该文档声明支持 4 万 MPS,并带有星号。 这意味着如果您在 Linux 上正确配置网络,您将获得所述数字。 (我们不知道如果您保持网络不变,您可以获得多少 MPS)。 尽管有这些优点,我们对布鲁贝克还是有一些严重的抱怨。

权利要求1。 该项目的开发者 Github 停止了支持:发布补丁和修复程序,接受我们的和(不仅仅是我们的)PR。 在过去几个月(2018 年 2 月至 XNUMX 月),活动已恢复,但在此之前有近两年的完全平静。 此外,该项目正在开发中 满足 Gihub 内部需求,这可能成为引入新功能的严重障碍。

权利要求2。 计算的准确性。 Brubeck总共收集了65536个值进行聚合。 在我们的例子中,对于某些指标,在聚合期间(30秒),可能会到达更多的值(峰值为1)。 这次采样的结果是,最大值和最小值显得毫无用处。 例如,像这样:

Bioyino - 分布式、可扩展的指标聚合器
怎么样

Bioyino - 分布式、可扩展的指标聚合器
本来应该怎样

出于同样的原因,金额通常计算不正确。 在这里添加一个带有 32 位浮点溢出的 bug,当接收到看似无辜的指标时,它通常会将服务器发送到段错误,然后一切都会变得很好。 顺便说一句,该错误尚未修复。

最后, 索赔X。 在撰写本文时,我们已准备好将其呈现给我们能够找到的所有 14 个或多或少有效的 statsd 实现。 让我们想象一下,某些单一基础设施已经发展得如此之快,以至于接受 4 万 MPS 已经不够了。 或者,即使它还没有增长,但这些指标对你来说已经如此重要,即使是图表中短暂的 2-3 分钟的下降也可能变得至关重要,并导致经理们陷入难以克服的抑郁情绪。 由于治疗抑郁症是一项吃力不讨好的任务,因此需要技术解决方案。

首先是容错,这样服务器突然出现的问题不会导致办公室出现精神病僵尸大灾难。 其次,扩展至能够接受超过 4 万 MPS,无需深入挖掘 Linux 网络堆栈并平静地“广度”增长到所需的大小。

由于我们有扩展空间,因此我们决定从容错开始。 “关于! 容错! 很简单,我们能做到。”我们这样想并启动了 2 台服务器,在每台服务器上提供了一份 brubeck 副本。 为此,我们必须将带有指标的流量复制到两台服务器,甚至为此编写 小实用程序。 我们用这个解决了容错问题,但是......不是很好。 起初一切看起来都很棒:每个 brubeck 收集自己版本的聚合,每 30 秒将数据写入 Graphite 一次,覆盖旧的间隔(这是在 Graphite 端完成的)。 如果一台服务器突然发生故障,我们总会有第二台服务器拥有自己的聚合数据副本。 但问题是:如果服务器出现故障,图表上就会出现“锯子”。 这是因为 brubeck 的 30 秒间隔不同步,并且在崩溃时其中一个间隔不会被覆盖。 当第二个服务器启动时,也会发生同样的事情。 相当可以忍受,但我想要更好! 可扩展性问题也没有消失。 所有指标仍然“飞行”到单个服务器,因此我们仅限于相同的 2-4 百万 MPS,具体取决于网络级别。

如果你稍微思考一下这个问题,同时用铲子挖雪,那么你可能会想到以下明显的想法:你需要一个可以在分布式模式下工作的 statsd。 即实现节点之间在时间和指标上的同步。 “当然,这样的解决方案可能已经存在,”我们说,然后去了谷歌...... 他们什么也没找到。 在浏览了不同 statsd 的文档后(https://github.com/etsy/statsd/wiki#server-implementations 截至11.12.2017年XNUMX月XNUMX日),我们什么也没发现。 显然,这些解决方案的开发人员和用户都还没有遇到过这么多指标,否则他们肯定会想出一些东西。

然后我们想起了在 Just for Fun 黑客马拉松上编写的“玩具”statsd - Bioyino(项目名称是在黑客马拉松开始前由脚本生成的),并意识到我们迫切需要自己的 statsd。 为了什么?

  • 因为世界上的 statsd 克隆太少了,
  • 因为可以提供期望的或接近期望的容错性和可扩展性(包括同步服务器之间的聚合指标并解决发送冲突的问题),
  • 因为可以比 brubeck 更准确地计算指标,
  • 因为你可以自己收集更详细的统计数据,而布鲁贝克实际上没有向我们提供这些数据,
  • 因为我有机会编写自己的超高性能分布式规模实验室应用程序,该应用程序不会完全重复另一个类似的超高性能的架构......好吧,就是这样。

写什么? 当然,在 Rust 中。 为什么?

  • 因为已经有了原型解决方案,
  • 因为文章的作者当时已经了解 Rust,并渴望在其中写一些东西用于生产,并有机会将其开源,
  • 因为由于接收到的流量的性质(几乎实时),带有 GC 的语言不适合我们,并且 GC 暂停实际上是不可接受的,
  • 因为您需要与 C 相当的最大性能
  • 因为 Rust 为我们提供了无所畏惧的并发性,如果我们开始用 C/C++ 编写它,我们会比 brubeck 遇到更多的漏洞、缓冲区溢出、竞争条件和其他可怕的词语。

还有一个反对 Rust 的争论。 该公司没有使用 Rust 创建项目的经验,现在我们也不打算在主项目中使用它。 因此,我们非常担心一切都不会成功,但我们决定冒险尝试一下。

时间飞逝...

最后,经过几次失败的尝试,第一个工作版本准备好了。 发生了什么? 这就是发生的事情。

Bioyino - 分布式、可扩展的指标聚合器

每个节点接收自己的指标集并累积它们,并且不会聚合最终聚合需要完整集合的那些类型的指标。 这些节点通过某种分布式锁协议相互连接,该协议允许您在其中选择唯一一个(我们在这里哭了)值得向伟大的节点发送指标的节点。 这个问题目前正在解决 领事,但未来作者的野心延伸到 自己 履行 Raft,其中最有价值的当然是共识领导节点。 除了共识之外,节点经常(默认情况下每秒一次)向其邻居发送它们在那一秒设法收集的预聚合指标的那些部分。 事实证明,扩展性和容错性得到了保留——每个节点仍然拥有一整套指标,但这些指标已经通过 TCP 聚合发送并编码成二进制协议,因此与 UDP 相比,重复成本显着降低。 尽管传入的指标数量相当大,但累积需要的内存非常少,甚至需要更少的 CPU。 对于我们高度可压缩的指标来说,这只是几十兆字节的数据。 作为额外的好处,我们在 Graphite 中不会像 burbeck 那样进行不必要的数据重写。

具有度量的UDP数据包通过简单的循环在网络设备上的节点之间不平衡。 当然,网络硬件不会解析数据包的内容,因此每秒可以拉取超过 4M 的数据包,更不用说它根本不知道的指标了。 如果我们考虑到指标并不是在每个数据包中一次出现一个,那么我们不会预见到这个地方会出现任何性能问题。 如果服务器崩溃,网络设备会快速(1-2 秒内)检测到这一事实,并将崩溃的服务器从轮换中删除。 因此,被动(即非领导者)节点实际上可以打开和关闭,而不会注意到图表上的下降。 我们损失的最大值是最后一秒传入的指标的一部分。 领导者的突然丢失/关闭/切换仍然会造成轻微异常(30秒间隔仍然不同步),但是如果节点之间存在通信,则可以将这些问题最小化,例如通过发送同步数据包。

关于内部结构的一些信息。 当然,该应用程序是多线程的,但线程架构与 brubeck 中使用的不同。 brubeck 中的线程是相同的 - 每个线程都负责信息收集和聚合。 在bioyino中,工作人员分为两类:负责网络的人员和负责聚合的人员。 这种划分可以让您根据指标类型更灵活地管理应用程序:在需要密集聚合的地方,可以添加聚合器,在网络流量较大的地方,可以添加网络流量的数量。 目前,我们的服务器在 8 个网络和 4 个聚合流中工作。

计数(负责聚合)部分非常无聊。 网络流填充的缓冲区分布在计数流中,随后在计数流中进行解析和聚合。 根据请求,给出发送到其他节点的指标。 所有这些,包括在节点之间发送数据以及与 Consul 一起工作,都是异步执行的,在框架上运行 东京.

开发过程中的更多问题是由负责接收指标的网络部分引起的。 将网络流分成单独的实体的主要目标是希望减少流花费的时间 没有 从套接字读取数据。 使用异步UDP和常规recvmsg的选项很快就消失了:第一个消耗太多的用户空间CPU用于事件处理,第二个需要太多的上下文切换。 因此现在使用 收据 有很大的缓冲区(先生们,缓冲区对你们来说没什么!)。 对常规 UDP 的支持保留用于不需要 recvmmsg 的轻型情况。 在多消息模式下,可以实现主要的事情:绝大多数时间,网络线程抓取操作系统队列 - 从套接字读取数据并将其传输到用户空间缓冲区,只是偶尔切换到将已填充的缓冲区提供给聚合器。 套接字中的队列实际上不会累积,丢弃的数据包数量实际上不会增加​​。

注意

在默认设置中,缓冲区大小设置得相当大。 如果您突然决定自己尝试该服务器,您可能会遇到这样的情况:发送少量指标后,它们将不会到达 Graphite,而是保留在网络流缓冲区中。 要使用少量指标,您需要在配置中将 bufsize 和 task-queue-size 设置为较小的值。

最后,为图表爱好者提供一些图表。

统计每台服务器传入的metrics数量:超过2万MPS。

Bioyino - 分布式、可扩展的指标聚合器

禁用节点之一并重新分配传入指标。

Bioyino - 分布式、可扩展的指标聚合器

传出指标统计:只有一个节点总是发送——raid boss。

Bioyino - 分布式、可扩展的指标聚合器

统计每个节点的运行情况,考虑到各个系统模块的错误。

Bioyino - 分布式、可扩展的指标聚合器

传入指标的详细信息(隐藏指标名称)。

Bioyino - 分布式、可扩展的指标聚合器

接下来我们打算如何处理这一切? 当然是写代码啦,妈的……! 该项目最初计划是开源的,并将在其整个生命周期中保持如此。 我们近期的计划包括切换到我们自己的 Raft 版本、将对等协议更改为更便携的协议、引入额外的内部统计数据、新类型的指标、错误修复和其他改进。

当然,欢迎大家为项目的开发提供帮助:创建 PR、Issue,如果可能的话我们会回应、改进等。

话虽这么说,那就是了,伙计们,买我们的大象吧!



来源: habr.com

添加评论