一、为什么要给Prometheus TSDB做备份?

很多人刚用Prometheus的时候,只关心能不能存数据、能不能查指标,忽略了最关键的备份,直到碰到数据丢失才后悔。我之前帮一个做电商的客户处理过一个故障:他们的Prometheus用了半年,某天磁盘空间满了,服务器管理员不知道怎么回事,直接把/var/lib下面的大目录删了,结果Prometheus的存储目录被误删,半个月的订单监控数据全没了,排查双11前的风险时,连核心指标都拿不出来,最后花了3天才补回数据,损失了不少业务进度。

1.1 常见的数据丢失场景

Prometheus的存储数据丢失一般有几种情况:第一种是磁盘空间告警不及时,系统自动清理大文件,把Prometheus的存储目录删了;第二种是运维人员误操作,比如打rm -rf的时候手滑选错路径;第三种是Prometheus版本升级时,旧数据格式不兼容,导致新进程读不了;第四种是服务器硬件故障,比如存储盘挂了,数据全丢。这些场景不管碰到哪个,都会让之前的监控积累白费,甚至影响业务判断。

1.2 备份的核心价值

备份的目的不是为了折腾,而是为了在数据出问题的时候,能快速恢复,减少损失。具体来说,一是能恢复丢失的监控数据,比如刚才的电商客户,如果有备份,10分钟就能恢复;二是能做历史数据的归档,比如把超过3个月的监控数据备份到低成本存储,不用占服务器的空间;三是能做故障排查的依据,比如要查过去某个时间点的指标,不用依赖Prometheus的在线存储,直接用备份数据分析。

二、适合生产环境的备份方案设计

做Prometheus备份的时候,不能随便打个tar包就完事,要考虑生产环境的几个核心需求:数据不能有缺失、备份不影响业务、备份能恢复、备份不会占爆空间。

2.1 方案选型的核心思路

首先要保证数据一致性:就是备份的时候,Prometheus不能写数据,否则备份的是"半完成"的文件,恢复的时候可能出错;然后要考虑业务可用性:如果是7*24小时的环境,不能随便停Prometheus,所以最好有不用停的方案;然后要做自动化,不能靠人工天天备份,容易忘;最后要保留合理的备份数量,比如保留7天的全量备份,或者保留最近的几个,不要占满磁盘。

2.2 核心方案的细节设计

最终我们设计的方案分两部分:基础方案(适合非核心业务,能接受短暂 downtime)和进阶方案(适合生产环境,不用停Prometheus)。基础方案就是停止Prometheus,拷贝存储目录,启动Prometheus,简单直接;进阶方案是用Prometheus的快照API,不用停服务,生成快照后拷贝快照目录。

三、生产环境实施的详细步骤

这里我们用shell脚本做自动化,所有操作都可以直接复制粘贴到服务器上用,不需要复杂的工具。

3.1 前置准备

首先要确认Prometheus的存储路径,这个可以去配置文件里找,一般默认配置在/etc/prometheus/prometheus.yml里,找storage.tsdb.path这一行,用shell命令查看:

# 查看Prometheus的存储路径
cat /etc/prometheus/prometheus.yml | grep -E 'storage.tsdb.path'

如果输出是storage.tsdb.path: /var/lib/prometheus,那这个路径就是我们要备份的目录。另外,要准备一个独立的磁盘或者目录来存备份,比如/data/prometheus_backup,这个目录不能和Prometheus的存储盘在同一个服务器,防止服务器挂了备份也没了。

3.2 基础备份脚本示例(需停止Prometheus)

这个脚本适合非核心业务,能接受1分钟左右的 downtime,写好后放到/usr/local/bin/下面,名字叫prometheus_backup_basic.sh:

#!/bin/bash
# --------------------------配置区,根据实际情况修改--------------------------
# Prometheus的存储路径
PROMETHEUS_DATA="/var/lib/prometheus"
# 备份的存储目录(独立磁盘)
BACKUP_BASE="/data/prometheus_backup"
# 要保留的备份数量,比如保留7天的备份
MAX_BACKUP=7
# Prometheus的系统服务名,不同系统可能不一样,比如有的是prometheus.service
PROMETHEUS_SERVICE="prometheus"
# --------------------------配置结束--------------------------

