指标存储:我们如何从 Graphite+Whisper 切换到 Graphite+ClickHouse

大家好! 在他的 上一篇文章 我写了一篇关于为微服务架构组织模块化监控系统的文章。 没有什么是静止的,我们的项目在不断增长,存储的指标数量也在不断增长。 我们如何在高负载条件下组织从 Graphite+Whisper 到 Graphite+ClickHouse 的过渡,了解其期望以及削减后的迁移结果。

指标存储:我们如何从 Graphite+Whisper 切换到 Graphite+ClickHouse

在我告诉您我们如何组织从在 Graphite+Whisper 中存储指标到 Graphite+ClickHouse 的过渡之前,我想先介绍一下做出这样的决定的原因以及我们长期以来一直忍受的 Whisper 的缺点。

石墨+耳语问题

1. 磁盘子系统负载过高

在过渡时,每分钟大约有 1.5 万个指标到达我们。 在这样的流程下,服务器上的磁盘利用率约为 30%。 总的来说,这是完全可以接受的 - 一切都运行稳定,写入速度快,读取速度快......直到其中一个开发团队推出了一项新功能并开始每分钟向我们发送 10 万个指标。 就在那时,磁盘子系统收紧了,我们看到了 100% 的利用率。 问题很快就得到了解决,但仍有残留。

2. 缺乏复制性和一致性

最有可能的是,就像每个使用 Graphite+Whisper 的人一样,我们将相同的指标流同时倒入多个 Graphite 服务器上,以创建容错能力。 这并没有什么特别的问题 - 直到其中一台服务器由于某种原因崩溃的那一刻。 有时我们设法足够快地恢复掉下的服务器,并且carbon-c-relay设法将其缓存中的指标加载到其中,但有时却不能。 然后指标中出现了一个漏洞,我们用 rsync 填补了这个漏洞。 整个过程相当漫长。 唯一可取之处是这种情况很少发生。 我们还定期获取一组随机指标,并将它们与集群相邻节点上相同类型的其他指标进行比较。 在大约 5% 的情况下,几个值是不同的,我们对此不太满意。

3、占地面积大

由于我们不仅用 Graphite 编写基础设施,还用 Graphite 编写业务指标(现在还包括来自 Kubernetes 的指标),因此我们经常会遇到这样的情况:指标仅包含几个值,而创建 .wsp 文件时考虑了所有保留期间,并占用预先分配的空间量,对我们来说约为 2MB。 随着时间的推移,出现大量类似的文件,并且在基于这些文件构建报告时,读取空点需要花费大量时间和资源,这一事实进一步加剧了该问题。

我想立即指出,上述问题可以使用各种方法来处理,并具有不同程度的有效性,但是您开始收到的数据越多,问题就越严重。

具备上述所有条件(考虑到之前的 文章),以及接收到的指标数量不断增加,希望将所有指标传输到 30 秒的存储间隔。 (如有必要,最多 10 秒),我们决定尝试 Graphite+ClickHouse 作为 Whisper 的有前途的替代方案。

石墨+ClickHouse。 期望

参观过 Yandex 人员的几次聚会,阅读过 几篇关于哈布雷的文章,在浏览了文档并找到了在 Graphite 下绑定 ClickHouse 的合理组件后,我们决定采取行动!

我希望收到以下信息:

  • 将磁盘子系统利用率从 30% 降低至 5%;
  • 将占用空间从 1TB 减少到 100GB;
  • 能够每分钟将 100 亿个指标接收到服务器中;
  • 开箱即用的数据复制和容错;
  • 不要在这个项目上等待一年并在合理的时间内完成过渡;
  • 无需停机即可切换。

相当雄心勃勃,对吧?

石墨+ClickHouse。 成分

为了通过 Graphite 协议接收数据并随后将其记录在 ClickHouse 中,我选择了 碳点击屋 (戈兰)。

选择ClickHouse的最新版本,稳定版本1.1.54253作为存储时间序列的数据库。 使用它时遇到了问题:大量错误涌入日志中,并且不完全清楚如何处理它们。 正在讨论中 罗蒙诺索夫 (carbon-clickhouse、graphite-clickhouse 等等的作者)选择了较旧的 发布1.1.54236。 错误消失了——一切都开始顺利进行。

选择从ClickHouse读取数据 石墨-Clickhouse (戈兰)。 作为 Graphite 的 API - 碳API (戈兰)。 ClickHouse用于组织表之间的复制 动物园管理员。 对于路由指标,我们留下了我们心爱的人 carbon-c-继电器 (C) (见上一篇文章).

石墨+ClickHouse。 表结构

“graphite”是我们为监控表创建的数据库。

“graphite.metrics” - 具有 ReplicatedReplacingMergeTree 引擎的表(复制 替换MergeTree)。 该表存储指标的名称及其路径。

CREATE TABLE graphite.metrics ( Date Date, Level UInt32, Path String, Deleted UInt8, Version UInt32 ) ENGINE = ReplicatedReplacingMergeTree('/clickhouse/tables/replicator/graphite.metrics', ‘r1’, Date, (Level, Path), 8192, Version);

“graphite.data” - 具有 ReplicatedGraphiteMergeTree 引擎的表(复制 石墨合并树)。 该表存储度量值。

CREATE TABLE graphite.data ( Path String, Value Float64, Time UInt32, Date Date, Timestamp UInt32 ) ENGINE = ReplicatedGraphiteMergeTree('/clickhouse/tables/replicator/graphite.data', 'r1', Date, (Path, Time), 8192, 'graphite_rollup')

