到底为什么建议轮询写本地表而不是直接写分布式表

发布于 5 个月前 作者 Fanduzi 1952 次浏览 来自 问答

看了sina高鹏大佬的分享 看了 https://github.com/ClickHouse/ClickHouse/issues/1854 还看了一些文章都是建议写本地表而不是分布式表 如果我设置internal_replication=true, 使用ReplicatedMergeTree引擎, 除了写本地表更灵活可控外, 写分布式表到底有什么致命缺陷吗? 因为要给同事解释, 只说一个大家说最佳实践是这样是不行的… 我自己也没理解到底写分布式表有啥大缺陷 如果说造成数据分布不均匀, sharding key我设为rand()还会有很大不均匀吗? 如果说扩容, 我也可以通过调整weight控制数据尽量写入新shared啊?

难道是因为

Data is written asynchronously. When inserted in the table, the data block is just written to the local file system. The data is sent to the remote servers in the background as soon as possible. The period for sending data is managed by the distributed_directory_monitor_sleep_time_ms and distributed_directory_monitor_max_sleep_time_ms settings. The Distributed engine sends each file with inserted data separately, but you can enable batch sending of files with the distributed_directory_monitor_batch_inserts setting. This setting improves cluster performance by better utilizing local server and network resources. You should check whether data is sent successfully by checking the list of files (data waiting to be sent) in the table directory: /var/lib/clickhouse/data/database/table/.

If the server ceased to exist or had a rough restart (for example, after a device failure) after an INSERT to a Distributed table, the inserted data might be lost. If a damaged data part is detected in the table directory, it is transferred to the ‘broken’ subdirectory and no longer used.

上面文档内容我理解意思是说假如我有S1 S2 S3 三个节点,每个节点都有local表和分布式表. 我向S1的分布式表写数据1, 2, 3 1写入S1, 2,3先写到S1本地文件系统, 然后异步发送到S2 S3 , 比如2发给S2, 3发给S3, 如果此时S3宕机了, 则3发到S3失败, 但是1,2还是成功写到S1,S2了? 所以整个过程不能保证原子性? 出现问题还要人为修数据? https://github.com/ClickHouse/ClickHouse/issues/1343 这个issue说S3 come back后S1会尝试重新发送数据给S3.

Data blocks are written in /var/lib/clickhouse/data/database/table/ folder. Special thread checks directory periodically and tries to send data. If it can’t, it will try next time.

那么只剩文档最后一句意思是如果S1过程中宕机, 会丢数据?

虚心求助各位大佬!

自问自答一下吧, weight是分片级别的, 不是表级别的, 灵活性差, 再有就是根据insert_distributed_sync参数

M(SettingBool, insert_distributed_sync, false, "If setting is enabled, insert query into distributed waits until data will be sent to all nodes in cluster.", 0) \

对于应用来说默认只要数据写入S1成功就返回成功了, S2 S3是异步发送的, 那么如果真的有插入会立即查询的需求, 可能查不到S2 S3的数据

联系了x浪的高鹏大佬, 大佬给出如下原因

  1. 做了外层的dns轮训 已经做了 lb了 就没有必要靠分布式表来做了
  2. 写分布式表 它又会帮你转发 导致连接数被占用
  3. 如果某一个节点异常 或者 对端的表被删了 分布式表会把写入的数据放到tmp目录 无限制的尝试去发送
  4. 分布式表本身的设计是为了读 并不是为了写 因此 不是很建议用

如果实在想用分布式表做hash 也不是不行 任何东西都不绝对 如果一天的量就那么十来个亿 完全可以用 x浪面临的是十几台机器 一天上千亿的量, 因此要尽量优化 避免问题

结合自身情况来看, 我们分片少, 副本少, 数据量少, 其实咋写都行, 不过第3点是个要注意的问题, 总之没有绝对的架构,只有适合自己的. 还有两点需要注意的就是:

  1. 写本地表, 需要开发配合, 保证每个链接写入的数据量是均衡的
    • 比如我CH就2个node,2个分片, 应用通过dns轮询2次分别链接到了两个分片向本地表做insert. 但是可能第一次插入了1W行, 第二次插入了1行, 这样虽然链接是负载均衡的建立了, 但是插入的数据还是不均衡
  2. 每次写入的batch size不能太小, 否则data part太多merge不过来
2 回复

你的分析过程有道理,我接收。 轮询写本地表如何操作呢?如果手动第一批数据写入s1,第二批数据写入s2,第三批数据写入s3,但是每**次的数据量不一样大,还是会出现数据分布不均匀。

@bjgua 确实是, 需要应用开发者也做好配合

回到顶部