跳至主要内容

使用建议

注意

此页面不适用于 ClickHouse Cloud。此处记录的过程在 ClickHouse Cloud 服务中已自动化。

CPU 缩放管理程序

始终使用 performance 缩放管理程序。on-demand 缩放管理程序在持续高需求的情况下效果要差得多。

$ echo 'performance' | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

CPU 限制

处理器可能会过热。使用 dmesg 查看 CPU 的时钟频率是否因过热而受到限制。该限制也可以在数据中心级别进行外部设置。你可以在负载下使用 turbostat 监控它。

RAM

对于少量数据(最多约 200 GB 压缩数据),最好使用与数据量一样多的内存。对于大量数据以及处理交互式(在线)查询时,你应使用合理的 RAM 量(128 GB 或更多),以便热点数据子集适合页面缓存。即使对于每个服务器约 50 TB 的数据量,使用 128 GB 的 RAM 与 64 GB 相比,查询性能也会有显著提高。

不要禁用超额分配。cat /proc/sys/vm/overcommit_memory 的值应为 0 或 1。运行

$ echo 0 | sudo tee /proc/sys/vm/overcommit_memory

使用 perf top 观察内核在内存管理方面花费的时间。永久大页面也不需要分配。

使用少于 16GB 的 RAM

建议的 RAM 量为 32 GB 或更多。

如果你的系统 RAM 少于 16 GB,你可能会遇到各种内存异常,因为默认设置与这种内存量不匹配。你可以在 RAM 量较小的系统(低至 2 GB)中使用 ClickHouse,但这些设置需要额外的调整,并且只能以较低的速度摄取数据。

在 RAM 少于 16GB 的情况下使用 ClickHouse 时,我们建议执行以下操作

  • 降低 config.xml 中标记缓存的大小。它可以设置低至 500 MB,但不能设置为零。
  • 将查询处理线程的数量降低到 1
  • max_block_size 降低到 8192。低至 1024 的值仍然是可行的。
  • max_download_threads 降低到 1
  • input_format_parallel_parsingoutput_format_parallel_formatting 设置为 0

其他说明

  • 要刷新内存分配器缓存的内存,可以运行 SYSTEM JEMALLOC PURGE 命令。
  • 我们不建议在内存不足的机器上使用 S3 或 Kafka 集成,因为它们需要大量的内存用于缓冲。

存储子系统

如果你的预算允许你使用 SSD,则使用 SSD。否则,使用 HDD。SATA HDD 7200 RPM 即可。

优先考虑使用大量带本地硬盘的服务器,而不是少量带附加磁盘架的服务器。但对于存储具有较少查询的归档,磁盘架可以使用。

RAID

使用 HDD 时,你可以将它们组合成 RAID-10、RAID-5、RAID-6 或 RAID-50。对于 Linux,软件 RAID 更好(使用 mdadm)。创建 RAID-10 时,选择 far 布局。如果你的预算允许,选择 RAID-10。

单独的 LVM(不使用 RAID 或 mdadm)可以,但与它一起创建 RAID 或将它与 mdadm 组合起来是一个鲜为人知的选项,并且出错的可能性更大(选择错误的块大小;块不对齐;选择错误的 RAID 类型;忘记清理磁盘)。如果你对使用 LVM 有信心,那么可以使用它。

如果你有超过 4 个磁盘,请使用 RAID-6(首选)或 RAID-50,而不是 RAID-5。使用 RAID-5、RAID-6 或 RAID-50 时,始终增加 stripe_cache_size,因为默认值通常不是最佳选择。

$ 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),因此建议的条带大小也是 1 MB。如果需要,可以在设置为 1 MB 除以 RAID 数组中非奇偶校验磁盘数量的情况下优化块大小,以便每个写入在所有可用的非奇偶校验磁盘上并行化。不要将块大小设置得太小或太大。

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

