备份与恢复
数据保护是运维中最重要的责任。PlantPulse 通过 plantpulse-backup 模块对 PostgreSQL / Aster TSDB / 文件 / 容器卷进行统一备份。
plantpulse-backup 包含在 plantpulse-datalake 镜像中。因为所有数据库都在该容器中运行。
cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh # 데이터레이크 진입
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
仅 Docker 卷备份在主机上执行(见下方 §3)。
保护对象概览
备份工具矩阵
| 工具 | 对象 | 方式 | 压缩 | 去重 |
|---|---|---|---|---|
| pgBackRest | PostgreSQL | 全量 / 差异 / 增量 | gzip / zstd | ✓ |
| Medusa | Aster TSDB | 全量 / 差异 (快照) | gzip | - |
| Restic | 文件 / 目录 | 增量 | zstd | ✓ |
| rc mirror | RustFS | 增量同步 | - | - |
| backup-volume.sh | Docker 卷 | tar.gz 快照 | gzip | - |
RPO / RTO 建议目标
| 数据 | RPO (恢复时点) | RTO (恢复时间) | 建议备份频率 |
|---|---|---|---|
| PostgreSQL 元数据 | 1小时 | 30分钟 | 每日1次全量 + 每小时 WAL |
| Aster TSDB 时序 | 24小时 | 2小时 | 每日1次差异 + 每周1次全量 |
| RustFS 对象 | 24小时 | 4小时 | 外部 S3 镜像 + 每日1次 |
| 配置 / 证书 | 变更时 | 15分钟 | 变更时立即备份 + 每月1次 |
运行级数据中心: 以上目标基于单站点简单运行标准。如需 Multi-AZ / Geo-redundant,请同步设计外部站点复制 (rsync, rc mirror, Kafka MirrorMaker)。
备份存储结构
/data1/pp-backup/
├── pgbackrest/postgres/ # PostgreSQL 백업 (pgBackRest)
│ ├── archive/ # WAL archive
│ └── backup/ # Full / Diff / Incr
├── medusa/ # Cassandra 백업 (Medusa)
│ └── <hostname>/<backup-name>/
├── restic/ # 파일 백업 (Restic)
│ ├── data/
│ ├── index/
│ └── snapshots/
└── docker-volume/ # Docker 볼륨 (tar.gz)
├── pp-data-YYYYMMDD.tar.gz
├── pp-security-YYYYMMDD.tar.gz
└── ...
1. plantpulse-backup 统一命令
plantpulse-backup 模块封装了所有备份工具。
初始安装 (仅限首次)
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
./backup.sh --install
自动执行:
- pgBackRest 配置 (
/etc/pgbackrest/pgbackrest.conf) - Medusa 配置 (
/etc/medusa/medusa.ini) - 创建目录 / 权限
- 创建 pgBackRest stanza
PostgreSQL 备份
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
./backup.sh --postgres # Differential (기본, 빠름)
./backup.sh --postgres full # Full (전체)
./backup.sh --postgres incr # Incremental (가장 빠름)
Aster TSDB 备份
./backup.sh --cassandra # Differential
./backup.sh --cassandra full # Full
文件备份 (Restic)
/opt/kopens/plantpulse-platform/plantpulse-backup/etc/run_restic.sh
/data1/pp-data增量备份- 保留策略:最近 7 天 + 每月 1 个
- 自动完整性检查
备份清理
./backup.sh --purge
- pgBackRest:
repo1-retention-full(默认 2 套) - Medusa:
CASS_PURGE_KEEP_DAYS(默认 10 天) - Restic: 根据策略自动清理
2. 自动备份 — 已默认开启
自动备份默认开启。无需单独运行安装计划的命令。
| 任务 | 职责 |
|---|---|
postgres-diff | PostgreSQL 差异备份 |
postgres-full | PostgreSQL 全量备份 |
cassandra-diff | Aster TSDB 差异备份 |
cassandra-full | Aster TSDB 全量备份 |
purge | 保留策略清理 |
数据湖镜像中既没有 systemd 也没有 crontab(PID 1 为入口点本身)。
计划存储在数据湖 DB 的 backup_schedule 表中,每项任务一行,
由 plantpulse-datalake-admin-api 中的 Quartz 调度器(仅在 PP_MODE=MASTER 中)读取并触发。
pd backup schedule # 읽기
pd backup schedule set --job <잡> --cron "<초 분 시 일 월 요일>"
pd backup schedule reset [--job <잡>]
请勿尝试通过 systemctl list-timers 查找 — 将无结果。
:::
默认计划
| 作业 | OnCalendar | 时间 |
|---|---|---|
| PostgreSQL Diff | *-*-* 01:30:00 | 每日 01:30 |
| PostgreSQL Full | Sun *-*-* 01:00:00 | 每周日 01:00 |
| Aster TSDB Diff | *-*-* 01:20:00 | 每日 01:20 |
| Aster TSDB Full | Sun *-*-* 00:10:00 | 每周日 00:10 |
| Purge | Sun *-*-* 03:00:00 | 每周日 03:00 |
开启与关闭
在主机的 Secret Sidecar 中写入开关并重启。
# 호스트에서
sudo vi /etc/kopens/plantpulse-platform.env
# export PP_BACKUP_SCHEDULE_ENABLED=false
cd /opt/kopens/plantpulse-platform-docker/bin
./restart.sh
定时器本身始终触发,包装脚本读取开关进行判断。若处于关闭状态,将跳过备份并在 日志与 history.jsonl 中记录为 result="skipped" — 而非 ok 或 fail。因此,事后可以将«关闭»与«运行»区分开来。
请勿直接修改单元文件进行关闭。下次镜像构建重新加载原文件时,将静默恢复开启状态。
若将 export PP_BACKUP_SCHEDULE_ENABLED=false 仅写入 bin/env.sh,将无法触达容器。 compose 将此名称传递给容器的配置行是开关的全部,其值来源于 Sidecar (或 shell export)。若写入错误,会出现«看似关闭但实际在运行»的状态。
3. Docker 卷备份 (容器环境)
在单行安装 / Docker 安装中,可以额外进行卷级备份。
在主机上执行。
cd /opt/kopens/plantpulse-platform-docker/bin
# 기본 세트를 한 번에 (pp-data · pp-security)
./backup.sh
# 볼륨 하나만
./tools/backup-volume.sh pp-data 7 /data1/pp-backup/docker-volume
./tools/backup-volume.sh pp-security 30 /data1/pp-backup/docker-volume
默认集中缺失两个卷并非遗漏 — pp-backup 是备份的目的地(若将自身放入自身,每次体积将翻倍),而 pp-temp 对恢复无用。如需要,可通过参数指定备份。
配置模板是绑定挂载的主机目录 /etc/kopens/conf,不属于 Docker 卷备份对象。请将其作为主机文件统一备份。Secret Sidecar /etc/kopens/plantpulse-platform.env 同理。
| 参数 | 说明 | 默认 |
|---|---|---|
| 1 | 卷名称 | (必填) |
| 2 | 保留天数 | 7 |
| 3 | 存储路径 | /data1/pp-backup/docker-volume |
4. 环境变量 (backup.sh)
| 变量 | 默认 | 说明 |
|---|---|---|
BACKUP_ROOT | /data1/pp-backup | 备份根目录 |
PG_VER | 18 | PostgreSQL 版本 |
PG_DATA | /data1/pp-data/postgres/data | PG 数据目录 |
CASS_BASE | /opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra | Aster TSDB 安装路径 |
CQL_USER | ${PP_CASSANDRA_USER} | CQL 用户 |
CQL_PASS | ${PP_CASSANDRA_PASSWORD} | CQL 密码 |
PG_RETENTION_FULL | 2 | PG 全量保留 |
CASS_PURGE_KEEP_DAYS | 10 | Medusa 保留天数 |
5. 外部站点复制 (Off-site)
仅凭本地备份在面对数据中心故障时较为脆弱。建议模式:
# 매일 새벽 4시 — 외부 S3 로 복제
0 4 * * * rclone sync /data1/pp-backup/ s3:kopens-pp-backup/$(hostname)/ \
--bwlimit 50M --log-file /var/log/pp-backup-sync.log
# RustFS 객체는 S3 클라이언트로 별도 미러
0 5 * * * rc mirror --overwrite local/ s3-offsite/
6. 恢复
6.1 PostgreSQL 恢复
# 1. plantpulse 중지 (PG 의존 모듈 + PG)
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./stop.sh
# 2. 백업 정보 확인
sudo -u postgres pgbackrest --stanza=pg18 info
# 3. 최신 복구
sudo -u postgres pgbackrest --stanza=pg18 restore
# 3-2. 시점 복구 (PITR)
sudo -u postgres pgbackrest --stanza=pg18 --type=time \
--target="2026-05-30 12:00:00" restore
# 4. 재시작
./start-daemon.sh
./status.sh
6.2 Aster TSDB 恢复
# 백업 목록
medusa list-backups
# 단일 노드 복구
medusa restore-node --backup-name full_20260530_0010
# 클러스터 전체 복구 (마스터에서)
medusa restore-cluster --backup-name full_20260530_0010
注意:
restore-cluster会覆盖所有节点的数据。执行前请务必在 stage 环境中验证。
6.3 文件恢复 (Restic)
# 스냅샷 목록
restic -r /data1/pp-backup/restic snapshots
# 최신 스냅샷 → 임시 위치 복구
restic -r /data1/pp-backup/restic restore latest --target /data1/pp-data-restored
# 특정 파일만 복구
restic -r /data1/pp-backup/restic restore latest --target / --include /data1/pp-data/cassandra/data/pp/tm_tag_point
6.4 部分时序恢复 (plantpulse-recovery)
若仅需重新处理特定资产的特定期间数据:
cd /opt/kopens/plantpulse-platform/plantpulse-recovery/bin
./recovery.sh EQUIPMENT_000001 20260501 20260530
6.5 部分时序提取 (plantpulse-exporter)
提取为 CSV 或通过 dsbulk 进行批量处理:
cd /opt/kopens/plantpulse-platform/plantpulse-exporter/bin
# 에셋 단위 CSV
./export.sh EQUIPMENT_000001 20260101 20260530 /tmp
# 테이블 벌크 언로드 → gz
./bulk-unload.sh pp tm_tag_point
# /data1/pp-backup/cassandra/bulk/tm_tag_point.gz
# 다시 로드
./bulk-load.sh pp tm_tag_point
7. 灾难恢复 (DR) 场景
场景 A: 服务器硬件故障 (Cold DR)
预计 RTO: 4~8小时 (取决于数据容量)
场景 B: 数据损坏 (PITR)
# 1. 손상 시점 직전으로 시점 복구
./stop.sh
sudo -u postgres pgbackrest --stanza=pg18 --type=time \
--target="2026-05-30 14:30:00" restore
# 2. Cassandra 도 동일 시점 가까운 백업으로
medusa restore-cluster --backup-name diff_20260530_0120
# 3. 재시작
./start-daemon.sh
./status.sh
场景 C: 外部站点故障转移 (Hot DR)
在外部站点维护备用集群的情况。需提前设计:
- PostgreSQL: 流复制 (streaming replication) 或 pgBackRest 异步复制
- Aster TSDB: multi-DC 集群 + 自动 hinted handoff
- Kafka: MirrorMaker 2 双向复制
- RustFS: 站点复制或
rc mirror --watch
8. 恢复后验证清单
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
# 1. 전체 모듈 상태
./status.sh
# 2. 헬스 체크
./ops-check.sh
# 3. Cassandra 클러스터 정상
./pd node status
# 4. PostgreSQL 연결
./pd node psql -c "SELECT count(*) FROM site;"
# 5. Kafka 토픽 / Consumer Group
./pd node topic
浏览器:
- Web 控制台访问 (
http://[HOST]/) - 管理员登录 (
admin / admin123!) - 仪表板加载
- 报警列表显示
- OPC 连接状态为 CONNECTED
- 时序趋势中显示最新数据
- CEP 规则执行确认
9. 备份运维最佳实践
- 3-2-1 原则: 3 份数据备份, 2 种存储介质, 1 份异地存放
- 每月 1 次恢复演练: 在 stage 环境尝试实际恢复
- 备份完整性验证:
restic check,pgbackrest verify,medusa verify - 备份监控: 备份失败时发送通知 (Slack, email)
- 加密: 外部站点传输使用 TLS, 存储使用 LUKS/SSE-S3
- 权限隔离: 备份磁盘单独挂载 + read-only 挂载选项
- 文档化: 将恢复流程记录在运维团队共享的 wiki 中
相关文档
技术支持
备份 / 恢复相关咨询: webmaster@kopens.com