我在clickhouse中有一个事件表(MergeTree),并希望同时运行很多小插入。但是,服务器变得过载并且没有响应。而且,一些插入物丢失了。 clickhouse错误日志中有很多记录:
01:43:01.668 [ 16 ] <Error> events (Merger): Part 201 61109_20161109_240760_266738_51 intersects previous part
有没有办法优化此类查询?我知道我可以使用批量插入来处理某些类型的事件。基本上,运行一个带有许多记录的插入,clickhouse处理得非常好。但是,某些事件(例如点击或打开)无法以这种方式处理。
另一个问题:为什么clickhouse决定存在类似记录,何时不存在?插入时有类似的记录,它们与索引中的字段相同,但其他字段不同。
我还会不时收到以下错误:
Caused by: ru.yandex.clickhouse.except.ClickHouseUnknownException: ClickHouse exception, message: Connect to localhost:8123 [ip6-localhost/0:0:0:0:0:0:0:1] timed out, host: localhost, port: 8123; Connect to ip6-localhost:8123 [ip6-localhost/0:0:0:0:0:0:0:1] timed out
... 36 more
主要是在项目构建期间运行针对clickhouse数据库的测试时。
答案 0 :(得分:5)
将大量小插入处理到(非复制)MergeTree时,这是已知问题。
这是一个错误,我们需要调查并修复。
对于变通方法,您应该按照建议大批量发送插入:大约每秒一批:https://clickhouse.yandex/reference_en.html#Performance%20on%20data%20insertion。
答案 1 :(得分:4)
我遇到过类似的问题,虽然没有那么糟糕 - 每秒约20次插入导致服务器达到高负载,内存消耗和CPU使用率。我创建了一个缓冲表,用于缓冲内存中的插入,然后定期刷新到&#34; real&#34;磁盘表。就像魔术一样,一切都很顺利:loadavg,内存和CPU使用率都降到了正常水平。好处是你可以对缓冲表运行查询,并从内存和磁盘中获取匹配的行 - 因此客户端不受缓冲的影响。见https://clickhouse.yandex/docs/en/table_engines/buffer.html
答案 2 :(得分:1)
Clickhouse为此具有特殊的表格类型-缓冲区。它存储在内存中,并允许许多小的插入而没有问题。每秒大约有200种不同的插入效果-效果很好。
缓冲区表:
CREATE TABLE logs.log_buffer (rid String, created DateTime, some String, d Date MATERIALIZED toDate(created)) ENGINE = Buffer('logs', 'log_main', 16, 5, 30, 1000, 10000, 1000000, 10000000);
主表:
CREATE TABLE logs.log_main (rid String, created DateTime, some String, d Date) ENGINE = MergeTree(d, sipHash128(rid), (created, sipHash128(rid)), 8192);
手册中的详细信息:https://clickhouse.yandex/docs/en/operations/table_engines/buffer/
答案 3 :(得分:0)
或者,您可以使用类似https://github.com/nikepan/clickhouse-bulk的东西:它将缓冲多个插入并根据用户策略将它们全部刷新。
答案 4 :(得分:0)
clickhouse MergeEngines 的设计并不意味着同时进行小写操作。据我所知,MergeTree 将写入表的数据 parts
合并到基于分区中,然后重新组织 parts
以获得更好的聚合读取。如果我们经常做小写,你会遇到另一个例外 Merge
Error: 500: Code: 252, e.displayText() = DB::Exception: Too many parts (300). Merges are processing significantly slow
当您尝试理解为什么会抛出上述异常时,您的想法会更加清晰。 CH需要合并数据,并且可以存在多少部分是有上限的!并且批处理中的每个写入都作为一个新部分添加,然后最终与分区表合并。
SELECT
table, count() as cnt
FROM system.parts
WHERE database = 'dbname' GROUP BY `table` order by cnt desc
上面的查询可以帮助你监控部分,在写的时候观察这些部分是如何增加并最终合并的。
我最好的选择是缓冲数据集并定期将其刷新到数据库,但这意味着没有实时分析。
使用缓冲区很好,但请考虑以下几点:
请通读一遍,这是一个特例引擎:https://clickhouse.tech/docs/en/engines/table-engines/special/buffer/