启用具有长队列的 NCQ。对于 HDD,选择 mq-deadline 或 CFQ 调度程序,对于 SSD,选择 noop。不要降低“readahead”设置。对于 HDD,启用写入缓存。

确保在你的操作系统中为 NVME 和 SSD 磁盘启用了 fstrim(通常它通过 cronjob 或 systemd 服务实现)。

文件系统

Ext4 是最可靠的选择。设置挂载选项 noatime。XFS 也效果很好。大多数其他文件系统也应该可以正常工作。

FAT-32 和 exFAT 不支持,因为缺少硬链接。

不要使用压缩文件系统,因为 ClickHouse 自己进行了更好的压缩。也不建议使用加密文件系统,因为你可以在 ClickHouse 中使用内置加密,它更好。

虽然 ClickHouse 可以在 NFS 上运行,但这不是最好的主意。

Linux 内核

不要使用过时的 Linux 内核。

网络

如果你使用的是 IPv6,请增加路由缓存的大小。3.2 之前的 Linux 内核在 IPv6 实现方面存在大量问题。

如果可能,请使用至少 10 GB 的网络。1 Gb 也可以,但对于使用数十 TB 数据修补副本,或者对于处理具有大量中间数据的分布式查询,效果要差得多。

大页面

如果你使用的是旧的 Linux 内核,请禁用透明大页面。它会干扰内存分配器,从而导致性能大幅下降。在较新的 Linux 内核上,透明大页面可以正常工作。

$ echo 'madvise' | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

如果你想永久修改透明大页面设置,请编辑 /etc/default/grub 以将 transparent_hugepage=madvise 添加到 GRUB_CMDLINE_LINUX_DEFAULT 选项中

$ GRUB_CMDLINE_LINUX_DEFAULT="transparent_hugepage=madvise ..."

之后,运行 sudo update-grub 命令,然后重新启动以使更改生效。

虚拟机管理程序配置

如果你使用的是 OpenStack,请设置

cpu_mode=host-passthrough

nova.conf 中。

如果你使用的是 libvirt,请设置

<cpu mode='host-passthrough'/>

在 XML 配置中。

这对于 ClickHouse 能够使用 cpuid 指令获取正确的信息很重要。否则,当虚拟机管理程序在旧的 CPU 模型上运行时,你可能会遇到 Illegal instruction 崩溃。

ClickHouse Keeper 和 ZooKeeper

建议使用 ClickHouse Keeper 替换 ClickHouse 集群的 ZooKeeper。有关 ClickHouse Keeper 的文档,请参阅。

如果你想继续使用 ZooKeeper,那么最好使用最新版本的 ZooKeeper - 3.4.9 或更高版本。稳定版 Linux 发行版中的版本可能已过时。

您永远不应该使用手动编写的脚本在不同的 ZooKeeper 集群之间传输数据,因为对于顺序节点来说,结果将不正确。由于相同的原因,也不要使用“zkcopy”工具:https://github.com/ksprojects/zkcopy/issues/15

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

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

您可以在一个集群中拥有 ZooKeeper 观察者,但 ClickHouse 服务器不应该与观察者交互。

不要更改 minSessionTimeout 设置,较大的值可能会影响 ClickHouse 重启的稳定性。

在默认设置下,ZooKeeper 就像一枚定时炸弹

在使用默认配置(请参阅 autopurge)时,ZooKeeper 服务器不会删除旧快照和日志中的文件,这是操作员的责任。

这枚炸弹必须解除。

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

zoo.cfg

# https://hadoop.apache.ac.cn/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 版本

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 参数

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

# TODO this is really ugly
# How to find out, which jars are needed?
# seems, that log4j requires the log4j.properties file to be in the 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 初始化

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

杀毒软件

如果您使用杀毒软件,请将其配置为跳过包含 ClickHouse 数据文件的文件夹 (/var/lib/clickhouse),否则性能可能会降低,并且您可能会在数据摄入和后台合并期间遇到意外错误。