> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-fbfa8bee.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> 介绍开源 ClickHouse 使用建议的页面

# 开源版使用建议

<CloudNotSupportedBadge />

<Note>
  本页不适用于 [ClickHouse Cloud](https://clickhouse.com/cloud)。本文所述流程在 ClickHouse Cloud 服务中已实现自动化。
</Note>

<div id="cpu-scaling-governor">
  ## CPU 扩缩容调控器
</div>

始终使用 `performance` 扩缩容调控器。对于持续高负载场景，`on-demand` 扩缩容调控器的效果会差很多。

```bash theme={null}
$ echo 'performance' | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
```

<div id="cpu-limitations">
  ## CPU 限制
</div>

处理器可能会过热。使用 `dmesg` 查看 CPU 的时钟频率是否因过热而受到限制。
这种限制也可能由外部在数据中心层面设置。你可以在负载状态下使用 `turbostat` 对其进行监控。

<div id="ram">
  ## RAM
</div>

对于少量数据 (压缩后不超过约 200 GB) ，最佳做法是使用与数据量相当的内存。
对于大量数据以及需要处理交互式 (在线) 查询的场景，应配备合理容量的 RAM (128 GB 或更多) ，以便热点数据子集能够放入页缓存中。
即使每台 server 的数据量约为 50 TB，128 GB RAM 相比 64 GB 也能显著提升查询性能。

不要禁用 overcommit。`cat /proc/sys/vm/overcommit_memory` 的值应为 0 或 1。运行

```bash theme={null}
$ echo 0 | sudo tee /proc/sys/vm/overcommit_memory
```

使用 `perf top` 观察内核在内存管理上耗费的时间。
也无需分配永久大页。

<div id="using-less-than-16gb-of-ram">
  ### 使用少于 16GB RAM 的环境
</div>

建议的 RAM 容量为 32 GB 或更高。

如果您的系统 RAM 少于 16 GB，可能会遇到各种内存相关异常，因为默认设置并不适合这么小的内存容量。您可以在 RAM 较小的系统上使用 ClickHouse (最低可至 2 GB) ，但这类配置需要额外调优，而且只能以较低速率摄取数据。

当 ClickHouse 运行在少于 16GB RAM 的环境中时，我们建议采取以下措施：

* 在 `config.xml` 中调小标记缓存的大小。它最低可设置为 500 MB，但不能设为零。
* 将查询处理线程数降到 `1`。
* 将 `max_block_size` 调小到 `8192`。低至 `1024` 的值在实际中也仍然可行。
* 将 `max_download_threads` 调低到 `1`。
* 将 `input_format_parallel_parsing` 和 `output_format_parallel_formatting` 设为 `0`。
* 禁用向日志表写入，因为这会让后台 合并 任务持续预留 RAM 来执行日志表的 合并。禁用 `asynchronous_metric_log`、`metric_log`、`text_log`、`trace_log`。

附加说明：

* 要清除内存分配器缓存的内存，您可以运行 `SYSTEM JEMALLOC PURGE`
  命令。
* 我们不建议在低内存机器上使用 S3 或 Kafka 集成，因为它们需要大量内存用于缓冲区。

<div id="storage-subsystem">
  ## 存储子系统
</div>

如果预算允许，优先使用 SSD。
如果不允许，就使用 HDD。7200 RPM 的 SATA HDD 也够用。

相比少量外接磁盘柜的服务器，更应优先选择大量配备本地硬盘的服务器。
但如果是存放很少查询的归档数据，磁盘柜也可以。

<div id="raid">
  ## RAID
</div>

使用 HDD 时，可以将其组建为 RAID-10、RAID-5、RAID-6 或 RAID-50。
在 Linux 上，软件 RAID (使用 `mdadm`) 更合适。
创建 RAID-10 时，请选择 `far` 布局。
如果预算允许，请选择 RAID-10。

单独使用 LVM (不配合 RAID 或 `mdadm`) 是可以的，但用它来创建 RAID，或将它与 `mdadm` 组合使用，都是实践较少的方案，也更容易出错
(例如选择了错误的 chunk 大小、chunks 未对齐、选错 RAID 类型，或忘记清理磁盘) 。如果你对
使用 LVM 很有把握，那么使用它也没有问题。

如果磁盘数量超过 4 块，请使用 RAID-6 (首选) 或 RAID-50，而不要使用 RAID-5。
使用 RAID-5、RAID-6 或 RAID-50 时，务必增大 stripe\_cache\_size，因为默认值通常不是最佳选择。

```bash theme={null}
$ echo 4096 | sudo tee /sys/block/md2/md/stripe_cache_size
```

使用以下公式，根据设备数量和块大小计算精确值：`2 * num_devices * chunk_size_in_bytes / 4096`。

对于大多数 RAID 配置，64 KB 的块大小已经足够。clickhouse-server 的平均写入大小约为 1 MB (1024 KB) ，因此建议的 stripe 大小也为 1 MB。如有需要，可将块大小设置为 1 MB 除以 RAID 阵列中非奇偶校验磁盘的数量，以进一步优化，从而使每次写入都能并行分发到所有可用的非奇偶校验磁盘上。
切勿将块大小设置得过小或过大。

你可以在 SSD 上使用 RAID-0。
无论是否使用 RAID，都应始终使用复制来确保数据安全。

启用具有较长队列的 NCQ。对于 HDD，选择 mq-deadline 或 CFQ 调度器；对于 SSD，选择 noop。不要调低 `readahead` 设置。
对于 HDD，启用写缓存。

确保你的操作系统已为 NVME 和 SSD 磁盘启用 [`fstrim`](https://en.wikipedia.org/wiki/Trim_\(computing\)) (通常通过 cron 作业或 systemd 服务实现) 。

<div id="file-system">
  ## 文件系统
</div>

Ext4 是最可靠的选择。请将挂载选项设为 `noatime`。XFS 也同样适用。
大多数其他文件系统通常也都可以正常使用。

由于不支持硬链接，FAT-32 和 exFAT 不受支持。

不要使用压缩文件系统，因为 ClickHouse 自身就具备压缩能力，而且效果更好。
也不建议使用加密文件系统，因为 ClickHouse 提供了更好的内置加密功能。

虽然 ClickHouse 可以运行在 NFS 上，但这并不是最佳选择。

<div id="linux-kernel">
  ## Linux 内核
</div>

不要使用过时的 Linux 内核。

<div id="network">
  ## 网络
</div>

如果您使用 IPv6，请增大路由缓存的大小。
3.2 之前的 Linux 内核在 IPv6 实现方面存在许多问题。

如果条件允许，请至少使用 10 GB 网络。1 Gb 也能用，但在修补拥有数十 TB 数据的副本，或处理包含大量中间数据的分布式查询时，性能会差很多。

<div id="huge-pages">
  ## Huge Pages
</div>

始终将 透明大页 (THP) 设置为 `madvise`。在较旧的内核 (5.9 之前) 中，将 THP 设为 `always` 可能会导致明显的性能下降——内核会花费大量时间进行内存碎片整理，尤其是在 RAM 达到 64 GB 以上的系统上。内核 5.9 引入了主动合并整理机制，对 THP 的处理改进了很多；但如果 THP 设为 `always`，ClickHouse 仍会在启动时发出警告，因此无论内核版本如何，仍推荐使用 `madvise`。

```bash theme={null}
$ echo 'madvise' | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
```

如果要永久修改透明大页设置，请编辑 `/etc/default/grub`，并在 `GRUB_CMDLINE_LINUX_DEFAULT` 选项中添加 `transparent_hugepage=madvise`：

```bash theme={null}
$ GRUB_CMDLINE_LINUX_DEFAULT="transparent_hugepage=madvise ..."
```

之后，运行 `sudo update-grub` 命令，然后重启使更改生效。

<div id="hypervisor-configuration">
  ## 虚拟机监控程序配置
</div>

如果你使用 OpenStack，请设置

```ini theme={null}
cpu_mode=host-passthrough
```

在 `nova.conf` 中。

如果使用 libvirt，请设置

```xml theme={null}
<cpu mode='host-passthrough'/>
```

在 XML 配置中。

这对 ClickHouse 通过 `cpuid` 指令获取正确信息非常重要。
否则，如果虚拟机监控程序运行在较旧的 CPU 型号上，可能会因 `Illegal instruction` 而崩溃。

<div id="zookeeper">
  ## ClickHouse Keeper 和 ZooKeeper
</div>

对于 ClickHouse 集群，建议使用 ClickHouse Keeper 来替代 ZooKeeper。参见 [ClickHouse Keeper](/zh/guides/oss/deployment-and-scaling/keeper/index) 文档。

如果你想继续使用 ZooKeeper，最好使用较新的 ZooKeeper 版本——3.4.9 或更高版本。稳定版 Linux 发行版中自带的版本可能已经过期。

绝不要使用手写脚本在不同的 ZooKeeper 集群之间传输数据，因为对于 sequential 节点，这样做会导致结果不正确。出于同样的原因，也不要使用 "zkcopy" 工具：[https://github.com/ksprojects/zkcopy/issues/15](https://github.com/ksprojects/zkcopy/issues/15)

如果你想将现有的 ZooKeeper 集群拆分为两个，正确的方法是先增加其副本数量，然后再将其重新配置为两个独立的集群。

在测试环境中，或者在摄取速率较低的环境中，你可以让 ClickHouse Keeper 与 ClickHouse 运行在同一台服务器上。
对于生产环境，我们建议为 ClickHouse 和 ZooKeeper/Keeper 使用独立的服务器，或者将 ClickHouse 文件和 Keeper 文件放在不同的磁盘上。因为 ZooKeeper/Keeper 对磁盘延迟非常敏感，而 ClickHouse 可能会占用所有可用的系统资源。

你可以在 ZooKeeper 集群中使用 observer 节点，但 ClickHouse 服务器不应与 observer 交互。

不要更改 `minSessionTimeout` 设置，过大的值可能会影响 ClickHouse 重启时的稳定性。

在默认设置下，ZooKeeper 就像一颗定时炸弹：

> 使用默认配置时，ZooKeeper server 不会删除旧 snapshots 和 logs 文件 (参见 `autopurge`) ，而这属于 operator 的职责。

必须拆除这颗炸弹。

下面的 ZooKeeper (3.5.1) 配置用于大型生产环境：

zoo.cfg:

```bash theme={null}
# http://hadoop.apache.org/zookeeper/docs/current/zookeeperAdmin.html

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
# This value is not quite motivated
initLimit=300
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=10

maxClientCnxns=2000

# It is the maximum value that client may request and the server will accept.
# It is Ok to have high maxSessionTimeout on server to allow clients to work with high session timeout if they want.
# But we request session timeout of 30 seconds by default (you can change it with session_timeout_ms in ClickHouse config).
maxSessionTimeout=60000000
# the directory where the snapshot is stored.
dataDir=/opt/zookeeper/{{ '{{' }} cluster['name'] {{ '}}' }}/data
# Place the dataLogDir to a separate physical disc for better performance
dataLogDir=/opt/zookeeper/{{ '{{' }} cluster['name'] {{ '}}' }}/logs

autopurge.snapRetainCount=10
autopurge.purgeInterval=1

# To avoid seeks ZooKeeper allocates space in the transaction log file in
# blocks of preAllocSize kilobytes. The default block size is 64M. One reason
# for changing the size of the blocks is to reduce the block size if snapshots
# are taken more often. (Also, see snapCount).
preAllocSize=131072

# Clients can submit requests faster than ZooKeeper can process them,
# especially if there are a lot of clients. To prevent ZooKeeper from running
# out of memory due to queued requests, ZooKeeper will throttle clients so that
# there is no more than globalOutstandingLimit outstanding requests in the
# system. The default limit is 1000.
# globalOutstandingLimit=1000

# ZooKeeper logs transactions to a transaction log. After snapCount transactions
# are written to a log file a snapshot is started and a new transaction log file
# is started. The default snapCount is 100000.
snapCount=3000000

# If this option is defined, requests will be will logged to a trace file named
# traceFile.year.month.day.
#traceFile=

# Leader accepts client connections. Default value is "yes". The leader machine
# coordinates updates. For higher update throughput at thes slight expense of
# read throughput the leader can be configured to not accept clients and focus
# on coordination.
leaderServes=yes

standaloneEnabled=false
dynamicConfigFile=/etc/zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }}/conf/zoo.cfg.dynamic
```

Java 版本：

```text theme={null}
openjdk 11.0.5-shenandoah 2019-10-15
OpenJDK Runtime Environment (build 11.0.5-shenandoah+10-adhoc.heretic.src)
OpenJDK 64-Bit Server VM (build 11.0.5-shenandoah+10-adhoc.heretic.src, mixed mode)
```

JVM 参数：

```bash theme={null}
NAME=zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }}
ZOOCFGDIR=/etc/$NAME/conf

# TODO 这段代码写得很不优雅
# 如何确定需要哪些 jar 包？
# 似乎 log4j 要求 log4j.properties 文件必须在 classpath 中
CLASSPATH="$ZOOCFGDIR:/usr/build/classes:/usr/build/lib/*.jar:/usr/share/zookeeper-3.6.2/lib/audience-annotations-0.5.0.jar:/usr/share/zookeeper-3.6.2/lib/commons-cli-1.2.jar:/usr/share/zookeeper-3.6.2/lib/commons-lang-2.6.jar:/usr/share/zookeeper-3.6.2/lib/jackson-annotations-2.10.3.jar:/usr/share/zookeeper-3.6.2/lib/jackson-core-2.10.3.jar:/usr/share/zookeeper-3.6.2/lib/jackson-databind-2.10.3.jar:/usr/share/zookeeper-3.6.2/lib/javax.servlet-api-3.1.0.jar:/usr/share/zookeeper-3.6.2/lib/jetty-http-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jetty-io-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jetty-security-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jetty-server-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jetty-servlet-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jetty-util-9.4.24.v20191120.jar:/usr/share/zookeeper-3.6.2/lib/jline-2.14.6.jar:/usr/share/zookeeper-3.6.2/lib/json-simple-1.1.1.jar:/usr/share/zookeeper-3.6.2/lib/log4j-1.2.17.jar:/usr/share/zookeeper-3.6.2/lib/metrics-core-3.2.5.jar:/usr/share/zookeeper-3.6.2/lib/netty-buffer-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-codec-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-common-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-handler-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-resolver-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-transport-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-transport-native-epoll-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/netty-transport-native-unix-common-4.1.50.Final.jar:/usr/share/zookeeper-3.6.2/lib/simpleclient-0.6.0.jar:/usr/share/zookeeper-3.6.2/lib/simpleclient_common-0.6.0.jar:/usr/share/zookeeper-3.6.2/lib/simpleclient_hotspot-0.6.0.jar:/usr/share/zookeeper-3.6.2/lib/simpleclient_servlet-0.6.0.jar:/usr/share/zookeeper-3.6.2/lib/slf4j-api-1.7.25.jar:/usr/share/zookeeper-3.6.2/lib/slf4j-log4j12-1.7.25.jar:/usr/share/zookeeper-3.6.2/lib/snappy-java-1.1.7.jar:/usr/share/zookeeper-3.6.2/lib/zookeeper-3.6.2.jar:/usr/share/zookeeper-3.6.2/lib/zookeeper-jute-3.6.2.jar:/usr/share/zookeeper-3.6.2/lib/zookeeper-prometheus-metrics-3.6.2.jar:/usr/share/zookeeper-3.6.2/etc"

ZOOCFG="$ZOOCFGDIR/zoo.cfg"
ZOO_LOG_DIR=/var/log/$NAME
USER=zookeeper
GROUP=zookeeper
PIDDIR=/var/run/$NAME
PIDFILE=$PIDDIR/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
JAVA=/usr/local/jdk-11/bin/java
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
JMXLOCALONLY=false
JAVA_OPTS="-Xms{{ '{{' }} cluster.get('xms','128M') {{ '}}' }} \
    -Xmx{{ '{{' }} cluster.get('xmx','1G') {{ '}}' }} \
    -Xlog:safepoint,gc*=info,age*=debug:file=/var/log/$NAME/zookeeper-gc.log:time,level,tags:filecount=16,filesize=16M
    -verbose:gc \
    -XX:+UseG1GC \
    -Djute.maxbuffer=8388608 \
    -XX:MaxGCPauseMillis=50"
```

Salt 的初始化：

```text theme={null}
description "zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }} centralized coordination service"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

limit nofile 8192 8192

pre-start script
    [ -r "/etc/zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }}/conf/environment" ] || exit 0
    . /etc/zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }}/conf/environment
    [ -d $ZOO_LOG_DIR ] || mkdir -p $ZOO_LOG_DIR
    chown $USER:$GROUP $ZOO_LOG_DIR
end script

script
    . /etc/zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }}/conf/environment
    [ -r /etc/default/zookeeper ] && . /etc/default/zookeeper
    if [ -z "$JMXDISABLE" ]; then
        JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY"
    fi
    exec start-stop-daemon --start -c $USER --exec $JAVA --name zookeeper-{{ '{{' }} cluster['name'] {{ '}}' }} \
        -- -cp $CLASSPATH $JAVA_OPTS -Dzookeeper.log.dir=${ZOO_LOG_DIR} \
        -Dzookeeper.root.logger=${ZOO_LOG4J_PROP} $ZOOMAIN $ZOOCFG
end script
```

<div id="antivirus-software">
  ## 防病毒软件
</div>

如果您使用防病毒软件，请将其配置为跳过存放 ClickHouse 数据文件的文件夹 (`/var/lib/clickhouse`) ，否则可能会导致性能下降，并在数据摄取和后台合并期间出现意外错误。

<div id="related-content">
  ## 相关内容
</div>

* [刚开始使用 ClickHouse？这里有 13 个“致命误区”以及如何避免它们](https://clickhouse.com/blog/common-getting-started-issues-with-clickhouse)
