> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

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

# 开源版使用建议

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            ClickHouse Cloud 不支持此功能
        </div>;
};

<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](/docs/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)
