横向扩展
描述
此示例架构旨在提供可扩展性。它包括三个节点:两个组合的 ClickHouse 加协调(ClickHouse Keeper)服务器,以及一个仅具有 ClickHouse Keeper 的服务器来完成三个节点的仲裁。使用此示例,我们将创建一个数据库、表和一个分布式表,该表将能够查询两个节点上的数据。
级别:基础
术语
副本
数据的副本。ClickHouse 始终至少拥有您数据的副本,因此**副本**的最小数量为 1。这是一个重要的细节,您可能不习惯将数据的原始副本算作副本,但这是 ClickHouse 代码和文档中使用的术语。添加数据的第二个副本可以提供容错能力。
分片
数据的子集。ClickHouse 始终至少拥有您数据的一个分片,因此如果您不将数据分散到多个服务器,那么您的数据将存储在一个分片中。将数据分散到多个服务器可以用来在您超过单个服务器的容量时划分负载。目标服务器由**分片键**确定,并在您创建分布式表时定义。分片键可以是随机的,也可以是哈希函数的输出。涉及分片的部署示例将使用rand()
作为分片键,并将提供有关何时以及如何选择不同分片键的更多信息。
分布式协调
ClickHouse Keeper 为数据复制和分布式 DDL 查询执行提供协调系统。ClickHouse Keeper 与 Apache ZooKeeper 兼容。
环境
架构图
节点 | 描述 |
---|---|
chnode1 | 数据 + ClickHouse Keeper |
chnode2 | 数据 + ClickHouse Keeper |
chnode3 | 用于 ClickHouse Keeper 仲裁 |
在生产环境中,我们强烈建议 ClickHouse Keeper 在专用主机上运行。此基本配置在 ClickHouse Server 进程内运行 Keeper 功能。在安装文档中提供了独立部署 ClickHouse Keeper 的说明。
安装
按照您的存档类型的说明(.deb、.rpm、.tar.gz 等)在三台服务器上安装 Clickhouse。在本示例中,您将按照三台机器上的 ClickHouse Server 和 Client 的安装说明进行操作。
编辑配置文件
通过添加或编辑配置文件来配置 ClickHouse Server 时,您应该
- 将文件添加到
/etc/clickhouse-server/config.d/
目录 - 将文件添加到
/etc/clickhouse-server/users.d/
目录 - 保持
/etc/clickhouse-server/config.xml
文件原样 - 保持
/etc/clickhouse-server/users.xml
文件原样
chnode1 配置
对于 chnode1,有五个配置文件。您可以选择将这些文件合并成一个文件,但为了文档的清晰性,单独查看它们可能更简单。当您阅读配置文件时,您会发现大多数配置在 chnode1 和 chnode2 之间是相同的;差异将被突出显示。
网络和日志记录配置
这些值可以根据您的需要进行自定义。此示例配置为您提供了将在 1000M 处滚动三次的调试日志。ClickHouse 将在 IPv4 网络上的端口 8123 和 9000 上监听,并将使用端口 9009 进行服务器间通信。
<clickhouse>
<logger>
<level>debug</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>
<display_name>clickhouse</display_name>
<listen_host>0.0.0.0</listen_host>
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<interserver_http_port>9009</interserver_http_port>
</clickhouse>
ClickHouse Keeper 配置
ClickHouse Keeper 为数据复制和分布式 DDL 查询执行提供协调系统。ClickHouse Keeper 与 Apache ZooKeeper 兼容。此配置在端口 9181 上启用 ClickHouse Keeper。突出显示的行指定此 Keeper 实例的server_id
为 1。这是三台服务器上enable-keeper.xml
文件中唯一的区别。chnode2
将设置server_id
为2
,而chnode3
将设置server_id
为3
。Raft 配置部分在所有三台服务器上都相同,下面突出显示它以向您展示server_id
与 Raft 配置中的server
实例之间的关系。
如果由于任何原因,Keeper 节点被替换或重建,请不要重复使用现有的server_id
。例如,如果server_id
为2
的 Keeper 节点被重建,请将其server_id
设置为4
或更高。
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>trace</raft_logs_level>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>chnode1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>chnode2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>chnode3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
宏配置
宏shard
和replica
减少了分布式 DDL 的复杂性。配置的值会自动替换到您的 DDL 查询中,这简化了您的 DDL。此配置的宏指定了每个节点的分片和副本编号。
在此 2 分片 1 副本示例中,replica
宏在 chnode1 和 chnode2 上都是replica_1
,因为只有一个副本。shard
宏在 chnode1 上是1
,在 chnode2 上是2
。
<clickhouse>
<macros>
<shard>1</shard>
<replica>replica_1</replica>
</macros>
</clickhouse>
复制和分片配置
从顶部开始
- XML 的
remote_servers
部分指定了环境中的每个集群。属性replace=true
将默认 ClickHouse 配置中的示例remote_servers
替换为在此文件中指定的remote_servers
配置。如果没有此属性,此文件中的远程服务器将附加到默认配置中的示例列表。 - 在此示例中,有一个名为
cluster_2S_1R
的集群。 - 为名为
cluster_2S_1R
的集群创建一个密钥,其值为mysecretphrase
。该密钥在环境中的所有远程服务器之间共享,以确保将正确的服务器连接在一起。 - 集群
cluster_2S_1R
有两个分片,每个分片都有一个副本。查看本文档开头的架构图,并将其与下面 XML 中的两个shard
定义进行比较。在每个shard
定义中,都只有一个副本。该副本是针对该特定分片的。该副本的主机和端口已指定。配置中第一个分片的副本存储在chnode1
上,配置中第二个分片的副本存储在chnode2
上。 - 分片的内部复制设置为 true。每个分片可以在配置文件中定义
internal_replication
参数。如果将此参数设置为 true,写入操作将选择第一个健康的副本并将数据写入该副本。
<clickhouse>
<remote_servers replace="true">
<cluster_2S_1R>
<secret>mysecretphrase</secret>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>chnode1</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>chnode2</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_1R>
</remote_servers>
</clickhouse>
配置 Keeper 的使用
在上面的一些文件中,配置了 ClickHouse Keeper。这个配置文件 `use-keeper.xml` 用于配置 ClickHouse Server 使用 ClickHouse Keeper 来协调复制和分布式 DDL。该文件指定 ClickHouse Server 应该在节点 chnode1-3 上使用端口 9181 上的 Keeper,该文件在 `chnode1` 和 `chnode2` 上是相同的。
<clickhouse>
<zookeeper>
<node index="1">
<host>chnode1</host>
<port>9181</port>
</node>
<node index="2">
<host>chnode2</host>
<port>9181</port>
</node>
<node index="3">
<host>chnode3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
chnode2 配置
由于 chnode1 和 chnode2 上的配置非常相似,这里只指出差异。
网络和日志配置
<clickhouse>
<logger>
<level>debug</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>
<display_name>clickhouse</display_name>
<listen_host>0.0.0.0</listen_host>
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<interserver_http_port>9009</interserver_http_port>
</clickhouse>
ClickHouse Keeper 配置
此文件包含 chnode1 和 chnode2 之间的两个差异之一。在 Keeper 配置中,`server_id` 设置为 `2`。
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>2</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>trace</raft_logs_level>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>chnode1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>chnode2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>chnode3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
宏配置
宏配置是 chnode1 和 chnode2 之间的差异之一。`shard` 在此节点上设置为 `2`。
<clickhouse>
<macros>
<shard>2</shard>
<replica>replica_1</replica>
</macros>
</clickhouse>
复制和分片配置
<clickhouse>
<remote_servers replace="true">
<cluster_2S_1R>
<secret>mysecretphrase</secret>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>chnode1</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>chnode2</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_1R>
</remote_servers>
</clickhouse>
配置 Keeper 的使用
<clickhouse>
<zookeeper>
<node index="1">
<host>chnode1</host>
<port>9181</port>
</node>
<node index="2">
<host>chnode2</host>
<port>9181</port>
</node>
<node index="3">
<host>chnode3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
chnode3 配置
由于 chnode3 不存储数据,仅用于 ClickHouse Keeper 提供仲裁中的第三个节点,因此 chnode3 只有两个配置文件,一个用于配置网络和日志,另一个用于配置 ClickHouse Keeper。
网络和日志配置
<clickhouse>
<logger>
<level>debug</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>
<display_name>clickhouse</display_name>
<listen_host>0.0.0.0</listen_host>
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<interserver_http_port>9009</interserver_http_port>
</clickhouse>
ClickHouse Keeper 配置
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>3</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>trace</raft_logs_level>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>chnode1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>chnode2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>chnode3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
测试
- 连接到 `chnode1` 并验证上面配置的集群 `cluster_2S_1R` 是否存在
SHOW CLUSTERS
┌─cluster───────┐
│ cluster_2S_1R │
└───────────────┘
- 在集群上创建一个数据库
CREATE DATABASE db1 ON CLUSTER cluster_2S_1R
┌─host────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ chnode2 │ 9000 │ 0 │ │ 1 │ 0 │
│ chnode1 │ 9000 │ 0 │ │ 0 │ 0 │
└─────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
- 在集群上创建一个使用 MergeTree 表引擎的表。注意
我们不需要指定表引擎的参数,因为这些参数将根据我们的宏自动定义
CREATE TABLE db1.table1 ON CLUSTER cluster_2S_1R
(
`id` UInt64,
`column1` String
)
ENGINE = MergeTree
ORDER BY id
┌─host────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ chnode1 │ 9000 │ 0 │ │ 1 │ 0 │
│ chnode2 │ 9000 │ 0 │ │ 0 │ 0 │
└─────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
- 连接到 `chnode1` 并插入一行
INSERT INTO db1.table1 (id, column1) VALUES (1, 'abc');
- 连接到 `chnode2` 并插入一行
INSERT INTO db1.table1 (id, column1) VALUES (2, 'def');
- 连接到任一节点,`chnode1` 或 `chnode2`,您将只看到插入到该节点上的该表的行。例如,在 `chnode2` 上
SELECT * FROM db1.table1;
┌─id─┬─column1─┐
│ 2 │ def │
└────┴─────────┘
- 创建一个分布式表,查询两个节点上的所有分片。(在这个例子中,`rand()` 函数被设置为分片键,以便它随机分配每个插入)
CREATE TABLE db1.table1_dist ON CLUSTER cluster_2S_1R
(
`id` UInt64,
`column1` String
)
ENGINE = Distributed('cluster_2S_1R', 'db1', 'table1', rand())
┌─host────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ chnode2 │ 9000 │ 0 │ │ 1 │ 0 │
│ chnode1 │ 9000 │ 0 │ │ 0 │ 0 │
└─────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
- 连接到 `chnode1` 或 `chnode2`,并查询分布式表以查看两行。
SELECT * FROM db1.table1_dist;
┌─id─┬─column1─┐
│ 2 │ def │
└────┴─────────┘
┌─id─┬─column1─┐
│ 1 │ abc │
└────┴─────────┘