## 一、环境信息
| 角色 | 服务器 | 说明 |
|------|--------|------|
| 源服务器(staging CK) | `81.132.201.61` | Docker ClickHouse 24.3.2.23,数据约 21GB |
| 远程备份服务器 | `41.111.222.115` | SFTP 备份存储目标,磁盘 40G |
### 源服务器关键信息
| 项目 | 值 |
|------|-----|
| Docker 容器名 | `clickhouse-server` |
| ClickHouse 版本 | 24.3.2.23 |
| 数据目录(宿主机) | `/data/docker/clickhouse/data` |
| 数据目录(容器内) | `/var/lib/clickhouse` |
| clickhouse-backup 路径 | `/usr/local/bin/clickhouse-backup`(安装在宿主机上,非容器内) |
| clickhouse-backup 版本 | 2.5.17 |
| 配置文件路径 | `/etc/clickhouse-backup/config.yml` |
| 脚本目录 | `/home/tools/` |
| 端口映射 | 8123→8123, 9000→9000, 9009→9009 |
| 系统架构 | x86_64 |
### ClickHouse 用户信息
| 用户名 | 密码 | 说明 |
|--------|------|------|
| `webfunny_user` | `123` | 唯一可用用户,有 access_management 权限 |
| ~~`default`~~ | ~~已移除~~ | users.d/default-user.xml 中 remove="remove" |
| ~~`root`~~ | ~~不可用~~ | docker-compose 中配置但已被 users.xml 覆盖 |
### 备份策略
采用「周度全量基准 + 日度增量更新」策略:
- **周日 00:00**:执行全量基准备份,记录基准名称到本地和远程标记文件
- **周一至周六 00:00**:基于周日全量基准,用 `--diff-from-remote` 增量上传差异数据
- 所有增量直连全量基准,不接力上一日增量,杜绝级联损坏风险
- 本地保留最近 2 份,远程保留最近 7 份(保护全量基准,仅清理增量)
- 备份成功/失败均推送微信告警
---
## 二、完整部署步骤
### 步骤 1:初始化远程备份服务器目录
登录远程备份服务器,创建备份目录和基准目录:
```bash
ssh root@41.111.222.135
# 密码:xxx
mkdir -p /home/data_dev/clickhouse_backup/base/
```
验证:
```bash
ls -la /home/data_dev/clickhouse_backup/
# 应看到 base/ 目录
```
### 步骤 2:在源服务器创建符号链接
clickhouse-backup 安装在宿主机上,但需要访问容器的数据目录。容器内 `/var/lib/clickhouse` 挂载到宿主机 `/data/docker/clickhouse/data`,因此需要创建符号链接:
```bash
ssh root@81.132.211.6
# 密码:xxx
mkdir -p /var/lib
ln -sf /data/docker/clickhouse/data /var/lib/clickhouse
```
验证:
```bash
ls -la /var/lib/clickhouse/
# 应看到 store/、metadata/、data/ 等目录
```
> **重要**:如果不创建此符号链接,clickhouse-backup 会报错找不到数据目录。
### 步骤 3:部署配置文件
将 `config.yml` 上传到源服务器的 `/etc/clickhouse-backup/config.yml`:
```bash
scp config.yml root@8.133.201.61:/etc/clickhouse-backup/config.yml
```
关键配置项确认:
```yaml
general:
remote_storage: sftp# 使用 SFTP 远程存储
backups_to_keep_local: 7# 本地保留 7 份
backups_to_keep_remote: 7# 远程保留 7 份
download_concurrency: 4# 下载并发
upload_concurrency: 4# 上传并发
clickhouse:
username: "webfunny_user"# ClickHouse 用户名
password: "abc345jdhgga@0886smnbv"# ClickHouse 密码
host: "127.0.0.1"# 本地连接
port: 9000# ClickHouse 原生端口
freeze_by_part: true# 增量备份核心依赖!必须开启
skip_tables:
- system.* # 跳过系统表
timeout: 30m# 超时时间
sftp:
address: "41.111.222.135"# 远程备份服务器 IP
port: 22
username: "root"
password: "xxx"
path: "/home/data_dev/clickhouse_backup"# 远程备份路径
compression_format: tar
compression_level: 6# 压缩级别
concurrency: 1# SFTP 并发
connection_timeout: 60s
transfer_timeout: 10800s# 3 小时传输超时
```
> **重要**:`freeze_by_part: true` 是增量备份生效的核心配置,关闭后增量等同于全量。
### 步骤 4:部署微信通知脚本
将 `wechat_notify.sh` 上传到源服务器:
```bash
scp wechat_notify.sh root@81.133.211.61:/home/tools/wechat_notify.sh
ssh root@81.133.211.6 "chmod +x /home/tools/wechat_notify.sh"
```
### 步骤 5:部署增量备份脚本
将 `clickhouse_backup_incremental.sh` 上传到源服务器:
```bash
scp 增量备份/clickhouse_backup_incremental.sh root@81.133.211.61:/home/tools/clickhouse_backup_incremental.sh
ssh root@81.133.211.61 "chmod +x /home/tools/clickhouse_backup_incremental.sh"
```
> **注意**:此脚本直接在宿主机上运行 `clickhouse-backup` 命令(不使用 `docker exec`),因为 clickhouse-backup 安装在宿主机上。
### 步骤 6:配置 SSH 免密登录
脚本中需要通过 SSH 写入远程标记文件,必须配置免密登录:
```bash
ssh root@81.133.211.61
# 如果没有 SSH 密钥,先生成
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
# 将公钥复制到远程备份服务器
ssh-copy-id -o StrictHostKeyChecking=no root@41.111.222.135
# 输入远程服务器密码:xxx
# 验证免密登录
ssh root@41.11·.222.135 'echo SSH_OK && hostname'
# 应输出 SSH_OK 和主机名,无需输入密码
```
### 步骤 7:手动执行首次全量备份(初始化基准)
首次运行前必须先执行一次全量备份,建立基准:
```bash
ssh root@81.133.211.61
# 1. 创建本地全量备份
clickhouse-backup create full_global_backup_initial -v
# 2. 上传到远程服务器(14.8GB 数据约需 20-30 分钟)
clickhouse-backup upload full_global_backup_initial -v
# 3. 写入本地追踪文件
echo 'full_global_backup_initial' > /home/tools/.ck_incremental_tracker
# 4. 写入远程基准标记
ssh root@47.116.222.135 "mkdir -p /home/data_dev/clickhouse_backup/base && echo 'full_global_backup_initial' > /home/data_dev/clickhouse_backup/base/.last_full_backup"
# 5. 清理本地缓存
rm -rf /var/lib/clickhouse/backup/full_global_backup_initial
```
### 步骤 8:配置定时任务
```bash
ssh root@81.133.211.61
# 添加 crontab 定时任务(每天凌晨 00:00 执行)
(crontab -l 2>/dev/null; echo '0 0 * * * /bin/bash /home/tools/clickhouse_backup_incremental.sh > /home/tools/backup_incremental.log 2>&1') | sort -u | crontab -
# 验证
crontab -l
```
### 步骤 9:验证
```bash
ssh root@81.133.211.61
# 验证 clickhouse-backup 可以正常连接
clickhouse-backup list
# 验证本地追踪文件
cat /home/tools/.ck_incremental_tracker
# 应输出:full_global_backup_initial
# 验证远程备份文件
ssh root@41.111.222.135 "ls -la /home/data_dev/clickhouse_backup/full_global_backup_initial/"
# 应看到 metadata/、metadata.json、shadow/ 目录
```
---
## 三、备份脚本工作原理
### 脚本逻辑流程
```
脚本启动
│
├── 判断今天星期几(date +%u)
│
├── 周日(DOW=7)
│ ├── clickhouse-backup create full_global_backup_时间戳 # 创建全量
│ ├── clickhouse-backup upload 全量备份名 # 上传到远程
│ ├── echo 备份名 > /home/tools/.ck_incremental_tracker # 写本地追踪
│ └── ssh root@远程 "echo 备份名 > base/.last_full_backup" # 写远程标记
│
└── 周一~周六(DOW=1~6)
├── 读取 /home/tools/.ck_incremental_tracker 获取全量基准名
├── clickhouse-backup create inc_global_backup_时间戳 # 创建增量
└── clickhouse-backup upload --diff-from-remote=基准名 增量备份名 # 增量上传
│
├── 统计耗时 + 微信告警(成功/失败)
├── 清理本地备份缓存
├── 本地保留最近 2 份
└── 远程保留最近 7 份(仅删除 inc_* 增量,保护 full_* 全量基准)
```
### 关键文件说明
| 文件路径 | 作用 | 所在服务器 |
|----------|------|-----------|
| `/etc/clickhouse-backup/config.yml` | clickhouse-backup 主配置文件 | 源服务器 81.133.211.61 |
| `/home/tools/clickhouse_backup_incremental.sh` | 增量备份脚本 | 源服务器81.133.211.61 |
| `/home/tools/wechat_notify.sh` | 微信通知函数 | 源服务器81.133.211.61 |
| `/home/tools/.ck_incremental_tracker` | 本地全量基准追踪文件 | 源服务器81.133.211.61 |
| `/home/data_dev/clickhouse_backup/base/.last_full_backup` | 远程全量基准标记文件 | 备份服务器 41.111.222.135 |
| `/home/data_dev/clickhouse_backup/` | SFTP 远程备份根目录 | 备份服务器 41.111.222.135 |
| `/home/tools/backup_incremental.log` | 备份日志 | 源服务器81.133.211.61 |
---
## 四、数据恢复流程
增量备份恢复遵循「先基准、后增量」原则:
```bash
ssh root@81.133.211.61
# 1. 恢复基准全量备份(本周周日备份)
clickhouse-backup download full_global_backup_2026-XX-XXT00-00-01
clickhouse-backup restore full_global_backup_2026-XX-XXT00-00-01 --rm
# 2. 叠加恢复对应日期增量备份
clickhouse-backup download inc_global_backup_2026-XX-XXT00-00-01
clickhouse-backup restore inc_global_backup_2026-XX-XXT00-00-01 --rm
```
> `--rm` 参数表示恢复前先删除现有数据。
---
## 五、部署过程中遇到的问题及解决方案
### 问题 1:clickhouse-backup 不在 Docker 容器内
**现象**:执行 `docker exec clickhouse-server clickhouse-backup` 报错 `executable file not found in $PATH`
**原因**:原方案设计为在容器内运行 clickhouse-backup(类似生产环境),但 staging 服务器上 clickhouse-backup 安装在宿主机 `/usr/local/bin/` 而非容器内。
**解决方案**:
- 将备份脚本从 `docker exec $CONTAINER clickhouse-backup ...` 改为直接 `clickhouse-backup ...`
- 由于宿主机上端口 9000 已映射,clickhouse-backup 可直接通过 `127.0.0.1:9000` 连接 ClickHouse
### 问题 2:`/var/lib/clickhouse` 在宿主机上不存在
**现象**:clickhouse-backup 运行时报错找不到数据目录
**原因**:clickhouse-backup 通过查询 ClickHouse 的 `system.disks` 获取数据路径 `/var/lib/clickhouse`,但宿主机上该路径不存在(数据实际在 `/data/docker/clickhouse/data`)。
**解决方案**:创建符号链接
```bash
ln -sf /data/docker/clickhouse/data /var/lib/clickhouse
```
### 问题 3:ClickHouse 认证失败
**现象**:`clickhouse-backup list` 报错 `Authentication failed: password is incorrect`
**原因**:
- 旧配置使用 `default` 用户 + 密码 `das345jdlka@0976sfda`
- docker-compose 配置 `root` 用户 + 密码 `clickhouse`
- 但 `users.d/default-user.xml` 中 **移除了 default 用户**,创建了 `webfunny_user` 用户
- 实际可用用户只有 `webfunny_user`,密码为 `abc345jdhgga@0886smnbv`
**排查过程**:
1. 尝试 `root/clickhouse` → 认证失败
2. 尝试 `default/xxx` → 认证失败
3. 查看 `/etc/clickhouse-server/users.d/default-user.xml` 发现 default 被 remove
4. 使用无密码连接 `clickhouse-client`(容器内)返回 `webfunny_user`
5. 最终确认正确凭证:`webfunny_user` / `xxx`
**解决方案**:更新 config.yml 中的 clickhouse 凭证。
### 问题 4:远程备份出现 broken 条目
**现象**:`clickhouse-backup list` 显示远程有一个 `base` 的 broken 条目:`base ??? remote broken (can't stat metadata.json)`
**原因**:初始化时在远程服务器创建了 `base/` 目录用于存储标记文件,但 clickhouse-backup 将其误认为备份目录。
**解决方案**:删除 broken 条目
```bash
clickhouse-backup delete remote base
```
### 问题 5:`freeze_by_part` 配置默认为 false
**现象**:如果不开启此配置,增量备份无法实现 Part 级别差异对比,增量等同于全量。
**原因**:旧配置文件中 `freeze_by_part: false`。
**解决方案**:修改为 `freeze_by_part: true`,这是增量备份的核心依赖配置。
### 问题 6:expect 脚本中 `!` 是特殊字符
**现象**:自动化部署时 expect 脚本报错 `invalid command name "!"`
**原因**:Tcl/expect 中 `!` 是特殊字符,不能直接在 `send` 命令中使用。
**解决方案**:避免在 expect 脚本中使用含 `!` 的 shell 条件判断,改用其他写法或直接跳过。
---
## 六、日常运维检查
### 查看备份状态
```bash
ssh root@81.133.211.61
# 查看本地和远程备份列表
clickhouse-backup list
# 查看仅本地备份
clickhouse-backup list local
# 查看仅远程备份
clickhouse-backup list remote
# 查看备份日志
tail -100 /home/tools/backup_incremental.log
```
### 查看远程备份文件
```bash
ssh root@41.111.222.135
# 查看备份目录
ls -la /home/data_dev/clickhouse_backup/
# 查看各备份大小
du -sh /home/data_dev/clickhouse_backup/*/
# 查看磁盘使用
df -h /
```
### 检查定时任务
```bash
ssh root@81.133.211.61
crontab -l
```
---
## 七、注意事项
1. **freeze_by_part 必须为 true**:增量备份的核心配置,关闭后增量等同于全量
2. **基准不断层**:每周日全量备份必须执行成功,否则后续一周增量备份全部失效
3. **SSH 免密配置**:脚本中需要通过 SSH 写入远程标记文件,必须配置免密登录
4. **符号链接持久性**:`/var/lib/clickhouse` 符号链接在服务器重启后依然有效,但容器重建后需确认
5. **磁盘空间监控**:远程服务器磁盘 40G 已使用约 82%(15G 备份 + 系统占用),增量备份体积很小但需定期关注
6. **定期演练**:每月至少一次备份恢复演练,验证备份文件可用性
7. **日志监控**:定期查看 `/home/tools/backup_incremental.log`,结合微信告警及时发现异常
8. **ClickHouse 重启后**:如果 ClickHouse 容器重建,需确认端口映射 9000 仍然生效