# 生成带时间戳的备份目录,方便区分
BACKUP_DIR="${BACKUP_BASE}/$(date +%Y%m%d_%H%M%S)"

# 检查备份目录是否存在,不存在就创建
mkdir -p "${BACKUP_DIR}"

echo "Starting Prometheus basic backup at $(date)"

# 停止Prometheus,保证数据一致性
systemctl stop "${PROMETHEUS_SERVICE}"

# 用rsync拷贝数据,比cp更高效,还能增量同步
rsync -av --delete "${PROMETHEUS_DATA}/" "${BACKUP_DIR}/prometheus/"

# 启动Prometheus,恢复服务
systemctl start "${PROMETHEUS_SERVICE}"

echo "Prometheus stopped and started successfully"

# 删除超过保留数量的旧备份,按时间排序,保留最新的MAX_BACKUP个
cd "${BACKUP_BASE}" || exit 1
# 按时间倒序排,取第MAX_BACKUP+1个之后的,就是要删除的旧备份
ls -t | tail -n +$((MAX_BACKUP + 1)) | xargs rm -rf

# 记录备份日志,方便排查问题
echo "[$(date)] Basic backup completed: ${BACKUP_DIR}" >> /var/log/prometheus_backup.log

这个脚本里的每一行都有注释,解释了为什么这么做,比如--delete参数是让备份目录和源目录完全一致,防止有多余的文件;用rsync比cp好,因为如果中间断了,下次可以继续,不用重新拷全部数据。

3.3 定时任务配置

要让备份自动执行,需要用crontab,这是Linux里的定时任务工具,执行命令:

# 编辑当前用户的crontab
crontab -e

然后在最后一行添加,比如每天凌晨2点执行备份,这个时候业务量小,不会影响服务:

0 2 * * * /bin/bash /usr/local/bin/prometheus_backup_basic.sh

保存退出后,crontab就会自动加载这个任务了。

3.4 进阶备份脚本(无需停止Prometheus,生产环境用)

如果是生产环境,不能停Prometheus,就用快照API的方式,这个API是Prometheus自带的,专门用来生成一致性快照,不需要停服务。脚本示例:

#!/bin/bash
# --------------------------配置区,根据实际情况修改--------------------------
BACKUP_BASE="/data/prometheus_backup"
MAX_BACKUP=7
PROMETHEUS_API="http://localhost:9090"  # Prometheus的API地址,本地的话用localhost
# --------------------------配置结束--------------------------

BACKUP_DIR="${BACKUP_BASE}/$(date +%Y%m%d_%H%M%S)"
mkdir -p "${BACKUP_DIR}"

echo "Starting Prometheus hot backup at $(date)"

# 调用API生成快照,返回的是JSON格式,用jq提取快照的名字
SNAPSHOT_RESPONSE=$(curl -X POST "${PROMETHEUS_API}/api/v1/admin/tsdb/snapshot")
# 检查API调用是否成功,如果返回的是error就退出
if echo "${SNAPSHOT_RESPONSE}" | grep -q '"status":"success"'; then
  # 提取快照的目录名
  SNAPSHOT_NAME=$(echo "${SNAPSHOT_RESPONSE}" | jq -r '.data.name')
  SNAPSHOT_PATH="/var/lib/prometheus/snapshots/${SNAPSHOT_NAME}"
  # 拷贝快照到备份目录
  cp -r "${SNAPSHOT_PATH}" "${BACKUP_DIR}/prometheus_snapshot/"
  echo "Snapshot created at: ${SNAPSHOT_PATH}"
else
  echo "Snapshot failed: ${SNAPSHOT_RESPONSE}" >> /var/log/prometheus_backup.log
  exit 1
fi

# 清理旧备份
cd "${BACKUP_BASE}" || exit 1
ls -t | tail -n +$((MAX_BACKUP +1)) | xargs rm -rf

echo "[$(date)] Hot backup completed: ${BACKUP_DIR}" >> /var/log/prometheus_backup.log

这个脚本用了jq工具,用来处理API返回的JSON,要先安装jq,命令是apt install jq(Debian/Ubuntu)或者yum install jq(CentOS/RHEL),这个工具很常用,用来解析JSON数据。

3.5 备份数据的恢复示例

万一数据丢了,怎么用备份恢复?比如基础方案的恢复:

