你好,哈布爾。
如果有人利用該系統
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 個多月裡,我一直在我的公司裡
開發該請求花費了幾公升啤酒和管理時間,以及
來源: www.habr.com