鲲鹏+麒麟V10源码编译ClickHouse 21.8.14部署指南 简介面向在华为鲲鹏920aarch64与麒麟V10国产化环境中部署OLAP数据库的运维与开发人员这份ClickHouse 21.8.14编译安装包针对ARM平台与国产操作系统适配、依赖兼容和快速落地等痛点整理可用于信创项目验证与内部分析平台搭建。压缩包共20个文件约115.69MB含一键安装与卸载脚本、服务单元文件、config.xml和users.xml配置模板以及clickhouse-server、client、keeper、benchmark等核心可执行组件覆盖服务端运行、客户端连接、数据导入和性能测试等常见场景省去从源码适配编译的重复工作。已有2150人学习下载说明其在国产化数据库部署场景中具有一定参考价值。读者可据此在鲲鹏与麒麟V10环境完成服务安装、参数调整与基础运维并借助包内组件开展查询验证、性能压测和日常管理适合需要快速搭建自主可控分析环境的团队参考。1. 为什么在鲲鹏 麒麟 V10 上非要从源码编译 ClickHouse 21.8.14上周又有人在群里贴出package architecture (amd64) does not match system (arm64)然后把官方 x86 的clickhouse-common-staticdeb 包直接往鲲鹏机器上装。麒麟 V10 服务器版是标准 aarch64glibc 停在 2.28而 ClickHouse 官方给出的 aarch64 预编译产物往往是在更新的发行版上构建的运行时会直接报某个GLIBC_2.29 not found。这就是这份安装包的由来把 ClickHouse 21.8.14 这个 LTS 收尾版本在鲲鹏 麒麟 V10 的原生环境里从源码编出来得到一份能在同类机器上直接铺开的二进制。21.8.14 被锁死是有原因的——分布式表引擎的行为、物化视图的刷新语义、客户端协议的握手细节都在这个版本上跑过完整回归换版本意味着重跑一遍业务 SQL。适合两类人一是必须在国产 ARM 服务器上部署 ClickHouse 又没法动版本的运维二是想搞清楚 clickhouse 在 aarch64 上到底依赖哪些 contrib、哪些开关必须关掉的开发者。2. 编译前的地基工具链、依赖与内存预算在 x86 上编 ClickHouse 是件体力活在 ARM 上编是体力活加算术题。这台机器要同时扛住 GCC 自身的构建、ClickHouse contrib 里几十个第三方库的编译以及最后那个把上百个静态库塞进单一可执行文件的链接过程。开工前先把三件事定死编译器版本、依赖清单、内存水位。2.1 麒麟 V10 自带的 GCC 8.3 为什么不达标麒麟 V10 默认源里的gcc是 8.3.1这个版本能编出内核模块但编不了 ClickHouse 21.8。21.8 的CMakeLists.txt把CMAKE_CXX_STANDARD定在 20代码里已经用上了 concepts、std::span、三路比较运算符这些 GCC 10 之后才完整实现的东西。用 8.3 硬上的结果不是报错一行而是编到某个 contrib 头文件时抛出几百行模板展开错误根本定位不到业务代码。先查源里有没有现成的 toolset这是最省事的路# 麒麟 V10 的源里有时会带 gcc-toolset先看一眼再决定要不要自己编 yum list available | grep -Ei gcc-toolset|devtoolset|gcc1[0-9]有gcc-toolset-10就直接装用scl enable gcc-toolset-10 bash进环境。没有的话只能自己编一个 GCC 10.3这一步在 32 核鲲鹏上大概一小时出头# 只编 C/C 前端并关掉 bootstrap能砍掉一半以上的构建时间 tar xf gcc-10.3.0.tar.xz cd gcc-10.3.0 ./contrib/download_prerequisites mkdir build cd build ../configure --prefix/opt/gcc-10.3 \ --enable-languagesc,c \ --disable-multilib \ --disable-bootstrap \ --with-system-zlib make -j 16 make install--disable-multilib只产出 64 位库aarch64 上本来也没有 32 位需求--disable-bootstrap跳过三阶段自举编译器自身的正确性由官方发布包保证没必要在服务器上重复验证。装完把/opt/gcc-10.3/lib64加到LD_LIBRARY_PATH否则后续 cmake 的编译器探测会因为找不到libgcc_s.so.1而失败。CMake 版本同样要看一眼21.8 要求 3.16 以上麒麟 V10 自带的可能是 3.15 或者干脆只有cmake3这个名字。低于 3.16 就自己编一个 3.20源码包不大十分钟的事。ninja 更简单pip3 install ninja或者从源码编都行装完确认ninja --version能输出。2.2 依赖清单与离线安装ClickHouse 21.8 的 contrib 已经把大部分第三方库boost、protobuf、abseil、icu、re2、jemalloc、zstd收进源码树编译时一起构建所以系统层面真正要装的包不多但缺一个就卡住。下面这张表是实测必须的包名用途是否必须cmake3.16生成构建系统必须ninja-build实际执行编译必须gcc / g10C20 编译器必须git拉取源码与子模块必须python3部分 contrib 的代码生成脚本必须ccache二次编译加速强烈建议openssl-devel若关闭内置 SSL 才需要可选zlib-devel系统 zlib 与内置二选一可选lld替代 ld 链接内存占用更低建议numactl后续 NUMA 绑核调优部署阶段用麒麟 V10 是 rpm 体系离线机器上先把这些包和它们的依赖用yumdownloader --resolve拖到一个目录里再yum localinstall *.rpm一次性装。这里有个容易忽略的点ccache在某些麒麟源里叫ccache但版本很老3.x而 ClickHouse 的 cmake 模块对 4.x 的统计输出格式有依赖版本太老会导致-DENABLE_CCACHEON之后编译报参数不识别。看到 ccache 是 3.x直接用源码编 4.6 以上。Rust 是另一个隐藏依赖。21.8 里 BLAKE3 的实现走的是 Rust 组件contrib 目录下有rust-toolchain文件写死了版本号。不要图省事装系统源里的 rust版本几乎必然不匹配用 rustup 按那个文件里的版本装或者直接读文件内容指定# 版本号以源码树里的 contrib/rust/rust-toolchain 为准不要拍脑袋 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source $HOME/.cargo/env rustc --version cargo --version离线环境下 rustup 也能用提前在有网机器上把 toolchain 目录整个打 tar 拷过去设RUSTUP_HOME和CARGO_HOME指向解压位置即可。2.3 内存与磁盘的硬性预算这是整个编译过程里最容易翻车的地方也是我第一次编时踩得最惨的坑。ClickHouse 21.8 完整源码加子模块大约 3.5GBbuild目录在编到一半时膨胀到 40GB 以上如果开着调试信息能到 60GB。磁盘至少留 80GB 空闲别信50G 够了这种说法。内存按阶段算阶段单进程峰值说明contrib 编译1.52.5GB并行数 × 单进程-j 16 时峰值可达 30GB主工程编译23GB单个 .cpp 编译单元模板重的文件更高链接816GB单进程使用 ld 时更高lld 可降到 6GB 左右一台 32 核 64GB 的鲲鹏 920 机器编 contrib 时可以放心-j 16到了主工程阶段降到-j 12链接阶段必须-j 1否则两个链接任务同时跑oom-killer 会毫不留情地把 g 干掉报出来的信息只有一行ninja: build stopped: subcommand failed.看不出是内存问题。加到 8GB swap 能兜住一部分但 swap 上的链接速度会慢到让人怀疑人生能加内存就加内存。还有一项vm.max_map_count默认 65530编 jemalloc 和后续压测时会撞上提前调到 262144。3. 从源码到单二进制21.8.14 的构建参数与分步命令地基打完就进正题。这一章的命令都可以直接复制粘贴但要按顺序走中间任何一步跳过去后面都会以奇怪的方式报错。3.1 拉取源码与子模块21.8.14 对应的 tag 命名规则是v21.8.14.x-lts后面的小版本号我不写死先列出来再切# 先确认实际 tag不同小版本的补丁号不固定 git ls-remote --tags https://github.com/ClickHouse/ClickHouse.git v21.8.14* # 切到 LTS 分支的对应 tag递归拉子模块depth 1 减少传输量 git clone --recursive --depth 1 \ --branch v21.8.14.5-lts \ https://github.com/ClickHouse/ClickHouse.git cd ClickHouse # 子模块有遗漏时补拉一次contrib 少一个目录 cmake 会直接停 git submodule update --init --recursive --depth 1--recursive是关键contrib 目录下几十个子模块如果没拉全cmake 配置阶段会报Add subdirectory ... which is not an existing directory看到这个错误别去改 CMakeLists回去补 submodule。离线机器上的做法是在有网环境完整 clone 一次git clean -xdf清掉构建残留然后tar czf clickhouse-src-21.8.14.tar.gz ClickHouse/打包拷过去。注意不要用git archive它不包含子模块内容解压出来缺一半。3.2 CMake 配置ARM64 下要显式关掉的那些开关这一条命令是整个编译的核心参数改错一个要么编到一半失败要么编出来体积翻倍、内存吃满mkdir -p build cd build cmake .. \ -G Ninja \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILER/opt/gcc-10.3/bin/gcc \ -DCMAKE_CXX_COMPILER/opt/gcc-10.3/bin/g \ -DCMAKE_CXX_FLAGS-marcharmv8-a -O2 \ -DCMAKE_INSTALL_PREFIX/usr \ -DENABLE_TESTSOFF \ -DENABLE_UTILSOFF \ -DENABLE_EMBEDDED_COMPILEROFF \ -DUSE_INTERNAL_SSL_LIBRARY1 \ -DSPLIT_SHARED_LIBRARIESOFF \ -DENABLE_CCACHEON \ -DUSE_LLDON逐个说清楚为什么要这么设-DENABLE_EMBEDDED_COMPILEROFF是这份配置里最值钱的一行。它控制的是内置的 LLVM JIT 编译器打开后会连带编整个 LLVM在 ARM 上这一项能吃掉两小时以上编译内存峰值翻倍而它只服务于compile表达式和部分聚合函数的即时编译。生产环境里用不到这个特性关掉没有副作用。-DENABLE_TESTSOFF和-DENABLE_UTILSOFF分别跳过单元测试和 clickhouse-utils 工具集。测试用例在 ARM 上有一批会超时失败卡在ninja的默认目标里很烦utils 是些小的辅助工具用不上就不编。-DUSE_INTERNAL_SSL_LIBRARY1让 ClickHouse 用自己 contrib 里的 BoringSSL而不是系统 openssl。麒麟 V10 自带的 openssl 是 1.1.1 系列ABI 上没问题但混用系统库和内置库在交叉链接时容易出符号冲突全内置最省心。代价是编译时间多一点。-DCMAKE_CXX_FLAGS-marcharmv8-a显式指定基线指令集。不要写-marchnative鲲鹏 920 不支持 SVE而某些 GCC 版本在native下会探测出一些边角特性编出来的二进制换一台机器就跑不了失去安装包的意义。-DUSE_LLDON需要系统装了 lld它把链接阶段的内存峰值从 16GB 降到 6GB 左右在内存紧张的机器上是救命选项。如果机器上没装 lld把这行去掉即可别硬留着让 cmake 报错。配置跑完检查输出里的三行关键信息编译器版本是不是 10.x、CMAKE_SYSTEM_PROCESSOR是不是 aarch64、Using internal SSL是不是 ON。有一项不对就rm -rf *重新配置别在错误的配置上继续编。3.3 ninja 编译与链接阶段的资源控制配置通过后开始编分两段走别一条命令到底# 第一段主工程控制在 12 并发避免 32 核全开时内存打满 ninja -j 12 clickhouse # 如果中途被打断重新进来时先看还有多少任务 ninja -j 12 -n clickhouse | wc -lclickhouse这个 target 产出的是合并后的单二进制server 和 client 都在里面靠 argv[0] 区分行为。这也意味着任何一处改动都会触发重新链接链接一次在鲲鹏上要二十分钟左右所以改代码调试的效率远不如改配置。编译过程中盯住内存# 另开一个窗口每两秒看一眼剩余内存和 swap 使用 while true; do free -g | awk NR2{print $2G total, $7G avail}; sleep 2; done可用内存掉到 4GB 以下就CtrlC把-j降下来重新跑ninja 是增量的已经编完的目标不会重来。ccache 的命中率在第一次编译时是 0第二次改动少量文件后能到 70% 以上用ccache -s看如果一直是 0 说明CCACHE_DIR空间不够或者头文件路径里有时间戳检查ccache -p | grep base_dir的配置。编译时长参考32 核鲲鹏 920、-j 12、关掉 embedded compiler 的情况下从零开始大约 4 到 6 小时。如果超过 8 小时还没完多半是某个 contrib 在反复重试下载或者卡在 rust 编译上看build/CMakeFiles/CMakeOutput.log和 ninja 的当前行。3.4 产物核验与体积裁剪编完之后别急着拷走先在本机验证三件事# 1. 版本与架构 ./programs/clickhouse --version file ./programs/clickhouse # 2. 动态库依赖确认没有指向 /opt/gcc-10.3 的路径 ldd ./programs/clickhouse | grep -E gcc|not found # 3. 符号表体积Release 构建理论上已经 strip 过 ls -lh ./programs/clickhousefile的输出必须是ELF 64-bit LSB executable, ARM aarch64。ldd里如果出现/opt/gcc-10.3/lib64/libstdc.so.6说明编译器自带的 libstdc 被静态链接进去了或者被动态引用前一种情况没问题后一种情况换到别的机器上会找不到库。解决方式是在 cmake 里加-DCMAKE_EXE_LINKER_FLAGS-static-libstdc -static-libgcc重新链接。产物体积正常在 1.21.8GB 之间如果超过 2.5GB说明调试符号没去掉手动strip --strip-unneeded ./programs/clickhouse压到 1GB 以内注意先备份未 strip 的版本后续出问题要靠它看栈。4. 打包与部署在麒麟 V10 上做成可复制的服务单二进制躺在 build 目录里没有意义要让它变成一份能拷到十台机器上直接跑的东西。ClickHouse 的官方打包脚本能产出 rpm但它依赖 rpm-build 和一堆宏定义在麒麟上经常卡在打包阶段。一线更常见的做法是手工铺目录加 systemd 单元可控性更高。4.1 目录布局与配置改写先建用户和目录结构和官方包的布局保持一致后续升级替换二进制时不用改路径# 专用用户禁止登录 useradd -r -s /sbin/nologin -M clickhouse # 标准目录布局 mkdir -p /etc/clickhouse-server/{config.d,users.d} mkdir -p /var/lib/clickhouse/{data,tmp,user_files,format_schemas} mkdir -p /var/log/clickhouse-server chown -R clickhouse:clickhouse /var/lib/clickhouse /var/log/clickhouse-server # 二进制与软链 install -m 755 programs/clickhouse /usr/bin/clickhouse ln -sf /usr/bin/clickhouse /usr/bin/clickhouse-server ln -sf /usr/bin/clickhouse /usr/bin/clickhouse-client配置文件从源码树的programs/server/config.xml和programs/server/users.xml拷过来然后改这几处其余保持默认配置项默认值麒麟上的建议值原因listen_host::10.0.0.0或具体内网 IP默认只监听本地远程连不上path/var/lib/clickhouse/同默认若数据盘挂别处则改数据根目录tmp_path/var/lib/clickhouse/tmp/指到数据盘大查询落盘logger.leveltraceinformationtrace 日志量在压测时能撑爆磁盘max_server_memory_usage0自动 90%按机器内存手写与同机其他服务共存时防抢内存users.xml里至少给default用户设密码并限制max_memory_usage不要留着空密码直接上线。config.d和users.d两个目录的作用是放覆盖片段后续改配置写小文件就行不用动主配置这一点在批量部署时特别有用。4.2 systemd 单元与内核参数麒麟 V10 是 systemd 体系写一个单元文件# /etc/systemd/system/clickhouse-server.service [Unit] DescriptionClickHouse Server (21.8.14 aarch64) Afternetwork.target [Service] Typesimple Userclickhouse Groupclickhouse Restartalways RestartSec30 LimitNOFILE500000 LimitNPROC500000 ExecStart/usr/bin/clickhouse-server --config-file/etc/clickhouse-server/config.xml ExecReload/bin/kill -HUP $MAINPID [Install] WantedBymulti-user.targetLimitNOFILE500000是必须的ClickHouse 每个 part 都持有文件句柄默认的 1024 在数据量上来之后会直接报Too many open files服务起不来或者查询全挂。Restartalways配合RestartSec30避免崩溃循环把机器拖死。内核参数写到/etc/sysctl.d/99-clickhouse.conf# 内存映射区域数jemalloc 和大表扫描都需要 vm.max_map_count 262144 # 允许过量提交ClickHouse 申请内存的策略比较激进 vm.overcommit_memory 1 # 连接队列客户端多的时候不够用会丢握手 net.core.somaxconn 4096sysctl -p /etc/sysctl.d/99-clickhouse.conf生效。这几项在麒麟 V10 上默认值都偏保守尤其是vm.max_map_count不改的话服务运行几天后会在日志里看到 mmap 失败的报错。4.3 启动自检与最小可用验证启动之后不要只看systemctl status是不是绿的逐层验证systemctl daemon-reload systemctl enable --now clickhouse-server sleep 5 # 版本、主机名、运行时长 clickhouse-client --query SELECT version(), hostName(), uptime() # 服务自身资源占用 clickhouse-client --query SELECT metric, value FROM system.asynchronous_metrics WHERE metric IN (MemoryTracking,NumberOfDatabases)然后再跑一个真正落盘的写入链路确认数据目录权限和 part 合并都正常-- 建表、写数、查数三步都过才说明部署完整 CREATE TABLE default.smoke_test (id UInt64, ts DateTime, msg String) ENGINE MergeTree ORDER BY id; INSERT INTO default.smoke_test SELECT number, now(), concat(row-, toString(number)) FROM numbers(100000); SELECT count(), max(id) FROM default.smoke_test;count()返回 100000 且max(id)是 99999说明写入、part 落盘、查询链路全通。如果卡在建表阶段报Cannot create directory是/var/lib/clickhouse的属主不对如果写入报Memory limit exceeded是users.xml里的配额设得太小。日志目录下应该出现clickhouse-server.log和clickhouse-server.err.log前者记录启动时的配置加载情况后者为空才算干净。启动时间超过 30 秒要留意通常是path目录下有太多旧 part 在做启动扫描。5. 避坑与排查五个高频翻车点这一节是我在这套环境上反复折腾攒下来的按出现频率排序每条都写清楚现象、原因和解决路径遇到问题时对着翻。第一个坑链接阶段被 OOM Killer 静默杀掉。现象是 ninja 跑到最后一步突然输出ninja: build stopped: subcommand failed.没有任何编译错误dmesg -T | tail里能看到Out of memory: Killed process ... (ld)。原因是链接 ClickHouse 单二进制时ld 要把上百个静态库拉进内存做符号解析峰值能到 16GB而 ninja 默认按 CPU 核数并行两个链接任务一撞就爆。解决是链接阶段强制-j 1或者改用-DUSE_LLDONlld 的峰值内存只有 ld 的三分之一左右。已经编到一半的话不用重来直接ninja -j 1 clickhouse会从链接阶段继续。第二个坑编译机 glibc 比目标机新运行时报 GLIBC 版本缺失。现象是二进制拷到另一台麒麟机器上执行--version直接报version GLIBC_2.29 not found。原因是编译环境的 glibc 版本高于运行环境这个依赖是硬编码在二进制里的strip 和静态链接 libstdc 都救不了。解决只有一个在 glibc 版本不高于目标机的那台机器上编或者在麒麟 V10 上做一套旧 glibc 的 sysroot 交叉编译。我一般直接要求所有目标机器的系统版本一致编译就在其中一台机器上做从根上避免这个问题。第三个坑rust 组件版本不符编译到 contrib/rust 时中断。现象是 ninja 输出error: failed to run custom build command for blake3或者feature xxx is not stable in this compiler version。原因是系统源里的 rust 版本和 ClickHouse 21.8 的contrib/rust/rust-toolchain文件要求不一致。解决是按文件里写的版本用 rustup 装装完之后rustup default version切过去再重新跑 cmake 让它重新探测 cargo 路径。注意source $HOME/.cargo/env这一步在 systemd 或者无人值守脚本里经常被忘掉导致 cmake 找不到 cargo。第四个坑ccache 一直不命中二次编译依然全量。现象是第二次编译和第一次耗时差不多ccache -s里 hit rate 稳定在 0.00%。原因通常有两个一是CCACHE_DIR所在分区满了ccache 静默退化成直通模式二是源码路径变化导致哈希失效比如第一次在/root/ClickHouse编译第二次在/home/build/ClickHouse。解决办法是固定源码路径并且在 cmake 里显式-DCCACHE_BASEDIR/root/ClickHouse让头文件路径归一化。查 ccache 空间用ccache -s看 cache size超过上限就ccache -C清一次。第五个坑服务能起来但查询报内存超限users.xml改了不生效。现象是明明在users.xml里把max_memory_usage调大了clickhouse-client查询还是报Memory limit (total) exceeded。原因是 21.8 支持users.d目录下的覆盖片段如果users.d里有同名 profile 的片段会覆盖主配置文件里的值而且加载顺序按文件名排序。解决是先clickhouse-client --query SELECT * FROM system.settings WHERE namemax_memory_usage FORMAT Vertical看实际生效值然后检查/etc/clickhouse-server/users.d/下有没有残留的旧片段。这个坑我踩过一次排查了两个小时后来养成习惯改完配置先查system.settings不信配置文件。6. 进阶把 21.8.14 做成可回归的编译基线编出来一次不算本事半年后还能编出字节级一致的东西才算。我现在的做法是把整个构建过程脚本化并且记录一份编译指纹每次重编都和指纹比对。脚本核心是把前面几章的命令串起来加上前置校验和产物归档#!/bin/bash # build-clickhouse-21.8.14.sh — 在鲲鹏 麒麟 V10 上复现构建 set -euo pipefail SRC/root/ClickHouse BUILD$SRC/build OUT/opt/dist/clickhouse-21.8.14 # 前置校验编译器、cmake、rust 三项版本必须匹配指纹 test $(/opt/gcc-10.3/bin/g -dumpversion) 10.3.0 test $(cmake --version | head -1 | awk {print $3}) \ 3.16 test $(rustc --version | awk {print $2}) $(cat $SRC/contrib/rust/rust-toolchain) cd $BUILD cmake .. -G Ninja \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILER/opt/gcc-10.3/bin/gcc \ -DCMAKE_CXX_COMPILER/opt/gcc-10.3/bin/g \ -DCMAKE_CXX_FLAGS-marcharmv8-a -O2 \ -DENABLE_TESTSOFF -DENABLE_UTILSOFF \ -DENABLE_EMBEDDED_COMPILEROFF \ -DUSE_INTERNAL_SSL_LIBRARY1 -DUSE_LLDON ninja -j 12 clickhouse ninja -j 1 clickhouse # 链接阶段串行防 OOM # 归档并生成指纹 mkdir -p $OUT install -m 755 $BUILD/programs/clickhouse $OUT/clickhouse sha256sum $OUT/clickhouse $OUT/clickhouse.sha256 /opt/gcc-10.3/bin/g -dumpversion $OUT/toolchain.txt指纹清单我固定记这几项出问题时逐项对照校验项采集方式用途git taggit describe --tags确认源码版本没漂移GCC 版本g -dumpversion编译器换版本会改二进制布局cmake 参数哈希sha256sum build/CMakeCache.txt配置项被改动会体现出来产物 sha256sha256sum clickhouse判断两次构建是否等价动态库依赖ldd clickhouse检查是否意外链接了编译机本地库这套东西的价值在于某次业务反馈查询结果异常第一反应不是怀疑代码而是先比指纹。有一次就是靠CMakeCache.txt的哈希对不上发现有人在构建目录里手动加了个-DENABLE_EMBEDDED_COMPILERON导致二进制行为和基线不一致排查方向瞬间从数据问题切到构建问题。再补一个验证技巧编完之后用clickhouse-benchmark跑一个最小基准把 QPS 和内存占用记进指纹里。这个数字不需要多精确只用来判断新编出来的二进制和上次是不是同一类东西——如果 QPS 掉了一半那一定是某个参数被改了比等业务报障早发现好几天。从那以后我每次重编都在脚本第一行做版本校验三项里有一项不匹配就直接退出宁愿不编也不编出个来路不明的二进制。希望帮到你。本文还有配套的精品资源点击获取