#!/bin/bash
# --------------------------配置区,根据实际情况修改--------------------------
BACKUP_BASE="/data/prometheus_backup"
PROMETHEUS_DATA="/var/lib/prometheus"
PROMETHEUS_SERVICE="prometheus"
# --------------------------配置结束--------------------------

# 找最新的备份目录
LATEST_BACKUP=$(ls -t "${BACKUP_BASE}" | head -n1)
BACKUP_PATH="${BACKUP_BASE}/${LATEST_BACKUP}/prometheus"

if [ -z "${LATEST_BACKUP}" ]; then
  echo "No backup found at $(date)" >> /var/log/prometheus_restore.log
  exit 1
fi

echo "Starting restore from backup: ${LATEST_BACKUP} at $(date)"

# 停止Prometheus
systemctl stop "${PROMETHEUS_SERVICE}"

# 清空当前Prometheus的存储目录,注意这里会删所有现有数据,所以要确认是最新备份
rm -rf "${PROMETHEUS_DATA:?}/*"  # 这里加了:?防止变量为空,误删目录

# 拷贝备份数据到Prometheus的存储目录
cp -r "${BACKUP_PATH}/"* "${PROMETHEUS_DATA}/"

# 启动Prometheus
systemctl start "${PROMETHEUS_SERVICE}"

echo "Restore completed successfully from ${LATEST_BACKUP} at $(date)" >> /var/log/prometheus_restore.log

这里要注意,清空存储目录的时候,用了${PROMETHEUS_DATA:?},这个是防止如果变量为空,误删根目录,是个很实用的小技巧,避免灾难。

四、方案的优缺点分析

4.1 方案优势

不管是基础方案还是进阶方案,都有几个优点:一是实现简单,不需要额外的复杂工具,只要会写shell脚本就能搞定;二是自动化,定时执行不用人工干预;三是成本低,只要一个独立磁盘就能存备份,不用花钱买专用的备份系统;四是可恢复性,只要备份没坏,就能快速恢复数据。

4.2 不足与改进方向

基础方案的不足是需要停服务,对于7*24小时的生产环境来说,停1分钟可能都会影响业务;进阶方案用快照API的话,虽然不用停服务,但备份的是全量快照,每次备份都要拷全部数据,数据量大的话备份时间长、占空间大。改进方向可以用增量备份,或者用专业的备份工具比如wal-g,这个工具支持Prometheus TSDB的增量备份、压缩,还能存到对象存储,节省空间的同时实现异地备份,不过wal-g的配置稍微复杂一点,适合有一定运维经验的团队。

五、应用场景与注意事项

5.1 适用场景

这个方案适合几种场景:第一种是中小团队的Prometheus监控平台,没有专门的运维团队,需要快速搭建备份;第二种是测试环境的Prometheus,防止误操作删除大量测试数据;第三种是需要归档历史监控数据的场景,把超过3个月的监控数据备份到低成本存储,节省服务器空间;第四种是对监控数据可靠性要求中等的生产环境,比如非核心业务的监控。

5.2 生产环境的注意事项

生产环境用的时候,一定要注意这几点:第一,备份目录一定要和Prometheus的存储目录在不同的磁盘,最好在不同的服务器,防止服务器整体故障导致备份丢失;第二,一定要定期测试恢复,比如每个月选一个时间,用最新的备份恢复一次,确认数据是好的,不然真出事的时候备份是坏的就白搭;第三,备份日志要定期查看,比如每天看/var/log/prometheus_backup.log,确认备份有没有成功,有没有报错;第四,如果用进阶方案的快照API,不要随便把Prometheus的API暴露到公网,防止被恶意调用,导致生成大量快照占空间;第五,备份的文件要做加密,如果备份存在公共存储,比如对象存储,要加密,防止数据泄露。

六、总结

给Prometheus的TSDB做备份,核心是"简单实用、可靠可恢复",不需要追求高大上的方案,从能快速落地的基础方案开始,再根据生产环境的需求逐步优化。很多人怕备份麻烦,但真碰到数据丢失的时候,就知道备份的重要性了。刚才的示例都是可以直接用的,只要根据实际情况修改配置路径,就能立刻搭建起自动化的备份体系,让Prometheus的监控数据不再是"没了就没了"的可有可无的数据,而是可靠的业务支撑。