你好,哈布尔。
如果有人利用该系统
ClickHouse很好地解决了所描述的问题。 例如,从 Whisper 传输 2TiB 数据后,它们可容纳 300GiB。 我不会详细讨论这种比较;关于这个主题的文章有很多。 此外,直到最近,我们的 ClickHouse 存储并不是一切都很完美。
空间消耗问题
乍一看,一切都应该运行良好。 下列的 retention
),然后根据为graphite-web选择的后端的推荐创建一个表:
为了了解哪一个,您需要了解插入是如何工作的以及*系列引擎表中数据的进一步生命路径合并树 ClickHouse(图表取自
- 插入
блок
数据。 在我们的例子中,是到达的指标。
- 每个这样的块在写入磁盘之前都会根据键进行排序。
ORDER BY
创建表时指定。 - 排序后,
кусок
(part
)数据写入磁盘。
- 服务器在后台监控,这样这样的碎片就不会很多,并启动后台
слияния
(merge
,以下合并)。
- 一旦数据停止主动流入服务器,服务器就会停止自行运行合并
партицию
(partition
),但您可以使用以下命令手动启动该进程OPTIMIZE
. - 如果分区中只剩下一块,那么您将无法使用通常的命令运行合并;您必须使用
OPTIMIZE ... FINAL
因此,第一个指标出现了。 它们占用了一些空间。 随后的事件可能会因多种因素而有所不同:
- 分区键可以非常小(一天)或非常大(几个月)。
- 保留配置可能适合活动分区(其中记录指标)内的几个重要数据聚合阈值,也可能不适合。
- 如果有大量数据,那么最早的块(由于后台合并可能已经很大了(如果您选择非最佳分区键))将不会与新的小块合并。
而且结局总是一样的。 ClickHouse 中指标占用的空间仅在以下情况下增加:
- 请勿应用
OPTIMIZE ... FINAL
手动或 - 不要持续将数据插入所有分区,这样后台合并迟早会开始
第二种方法似乎是最容易实现的,因此它是不正确的,因此首先尝试过。
我编写了一个相当简单的 python 脚本,该脚本在过去 4 年里每天发送虚拟指标,并每小时运行一次 cron。
由于ClickHouse DBMS的整个操作是建立在这个系统迟早会完成所有后台工作的基础上的,但不知道什么时候,我无法等待旧的大块开始合并的那一刻新的小。 很明显,我们需要寻找一种自动执行强制优化的方法。
ClickHouse系统表中的信息
我们看一下表结构
- 数据库名称(
database
); - 表名(
table
); - 分区名称和 ID (
partition
&partition_id
); - 当这件作品被创作时(
modification_time
); - 片段中的最小和最大日期(按天进行分区)(
min_date
&max_date
);
还有一张桌子
- 数据库名称(
Tables.database
); - 表名(
Tables.table
); - 应应用下一次聚合的指标年龄(
age
);
所以:
- 我们有一个块表和一个聚合规则表。
- 我们组合它们的交集并得到所有表 *GraphiteMergeTree。
- 我们正在寻找其中的所有分区:
- 多于一件
- 或者已经到了应用下一个聚合规则的时候了,并且
modification_time
比这一刻更老。
履行
这个请求
SELECT
concat(p.database, '.', p.table) AS table,
p.partition_id AS partition_id,
p.partition AS partition,
-- Самое "старое" правило, которое может быть применено для
-- партиции, но не в будущем, см (*)
max(g.age) AS age,
-- Количество кусков в партиции
countDistinct(p.name) AS parts,
-- За самую старшую метрику в партиции принимается 00:00:00 следующего дня
toDateTime(max(p.max_date + 1)) AS max_time,
-- Когда партиция должна быть оптимизированна
max_time + age AS rollup_time,
-- Когда самый старый кусок в партиции был обновлён
min(p.modification_time) AS modified_at
FROM system.parts AS p
INNER JOIN
(
-- Все правила для всех таблиц *GraphiteMergeTree
SELECT
Tables.database AS database,
Tables.table AS table,
age
FROM system.graphite_retentions
ARRAY JOIN Tables
GROUP BY
database,
table,
age
) AS g ON
(p.table = g.table)
AND (p.database = g.database)
WHERE
-- Только активные куски
p.active
-- (*) И только строки, где правила аггрегации уже должны быть применены
AND ((toDateTime(p.max_date + 1) + g.age) < now())
GROUP BY
table,
partition
HAVING
-- Только партиции, которые младше момента оптимизации
(modified_at < rollup_time)
-- Или с несколькими кусками
OR (parts > 1)
ORDER BY
table ASC,
partition ASC,
age ASC
返回每个 *GraphiteMergeTree 表分区,其合并应释放磁盘空间。 剩下要做的唯一一件事就是通过一个请求来检查所有这些 OPTIMIZE ... FINAL
。 最终的实现还考虑到不需要接触活动记录的分区这一事实。
这正是该项目所做的
如果您在带有 ClickHouse 的服务器上运行该程序,它将简单地开始以守护进程模式工作。 每小时执行一次请求,检查是否出现了超过三天的可以优化的新分区。
我们近期的计划是至少提供 deb 软件包,如果可能的话还提供 rpm。
取而代之的是结论
在过去的 9 个多月里,我一直在我的公司里
开发该请求花费了几升啤酒和管理时间,以及
来源: habr.com