ClickHouse到底应该写分布式表还是写本地表?

本文探讨了ClickHouse中本地表与分布式表的写入策略。对于数据量较小的业务,两者均可使用;而对于大规模数据,则推荐使用本地表。文章详细分析了不同场景下的优缺点,并提供了实际操作建议。

ClickHouse到底改写本地表还是分布式表

TL;DR

如果预估自己的业务数据量不大(日增不到百万行), 那么写分布式表和本地表都可以, 但要注意如果选择写本地表, 请保证每次写入数据都建立新的连接, 且每个连接写入的数据量基本相同

如果预估自己的业务数据量大(日增百万以上, 并发插入大于10), 那么请写本地表

建议每次插入50W行左右数据, 最多不可超过100W行. 总之CH不像MySQL要小事务. 比如1000W行数据, MySQL建议一次插入1W左右, 使用小事务, 执行1000次. CH建议20次,每次50W. 这是MergeTree引擎原理决定的, 频繁少量插入会导致data part过多, 合并不过来.

再有, AP不像TP, TP为了避免建立新连接产生的损耗影响性能, 通常会使用长连接, 连接池等技术做优化. 但AP业务不需要, 因为AP的属性就不会有高并发, 小SQL.

原因请继续看

看了一些文档都建议写分布式表, 虽说别人没必要骗我们, 但是搞技术的不能人云亦云, 还是要明白为啥, 说实话我想了很久没想出直接写分布式表有什么致命缺陷, 于是在ClickHouse中文社区提了问题, 内容如下

看了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 是分片级别的, 不是表级别的, 灵活性差

问了下新浪的高鹏
在这里插入图片描述
在这里插入图片描述
高鹏的回答总结一下就是:

1.新浪每天增量是千亿级的, INSERT并发和节点数应该比较高, 直接写某个节点的分布式表, 这个节点还需要建立N-1个连接(N是集群节点数)分发数据, 再有就是他说的第3点

2.通过负载均衡向本地表插入数据要控制尽量每次插入数据建立一次连接, 每个链接插入的数据量要差不多, batch size不能太小, 否则data part过多, merge不过来clickhouse会报错

<think>嗯,用户想了解ClickHouse分布式的配置和使用,这属于分布式数据库的核心功能。用户可能正在搭建数据分析平台,或是遇到性能瓶颈需要横向扩展。从问题述看,用户对分布式概念有一定基础,但需要实操指导。 分布式的核心价值在于透明化集群操作。引用[2]提到它像Elasticsearch的分片机制,这个类比很贴切。不过要注意ClickHouse的特殊性:分布式本质是逻辑视图(引用[4]强调过),实际数据存储在本地表。这种设计带来两个关键点: - 写入路由策略:引用[4]详细说明sharding_key机制,用户需要根据业务选择哈希或随机分布 - 读分离:引用[1]特别警告异步写入可能导致数据不一致,建议生产环境直写本地表 配置流程上要分三步走: 1. 集群定义必须先在config.xml声明(引用[3]踩坑提示),否则分布式无法跨节点识别 2. ReplicatedMergeTree引擎的选择直接影响高可用性(引用[2]提到依赖ZooKeeper) 3. 分布式创建时的分片权重配置(引用[4])容易被忽略,但这对热点数据均衡很重要 用户可能没意识到的问题: - 分布式查询的代价:当WHERE条件涉及sharding_key时性能最佳,否则引发全集群扫描 - 二级索引的局限性:引用[4]隐含提到,非分片键的索引只在本地表生效 最后要注意版本差异。引用[3]示例的ON CLUSTER语法在旧版可能不支持,这点必须明确告知用户避免配置失败。 相关问题的设计要覆盖用户后续可能遇到的痛点: 1. 性能调优是刚需(尤其大数据量下的查询) 2. 数据一致性保障在生产环境至关重要 3. 运维层面的监控和扩容也是高阶用户必然面对的</think>下面详细介绍ClickHouse分布式的配置和使用,结合核心原理和实操要点: --- ### **一、分布式的核心概念** 1. **分布式(Distributed)** - 逻辑视图,不存储实际数据 - 通过`Distributed`引擎将查询路由到集群中的**本地表** - 支持跨节点数据聚合与查询 2. **本地表(Local Table)** - 物理存储数据的,如: ```sql CREATE TABLE local_table ON CLUSTER my_cluster ( id UInt32, event_time DateTime ) ENGINE = ReplicatedMergeTree('/ch/tables/{shard}/local_table', '{replica}') ORDER BY id; ``` - 必须使用`ReplicatedMergeTree`系列引擎实现数据复制和高可用[^2] 3. **集群配置(config.xml)** 在每台节点的`config.xml`中定义集群拓扑: ```xml <remote_servers> <my_cluster> <!-- 集群名 --> <shard> <!-- 分片1(含副本) --> <weight>1</weight> <replica> <host>node1</host> <port>9000</port> </replica> <replica> <!-- 副本 --> <host>node2</host> <port>9000</port> </replica> </shard> <shard> <!-- 分片2 --> ... </shard> </my_cluster> </remote_servers> ``` - `weight`控制写入时的数据分布权重[^4] --- ### **二、分布式操作指南** #### 1. **创建分布式** ```sql CREATE TABLE distributed_table ON CLUSTER my_cluster AS local_table ENGINE = Distributed( my_cluster, -- 集群名称 default, -- 数据库名 local_table, -- 本地表名 rand() -- 分片键(可选:rand()/列名) ); ``` - **关键参数**: - **分片键**:决定数据写入哪个分片 - `rand()`:随机分布 - `intHash64(user_id)`:按哈希值分布(推荐离散数据)[^4] - 必须使用`ON CLUSTER`确保集群内所有节点生效[^3] #### 2. **数据写入策略** | **方式** | **优点** | **缺点** | 适用场景 | |------------------|-----------------------------|-----------------------------|--------------| | **分布式** | 自动路由数据 | 异步写入可能丢失数据[^1] | 测试环境 | | **直写本地表** | 数据强一致 | 需应用层处理分片逻辑 | 生产环境[^1] | **直写本地表示例**: ```sql INSERT INTO local_table VALUES (1, '2023-10-01 00:00:00') -- 需在应用层计算目标分片 ``` #### 3. **查询流程** ```mermaid graph LR A[客户端] --> B[分布式] B --> C{路由查询} C --> D[分片1本地表] C --> E[分片2本地表] D --> F[聚合结果] E --> F F --> G[返回客户端] ``` - WHERE条件含**分片键**时触发**本地查询**,否则全集群扫描[^4] --- ### **三、生产环境最佳实践** 1. **避免分布式写入** - 通过负载均衡器将请求定向到具体分片的本地表 - 使用`insert_distributed_sync=1`强制同步写入(影响性能) 2. **分片键设计原则** - 选择高基数字段(如`user_id`) - 确保数据均匀分布:`SELECT shard, count() FROM distributed_table GROUP BY shard` 3. **ZooKeeper高可用配置** ```xml <zookeeper> <node index="1"> <host>zk1</host> <port>2181</port> </node> <node index="2">...</node> </zookeeper> ``` - 副本依赖ZK管理数据同步[^2] --- ### **四、常见问题解决** 1. **分布式查询卡顿** - 检查网络延迟:`SELECT * FROM system.clusters` - 优化分片键减少跨节点通信 2. **数据不一致** - 直写本地表 + 启用`insert_quorum=2`(多数写入成功) 3. **节点扩容** - 动态更新`config.xml`后重启ClickHouse - 重新平衡数据:`ALTER TABLE ... MOVE PARTITION` ---
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值