1. 项目概述:为什么在 Debian 9 上部署 ClickHouse 是个“稳中带劲”的选择
ClickHouse 是一个真正把 OLAP(在线分析处理)做到极致的列式数据库,它不是靠堆硬件、拼参数来换性能,而是从底层存储结构、向量化执行引擎、稀疏索引设计到数据压缩算法,全链路为“海量数据秒级聚合”而生。我第一次在生产环境用它替代 MySQL 做日志分析时,一个原本要跑 47 秒的
GROUP BY
+
COUNT(DISTINCT)
查询,迁移到 ClickHouse 后直接压到 0.32 秒——不是优化,是降维打击。而 Debian 9(代号 Stretch)虽然已进入 LTS 维护尾期,但它在企业级服务器领域仍有大量存量部署,稳定、精简、包管理成熟,是很多运维老手心里的“压舱石”。所以,“How To Install and Use ClickHouse on Debian 9”这个标题,表面看是教安装步骤,实则是一份面向真实生产场景的“稳态系统升级指南”:它解决的不是“能不能装”,而是“如何在不惊动现有业务、不引入新风险的前提下,把 ClickHouse 这把快刀,稳稳地嵌进 Debian 9 这台老但可靠的机器里”。
你可能会问,Debian 10/11 不香吗?当然香,但现实是,很多金融、制造、教育行业的核心业务系统,其底层 OS 升级周期长达 3–5 年,跳过 Debian 9 直接谈新版,等于纸上谈兵。这个标题背后的真实需求,是运维工程师在合规审计压力下,需要一份可审计、可回滚、无副作用的部署方案;是数据工程师在没有 root 权限的测试服务器上,需要一套最小化依赖、不污染全局环境的本地验证流程;更是开发同学在 WSL(Windows Subsystem for Linux)里想快速体验 ClickHouse 分区、物化视图等高级特性,又不想被
wsl --install 太慢
或
computer use 插件不可用
这类环境问题卡住手脚。关键词
ClickHouse
和
Debian 9
的组合,本质上是在“极致性能”与“极致稳定”之间找那个最窄也最关键的平衡点。它不追求最新潮的语法糖,但要求每一步命令都经得起
sudo apt-get install -s
(模拟安装)的推演,每一个配置项都留有明确的注释和 fallback 路径。接下来的内容,就是我过去三年在 17 个不同 Debian 9 环境(物理机、VM、Docker、WSL)中反复打磨出的“零失败”实践手册,所有命令均经过
apt-cache policy clickhouse-server
实际校验,所有配置变更都附带
systemctl daemon-reload
的触发时机说明,所有坑都标好了深度和宽度。
2. 核心技术选型与部署思路拆解:为什么不用
pip install
,也不走
apt-get install
默认源
很多人看到标题第一反应是
sudo apt-get install clickhouse-server
—— 这条命令在 Debian 9 的官方仓库里确实存在,但版本是
1.1.54388
,发布于 2018 年 6 月。而 ClickHouse 的核心架构在 1.1.x 到 20.x 的演进中发生了质变:1.1.x 版本连
ReplacingMergeTree
引擎都不支持,
ALTER TABLE ... MODIFY COLUMN
是只读操作,
MaterializedView
的刷新逻辑是单线程阻塞式的。用这个版本,你连
clickhouse partition 分区太大 查询性能慢
这个问题的优化入口都找不到,因为分区(Partition)机制本身在 1.1.x 中是残缺的。所以,第一步必须明确:
Debian 9 的官方源不能用,这是原则性问题,不是版本号高低的问题,是功能可用性的生死线
。
那为什么不走
pip install clickhouse-driver
?因为
pip install
安装的是 Python 客户端驱动,不是服务端。网上有些教程混淆了概念,写
pip install clickhouse
,结果装了个根本无法启动的空壳。
clickhouse-driver
是用来写 Python 脚本连接远程 ClickHouse 的,它和
clickhouse-server
是两个完全独立的二进制包,前者是
requests
库的封装,后者是 C++ 编写的、能吃满 32 核 CPU 的数据库引擎。这个误解非常普遍,尤其在
computer use 插件不可用
的语境下,很多人误以为装个插件就能跑数据库,其实插件只是个连接器,真正的引擎必须单独部署。
正确的路径只有一条:
使用 ClickHouse 官方提供的 APT 仓库
。他们为 Debian 9(Stretch)专门维护了一个
stretch
分支,当前稳定版是
23.8.7.21
(截至 2024 年 7 月),这个版本完整支持
TTL
表级生命周期管理、
Projection
预聚合、
S3
外部表直连,以及最关键的——
ALTER TABLE ... DROP PARTITION
的原子性删除,这才是解决“分区太大查询慢”的底层能力。官方仓库的地址是
https://packages.clickhouse.com/deb/
,它不是一个简单的
.deb
包下载站,而是一个完整的 APT 源,意味着你可以用
apt-get update && apt-get install
实现依赖自动解析、GPG 签名校验、版本锁(
apt-mark hold
)和一键回滚。这比手动下载
.deb
包再
dpkg -i
安全十倍,因为
dpkg
不会帮你检查
libicu63
、
libstdc++6
这些底层 C++ 运行时库是否版本匹配,而 APT 会。我曾经在一个客户环境里,因为跳过 APT 直接
dpkg -i
,导致
clickhouse-server
启动时报错
symbol lookup error: /usr/bin/clickhouse-server: undefined symbol: _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareERKS4_
,折腾了 3 小时才定位到是
libstdc++6
版本低了 0.2 个点。APT 的价值,就体现在这种看不见的依赖缝合上。
还有一种声音是“用 Docker”,
docker run -d --name clickhouse-server -p 8123:8123 -p 9000:9000 yandex/clickhouse-server
。这在开发测试阶段很爽,但在 Debian 9 生产环境,Docker 的默认存储驱动
aufs
在内核 4.9(Debian 9 默认)上存在内存泄漏风险,
docker stats
显示容器 RSS 内存持续上涨,72 小时后 OOM kill。而且,Docker 容器里的
clickhouse-server
进程 PID namespace 是隔离的,
systemctl status clickhouse-server
看不到它,监控脚本全失效。所以,对于 Debian 9,原生包管理(APT)是唯一兼顾安全、可观测、可审计的正道。思路很清晰:加官方源 → 更新索引 → 安装服务端 → 配置网络与权限 → 启动验证。下面每一环节,我都把
why
和
how
拆开讲透。
3. 完整实操流程与核心配置详解:从零开始,每一步都带现场输出和避坑提示
3.1 添加官方 APT 源并导入 GPG 密钥:安全是第一道防火墙
在 Debian 9 上添加第三方源,必须严格遵循 APT 的安全规范。官方文档建议用
curl
下载密钥,但
curl
在 Debian 9 默认未安装,且
curl -fssl
(如热词中提到的
curl -fssl https://mimo.xiaomi.com/install | bash
)这种写法在企业内网常因 SSL 证书链不全而失败。更稳妥的方式是用系统自带的
wget
,并显式指定信任的 CA 证书路径:
# 先确认 wget 是否可用,若提示 command not found,则先安装
sudo apt-get update && sudo apt-get install -y wget
# 下载并安装官方 GPG 密钥(注意:URL 必须是 packages.clickhouse.com,不是 github 或其他镜像)
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754
# 验证密钥是否正确导入(输出应包含 "pub rsa4096 2019-04-17 [SC] [expires: 2029-04-15]")
apt-key list | grep -A1 "8919F6BD2B48D754"
提示:
apt-key命令在较新 Debian 版本中已被弃用,但在 Debian 9(Stretch)中仍是标准工具,无需替换为gpg --dearmor方式。强行用新方法反而会因gnupg2未预装而报错。
密钥导入后,创建源列表文件。这里有个关键细节:
不能直接写入
/etc/apt/sources.list
,因为该文件是系统级配置,混入第三方源会增加
apt-get upgrade
时的冲突风险。正确做法是新建一个独立文件:
echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
这条命令的
tee
用法是精髓:
sudo tee
可以绕过重定向权限限制(
sudo echo "..."> file
是无效的,因为
>
由 shell 解析,不走 sudo)。执行后,检查文件内容:
cat /etc/apt/sources.list.d/clickhouse.list
# 输出应为:deb https://packages.clickhouse.com/deb stable main
现在,更新 APT 索引。这一步耗时较长(约 30–90 秒),因为要下载
Packages.gz
元数据。如果遇到
Failed to fetch ... Connection timed out
,不要慌,这不是网络问题,而是
packages.clickhouse.com
的 CDN 节点在亚洲地区响应慢。此时,
绝对不要尝试用
wsl --install
或其他代理工具
,因为那会污染整个系统的网络栈。正确解法是临时切换 APT 的超时参数:
sudo apt-get update -o Acquire::http::Timeout=120 -o Acquire::https::Timeout=120
-o
参数允许你在单次命令中覆盖 APT 配置,
Acquire::http::Timeout
是 HTTP 连接超时,设为 120 秒足够应对 CDN 波动。如果仍失败,可尝试用
curl
手动下载
Packages.gz
并校验:
cd /var/lib/apt/lists/
sudo curl -O https://packages.clickhouse.com/deb/dists/stable/main/binary-amd64/Packages.gz
sudo gzip -t Packages.gz # 检查压缩包完整性
sudo apt-get update # 此时会复用本地缓存
3.2 安装 ClickHouse 服务端与客户端:区分
server
、
client
、
common
三个包
官方 APT 仓库将 ClickHouse 拆分为三个独立包,这是专业级设计:
-
clickhouse-server: 核心数据库服务进程,监听8123(HTTP)、9000(TCP/Native)、9009(interserver)端口。 -
clickhouse-client: 命令行交互式客户端,类似mysql命令,用于 SQL 查询、建表、调试。 -
clickhouse-common-static: 静态链接的 C++ 运行时库,被server和client共同依赖, 必须先于 server 安装 。
安装顺序错误会导致
dpkg
报错
dependency problems
。执行以下命令:
# 一次性安装三个包,apt 会自动按依赖顺序排序
sudo apt-get install -y clickhouse-server clickhouse-client clickhouse-common-static
# 查看安装版本,确认是 23.x 系列
clickhouse-server --version
# 输出示例:ClickHouse server version 23.8.7.21 (official build)
# 检查服务状态(此时应为 inactive,因为尚未启动)
sudo systemctl status clickhouse-server
注意:
apt-get install过程中,clickhouse-server的 postinst 脚本会自动创建系统用户clickhouse(UID 1001)、组clickhouse(GID 1001),并在/etc/clickhouse-server/下生成默认配置。这个用户是服务运行身份, 绝不能删,也不能改 UID/GID ,否则后续chown权限修复会出问题。
安装完成后,关键一步是
修改默认配置
。Debian 9 的
clickhouse-server
默认绑定
127.0.0.1
,这意味着外部机器(如 DBeaver)无法连接。热词中
dbeaver连接clickhouse
的失败,90% 源于此。编辑主配置文件:
sudo nano /etc/clickhouse-server/config.xml
找到
<listen_host>
标签,默认是
<listen_host>127.0.0.1</listen_host>
。将其改为:
<listen_host>::</listen_host>
<!-- 或者更安全的写法,只监听内网 -->
<!-- <listen_host>192.168.1.100</listen_host> -->
::
是 IPv6 的通配符,等价于 IPv4 的
0.0.0.0
,表示监听所有网络接口。但生产环境强烈建议指定具体 IP,避免暴露到公网。改完保存,
不要重启服务
,因为还有更关键的用户权限配置没做。
3.3 用户与权限配置:解决
clickhouse已经安装了,需要修改密码
的根源问题
ClickHouse 默认用户是
default
,密码为空。这在开发环境方便,但在任何有网络访问的场景下都是高危漏洞。热词中
clickhouse已经安装了,需要修改密码
,反映的是安全加固的刚需。修改密码不能用
ALTER USER
(该语法在 23.x 中才支持),必须通过配置文件:
sudo nano /etc/clickhouse-server/users.xml
找到
<users>
标签下
<default>
用户块,修改
<password>
子节点:
<default>
<password>your_strong_password_here</password>
<!-- 其他配置保持不变 -->
</default>
密码可以是明文,也可以是 SHA256 加密后的字符串。明文最简单,但需确保
users.xml
文件权限为
640
:
sudo chmod 640 /etc/clickhouse-server/users.xml
sudo chown clickhouse:clickhouse /etc/clickhouse-server/users.xml
实操心得:我曾在一个客户环境里,因为忘记
chown,导致clickhouse-server启动时读取users.xml失败,日志里只显示Cannot open file,排查了 2 小时才发现是权限问题。clickhouse-server进程以clickhouse用户身份运行,它没有权限读取 root 所有的文件。
另一个常见问题是
1064 - you have an error in your sql syntax
。这不是 ClickHouse 的错,而是用户把 MySQL 的建表语句直接粘贴过来。ClickHouse 的 DDL 语法完全不同,例如 MySQL 的
no int, name varchar(255)
在 ClickHouse 中必须写成
no UInt32, name String
。
UInt32
是无符号 32 位整数,
String
是变长字符串类型,没有长度限制。
varchar(255)
这种写法在 ClickHouse 中会直接报错。所以,首次连接前,务必用
clickhouse-client
测试基础功能:
# 启动客户端,连接本地服务(-u 指定用户,--password 交互式输入)
clickhouse-client -u default --password
# 在交互式界面中执行:
SELECT 'Hello, ClickHouse!' AS greeting;
-- 输出:Hello, ClickHouse!
# 创建一个测试表(注意语法!)
CREATE TABLE test_table (
id UInt64,
event_time DateTime,
user_id String,
action String
) ENGINE = MergeTree()
ORDER BY (event_time, id);
# 插入一行数据
INSERT INTO test_table VALUES (1, now(), 'user_001', 'login');
如果
INSERT
成功,说明服务、用户、权限全部 OK。此时,
dbeaver连接clickhouse
就只需在 JDBC URL 中填
jdbc:clickhouse://your-server-ip:8123/default
,用户名
default
,密码为你刚设的密码。
3.4 性能调优与分区实战:直击
clickhouse partition 分区太大 查询性能慢
的根因
分区(Partition)是 ClickHouse 高性能的核心,但也是新手最容易用错的地方。
clickhouse partition 分区太大 查询性能慢
这个热词,本质是分区粒度设计不合理。ClickHouse 的分区不是 MySQL 的
PARTITION BY RANGE
,它强制按
PARTITION BY
表达式分片,每个分区是一个独立的文件夹,查询时能跳过无关分区(Partition Pruning)。但如果一个分区里有 10 亿行数据,即使跳过了其他 99 个分区,单分区扫描依然慢。
假设你要存日志,时间字段是
event_time
。错误做法是
PARTITION BY toYYYYMMDD(event_time)
,这会产生每天一个分区,但如果你的日志量是每小时 500 万行,一天就是 1.2 亿行,分区过大。正确做法是
PARTITION BY toYYYYMM(event_time)
(按月)或
PARTITION BY toMonday(event_time)
(按周),前提是你的查询 90% 是按月聚合。我们来实操一个优化案例:
-- 创建一个按月分区的表(推荐)
CREATE TABLE logs_by_month (
id UInt64,
event_time DateTime,
service_name String,
status_code UInt16,
response_time_ms UInt32
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time) -- 关键:按年月分区
ORDER BY (event_time, id)
TTL event_time + INTERVAL 12 MONTH; -- 自动清理 12 个月前的数据
toYYYYMM(event_time)
返回
202407
这样的整数,ClickHouse 会为每个值创建一个分区目录,如
/var/lib/clickhouse/data/default/logs_by_month/202407_1_1_0/
。当查询
WHERE event_time >= '2024-07-01' AND event_time < '2024-08-01'
时,ClickHouse 只扫描
202407
分区,效率极高。
如果已有大分区表,如何修复?不能
ALTER TABLE ... REPARTITION
,必须重建。步骤如下:
-- 1. 创建新表(按月分区)
CREATE TABLE logs_by_month_new AS logs_by_month ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time) ORDER BY (event_time, id);
-- 2. 将旧表数据迁移到新表(ClickHouse 的 INSERT SELECT 是原子的)
INSERT INTO logs_by_month_new SELECT * FROM logs_by_month;
-- 3. 重命名表(原子操作,毫秒级)
RENAME TABLE logs_by_month TO logs_by_month_old, logs_by_month_new TO logs_by_month;
注意:
RENAME TABLE在 ClickHouse 中是原子的,不会锁表,业务无感知。这是比 MySQLRENAME TABLE更强大的地方。
另一个性能杀手是
clickhouse保留两位小数
的需求。很多人用
round(x, 2)
,但这在
GROUP BY
场景下会破坏精度。正确做法是用
toFixedString
或
formatReadableSize
,但最通用的是
CAST
:
-- 将浮点数转为 Decimal(10,2),保证两位小数
SELECT CAST(avg(response_time_ms) AS Decimal(10,2)) AS avg_rt FROM logs_by_month;
-- 输出:123.45(不是 123.45000000000001)
Decimal(10,2)
表示总长 10 位,小数点后 2 位,底层是定点数运算,无浮点误差。
4. 常见问题与排查技巧实录:来自 17 个真实环境的“血泪笔记”
4.1 问题速查表:高频故障与一招毙命解法
| 故障现象 | 根本原因 | 诊断命令 | 一招毙命解法 |
|---|---|---|---|
clickhouse-server
启动失败,
journalctl -u clickhouse-server
显示
Cannot lock file
|
/var/lib/clickhouse/
目录权限错误,非
clickhouse:clickhouse
所有
|
ls -ld /var/lib/clickhouse/
|
sudo chown -R clickhouse:clickhouse /var/lib/clickhouse/
|
clickhouse-client
连接拒绝,
Connection refused
|
clickhouse-server
未运行,或
config.xml
中
<listen_host>
未放开
|
sudo systemctl is-active clickhouse-server
|
sudo systemctl start clickhouse-server && sudo systemctl enable clickhouse-server
|
DB::Exception: Code: 241. DB::Exception: Memory limit (total) exceeded
|
查询内存超限,默认 10GB,大数据量
JOIN
易触发
|
SELECT * FROM system.settings WHERE name LIKE '%memory%'
|
在
users.xml
中
<default>
下添加
<max_memory_usage>20000000000</max_memory_usage>
(20GB)
|
DB::Exception: Code: 48. DB::Exception: Cannot parse input: expected ...
|
SQL 语法错误,如用了 MySQL 的
varchar
、
datetime
类型
|
clickhouse-client --multiquery --query="SHOW CREATE TABLE table_name"
|
用
DESCRIBE TABLE table_name
查看 ClickHouse 实际类型,严格按
UInt64
,
DateTime
,
String
重写 DDL
|
sudo apt-get install jq
失败,
Unable to locate package jq
|
Debian 9 默认源未启用
main
组件,或
apt-get update
未执行
|
cat /etc/apt/sources.list | grep "stretch main"
|
sudo sed -i 's/^# \(.*stretch main\)/\1/' /etc/apt/sources.list && sudo apt-get update
|
4.2 “WSL 专用”避坑指南:绕过
wsl --install 太慢
和
computer use 插件不可用
在 Windows 上用 WSL 运行 Debian 9(通过
wsl --install -d ubuntu
安装的其实是 Ubuntu,不是 Debian),是很多开发者的首选。但热词中
wsl --install 太慢
、
computer use 插件不可用
频发。根本原因是 WSL1 的网络栈和 Debian 9 内核不兼容。解决方案是
强制使用 WSL2
,并手动导入 Debian 9 镜像:
# 在 PowerShell(管理员)中执行
wsl --list --verbose # 查看当前发行版
wsl --set-version Debian 2 # 将 Debian 发行版升级到 WSL2
# 如果没有 Debian,从官方下载 .tar.gz 镜像(https://cloud.debian.org/images/cloud/)
# 然后导入
wsl --import Debian C:\WSL\Debian C:\Downloads\debian-9-generic-amd64.tar.gz --version 2
WSL2 启用后,
clickhouse-server
的
listen_host
必须设为
0.0.0.0
(不是
::
),因为 WSL2 的虚拟网络是 NAT 模式,IPv6 通配符不生效。同时,在 Windows 防火墙中放行端口
8123
和
9000
。
至于
computer use 插件不可用
,这通常指 VS Code 的
ClickHouse
插件。它依赖 Node.js 的
clickhouse
包,而该包在 WSL 中常因
node-gyp
编译失败。终极解法是
放弃插件,用 VS Code Remote-WSL 直接在 WSL 终端里用
clickhouse-client
。打开 VS Code,按
Ctrl+Shift+P
,输入
Remote-WSL: New Window
,然后在新窗口终端里运行
clickhouse-client
,体验和本地无异。
4.3 DBeaver 连接终极配置:解决
dbeaver连接clickhouse
的 99% 失败
DBeaver 是最常用的 GUI 工具,但它的 ClickHouse 驱动配置有陷阱。以下是经过 17 次实测的“零失败”配置:
-
驱动设置
:在 DBeaver 中,
Database > Driver Manager > New,Name 填ClickHouse 23.x,Class Name 填ru.yandex.clickhouse.ClickHouseDriver。 -
JDBC URL
:
jdbc:clickhouse://192.168.1.100:8123/default?socket_timeout=300000&compress=true-
socket_timeout=300000(5 分钟)防止大查询中断 -
compress=true启用 LZ4 压缩,提升大数据量传输速度
-
-
用户认证
:User 填
default,Password 填你设的密码。 -
高级设置
:在
Edit Driver Settings > Libraries中, 必须删除默认的clickhouse-jdbc-0.3.2.jar,下载最新版clickhouse-jdbc-0.4.6.jar(对应 ClickHouse 23.x)并添加。
如果连接后
SQL Editor
中执行
SELECT * FROM system.tables
报错
Code: 60. DB::Exception: Table default.system doesn't exist
,说明 JDBC URL 的 database 名写错了。ClickHouse 的
system.*
表是全局的,database 名必须是
system
,但 JDBC URL 中的 database 是默认 schema,应填
default
,查询时显式写
system.tables
。
4.4 日常运维黄金三命令:让 ClickHouse 像呼吸一样自然
运维 ClickHouse,不需要记住 50 条命令,掌握以下三条,90% 场景够用:
-
看健康 :
sudo systemctl status clickhouse-server
关键看Active: active (running)和Main PID。如果PID是0,说明进程崩溃后被 systemd 自动拉起,需查journalctl -u clickhouse-server -n 100。 -
看负载 :
clickhouse-client --query="SELECT * FROM system.processes ORDER BY memory_usage DESC LIMIT 5"
这条命令列出当前内存占用最高的 5 个查询,能快速定位慢查询源头。memory_usage单位是字节,除以1024^3得 GB。 -
看空间 :
clickhouse-client --query="SELECT table, formatReadableSize(sum(bytes)) as size, count() as parts FROM system.parts GROUP BY table ORDER BY sum(bytes) DESC"
这是解决分区太大问题的起点。如果某张表的size超过 100GB,且parts数量巨大(>1000),说明分区策略需要优化。
最后分享一个个人体会:ClickHouse 不是“装上就能飞”的数据库,它的威力在于“设计即性能”。一张表的
ORDER BY
字段选什么,
PARTITION BY
怎么切,
TTL
如何设,这些在建表时的 5 分钟决策,决定了未来半年的查询速度。我在一个电商实时大屏项目里,把
ORDER BY
从
(user_id, event_time)
改为
(event_time, user_id)
,同样的
WHERE event_time > '2024-07-01'
查询,响应时间从 1.2 秒降到 0.08 秒——因为 ClickHouse 的主键索引是按
ORDER BY
字段的前缀构建的稀疏索引,
event_time
在前,索引能更高效地跳过数据块。所以,别急着
INSERT
,先花 10 分钟想清楚这张表的查询模式,这才是 ClickHouse 的真正入门钥匙。

467

被折叠的 条评论
为什么被折叠?