“graphite.date_metrics”是一个使用 ReplicatedReplacingMergeTree 引擎进行条件填充的表。 该表记录了当天遇到的所有指标的名称。 创建它的原因在章节中描述 “问题” 在这篇文章的最后。

CREATE MATERIALIZED VIEW graphite.date_metrics ( Path String,  Level UInt32,  Date Date) ENGINE = ReplicatedReplacingMergeTree('/clickhouse/tables/replicator/graphite.date_metrics', 'r1', Date, (Level, Path, Date), 8192) AS SELECT toUInt32(length(splitByChar('.', Path))) AS Level, Date, Path FROM graphite.data

“graphite.data_stat” - 根据条件填充的表,使用 ReplicatedAggregatingMergeTree 引擎(复制 聚合合并树)。 该表记录传入指标的数量,分为 4 个嵌套级别。

CREATE MATERIALIZED VIEW graphite.data_stat ( Date Date,  Prefix String,  Timestamp UInt32,  Count AggregateFunction(count)) ENGINE = ReplicatedAggregatingMergeTree('/clickhouse/tables/replicator/graphite.data_stat', 'r1', Date, (Timestamp, Prefix), 8192) AS SELECT toStartOfMonth(now()) AS Date, replaceRegexpOne(Path, '^([^.]+.[^.]+.[^.]+).*$', '1') AS Prefix, toUInt32(toStartOfMinute(toDateTime(Timestamp))) AS Timestamp, countState() AS Count FROM graphite.data  GROUP BY Timestamp, Prefix

石墨+ClickHouse。 组件交互图

指标存储:我们如何从 Graphite+Whisper 切换到 Graphite+ClickHouse

石墨+ClickHouse。 数据迁移

正如我们对这个项目的期望所记得的那样,向 ClickHouse 的过渡应该不会出现停机;因此,我们必须以某种方式将整个监控系统切换到新的存储,对用户来说尽可能透明。
我们就是这样做的。

  • Carbon-c-relay 中添加了一条规则,用于将额外的指标流发送到参与 ClickHouse 表复制的服务器之一的 Carbon-Clickhouse。

  • 我们用 python 编写了一个小脚本,它使用 Whisper-dump 库从我们的存储中读取所有 .wsp 文件,并通过 24 个线程将该数据发送到上述的carbon-clickhouse。 Carbon-Clickhouse 中接受的指标值数量达到了 125 亿/分钟,ClickHouse 甚至不费吹灰之力。

  • 我们在 Grafana 中创建了一个单独的数据源来调试现有仪表板中使用的功能。 我们确定了我们使用的函数列表,但它们并未在carbonapi中实现。 我们添加了这些功能并向carbonapi的作者发送了PR(特别感谢他们)。

  • 为了切换平衡器设置中的读取负载,我们将端点从graphite-api(Graphite+Whisper的API接口)更改为carbonapi。

石墨+ClickHouse。 结果

  • 将磁盘子系统利用率从 30% 降低至 1%;

    指标存储:我们如何从 Graphite+Whisper 切换到 Graphite+ClickHouse

  • 将占用空间从 1 TB 减少到 300 GB;
  • 我们有能力每分钟将 125 亿个指标接收到服务器中(迁移时的峰值);
  • 将所有指标转移到三十秒的存储间隔;
  • 接收数据的复制和容错;
  • 无需停机即可切换;
  • 完成所有工作大约需要 7 周时间。

石墨+ClickHouse。 问题

在我们的例子中,存在一些陷阱。 这是我们转型后遇到的情况。

  1. ClickHouse 并不总是即时重新读取配置;有时需要重新启动。 例如,对于 ClickHouse 配置中的 Zookeeper 集群的描述,直到 clickhouse-server 重新启动后才使用它。
  2. 大型 ClickHouse 请求没有通过,因此在石墨-clickhouse 中,我们的 ClickHouse 连接字符串如下所示:
    url = "http://localhost:8123/?max_query_size=268435456&max_ast_elements=1000000"
  3. ClickHouse 经常发布稳定版本的新版本;它们可能包含惊喜:要小心。
  4. kubernetes 中动态创建的容器会发送大量生命周期短且随机的指标。 这样的指标点数并不多,空间也不存在问题。 但是在构建查询时,ClickHouse 会从“指标”表中获取大量相同的指标。 在 90% 的情况下,在窗口(24 小时)之外没有关于它们的数据。 但是时间花在了在“数据”表中搜索这些数据,最终会遇到超时。 为了解决这个问题,我们开始维护一个单独的视图,其中包含当天遇到的指标信息。 因此,在为动态创建的容器构建报告(图表)时,我们仅查询给定窗口内遇到的指标,而不是整个时间,这显着加快了报告的构建速度。 对于上述解决方案,我收集了 石墨-clickhouse(叉子),其中包括使用 date_metrics 表的实现。

石墨+ClickHouse。 标签

随着版本 1.1.0 Graphite 正式上线 支持标签。 我们正在积极思考如何以及如何支持石墨+clickhouse 堆栈中的这一举措。

石墨+ClickHouse。 异常检测器

基于上述基础设施,我们实现了异常检测器的原型,并且它可以工作! 但下一篇文章将详细介绍他。

订阅,按向上箭头并快乐!

来源: habr.com

添加评论