clickhouse对数据实时性的解决方案
因为clickhouse 对数据的更新不是实时性的,但是有的业务对实时性要求比较高。 ck变相提供了一些不是完美的方案
方案一、
insert +xxxxmergeTree 引擎 解决更新问题。
但是数据聚合又是非实时的,
只能做到最终一致性,数据非实时, 极端情况下,可能需要一天的时间。
可以调用Optimize Table … Final 强制合并数据。
方案二、
Insert+xxxxMergeTree+Final
xxxMergeTree是异步的 可以使用final 指定final以后,
clickhouse 会再返回结果之前 完全合并数据。
缺点:
每次查询之前都要合并数据, 成本高。
CREATE TABLE alerts(
tenant_id UInt32,
alert_id String,
timestamp DateTime Codec(Delta, LZ4),
alert_data String,
acked UInt8 DEFAULT 0,
ack_time DateTime DEFAULT toDateTime(0),
ack_user LowCardinality(String) DEFAULT ''
)
ENGINE = ReplacingMergeTree(ack_time)
PARTITION BY tuple()
ORDER BY (tenant_id, timestamp, alert_id);
SELECT
count(),
sum(cityHash64(*)) AS data
FROM alerts
FINAL
WHERE (tenant_id = 451) AND (NOT acked)
查询及其快,只有25ms就可以查询出非确认的数据。为啥如此快呢?
在这个过滤条件中不同的是tenant_id 是主键的一部分,所以clickhouse在FINAL之前就可以过滤数据,ReplacingMergeTree 变的更加有效。
SELECT count()
FROM alerts
FINAL
WHERE (ack_user = 'user451') AND acked
我们不能在 ack_user列添加索引,因为它会破坏ReplacingMergeTree的语义。 不过,我们可以使用PREWHERE技巧:
SELECT count()
FROM alerts
FINAL
PREWHERE (ack_user = 'user451') AND acked
PREWHERE是ClickHouse的特殊提示去应用于不同的过滤器。 通常,ClickHouse足够聪明,可以自动将条件移至PREWHERE,
因此用户无需理会。 此次没有发生,便于我们检查核对。
https://blog.csdn.net/vkingnew/article/details/106913907
方案三、
Insert + argMax
argMax(score, create_time) AS score 按照create_time 最大值,取score的值。
select ru_id,row_update_time,
argMax(is_effective,row_update_time) is_effective
from t_ru_packaging_build
group by ru_id,row_update_time;
缺点:
查询语句比较复杂;
如果还要做一些聚合统计逻辑,那么就需要子查询;
内存开销会大一些。
方案四、
AggregatingMergeTree 和聚合函数
CREATE TABLE alerts_amt_max (
tenant_id UInt32,
alert_id String,
timestamp DateTime Codec(Delta, LZ4),
alert_data SimpleAggregateFunction(max, String),
acked SimpleAggregateFunction(max, UInt8),
ack_time SimpleAggregateFunction(max, DateTime),
ack_user SimpleAggregateFunction(max, LowCardinality(String))
)
Engine = AggregatingMergeTree()
ORDER BY (tenant_id, timestamp, alert_id);
SELECT count(), sum(cityHash64(*)) data FROM (
SELECT tenant_id, alert_id, timestamp,
max(alert_data) alert_data,
max(acked) acked,
max(ack_time) ack_time,
max(ack_user) ack_user
FROM alerts_amt_max
GROUP BY tenant_id, alert_id, timestamp
)
WHERE tenant_id=451 AND NOT acked;
方案5
UPDATE+ SETTING mutations_sync
参数mutations_sync默认为0,表示异步。1表示等待当前server完成后返回,2表示等待所有副本数据都更新后再返回。
Alter table xxx update col = xxx where xxx mutations_sync = 1/2
更新完之后所有查询都能立马感知到最新的数据。
操作本身会比较耗时。如果数据量大,执行起来就会很慢。
注意: 所以不能指望merge自己合并数据,非常不靠谱。
mergeTree自己合并数据 是Clickhouse基于策略控制的,执行时间比较随机,因此数据一致性缺少时间保证,极端情况下数据过了一天也没有完全合并。
clickhouse 对update,delete 支持不友好, 比较适合insert 场景的应用。
在基于Clickhouse的数据仓库建设中,由于Clickhouse本身不支持完备的数据更新,数据的实时性和一致性存在trade-off,如果应用场景对数据一致性要求很高,在有数据更新的情况下,基本无法实时导入数据,只能周期性的离线导入以保证Clickhouse中的数据是某一时刻的完整切片。离线任务由于存在调度延时,一般来讲周期最小只能做到小时级,很难做到分钟级。如果应用场景更在意数据的实时性,就可以采用实时导入的方式,由于Clickhouse的Merge过程是基于策略调度的,因此在数据一致性上就会差一些(会查到本该被删除的数据)。
基于实时写入+定期Optimize的方式,可以通过改变Optimize周期,在性能、数据一致性之间做平衡。当数据一致性要求较高时,可以缩短Optimize周期,极端情况甚至可以每次写入都执行Optimize,这样可以将数据不一致的时间缩短到分钟级(当然这样对Clickhouse的性能要求比较严格);当数据量比较大时,可以半个小时左右执行一次Optimize,这样在保证Clickhouse集群性能的同时,也对数据不一致的时间有一个保障。在笔者的实际使用中,Clickhouse集群使用32核64G机器,单表原始数据量在1TB以内的情况下,Optimize执行周期在5min-10min都没什么压力。
https://juejin.cn/post/7039978768022110238 这篇文章的总结

ClickHouse 提供了丰富的工具集来处理实时更新,如 ReplacingMergeTree、CollapsingMergeTree(本文未提及)、AggregatingMergeTree 和聚合函数。所有这些方法都具有以下三个共性:
通过插入新版本来“修改”数据。ClickHouse 中的插入速度非常快。
有一些有效的方法来模拟类似于 OLTP 数据库的更新语义。
然而,实际的修改并不会立即发生。
具体方法的选择取决于应用程序的用例。对用户来说,ReplacingMergeTree 是直截了当的,也是最方便的方法,但只适用于中小型的表,或者数据总是按主键查询的情况。使用聚合函数可以提供更高的灵活性和性能,但需要大量的查询重写。最后,AggregatingMergeTree 可以节约存储空间,只保留修改过的列。这些都是 ClickHouse DB 设计人员的好工具,可根据具体需要来应用。
参考
https://juejin.cn/post/7039978768022110238
https://zhuanlan.zhihu.com/p/485645089
https://cloud.tencent.com/developer/article/1888949
https://cloud.tencent.com/developer/article/1644570
https://www.modb.pro/db/197765
更多推荐




所有评论(0)