【TDengine 使用环境】
生产环境 /测试/ Poc/预生产环境
【TDengine 版本】
3.3.8.4-oss
【操作系统以及版本】
centonOS7.9
【部署方式】容器/非容器部署
非容器部署
【集群节点数】
【集群副本数】
【描述业务影响】
源服务器A:td_1,源服务器B:td_2,定时同步到服务器C:td_1,首次全量后面增量,两个服务器不会有相同的超级表和其子表,数据字段不变。
【问题复现路径/shan】做过哪些操作出现的问题
【遇到的问题:问题现象及影响】
下面是我的shell脚本,看看行吗?
源A:
#!/bin/bash
源A:td_8bu 备份同步脚本(修复时间差,避免丢数据)
set -euo pipefail
配置项
DB_NAME=“td_8bu”
SOURCE_ID=“src_a”
LOCAL_BACKUP_ROOT=“/taos/data/taos_incr_backup_${SOURCE_ID}”
RECORD_FILE=“${LOCAL_BACKUP_ROOT}/last_backup_endtime.txt”
TAOS_HOST=“localhost”
TAOS_PORT=“6030”
LOCAL_LOG_FILE=“${LOCAL_BACKUP_ROOT}/backup_sync.log”
KEEP_DAYS=180
TIME_OFFSET=30 # 时间回退秒数,覆盖备份耗时的时间差
目标服务器配置
TARGET_IP=“xxx.xx.xxx.xx”
TARGET_USER=“root”
TARGET_BACKUP_ROOT=“/taos/data/taos_backup_sync/${SOURCE_ID}”
TARGET_RECORD_FILE=“${TARGET_BACKUP_ROOT}/last_backup_endtime.txt”
1. 初始化目录
mkdir -p ${LOCAL_BACKUP_ROOT}
chmod 755 ${LOCAL_BACKUP_ROOT}
ssh ${TARGET_USER}@${TARGET_IP} “mkdir -p ${TARGET_BACKUP_ROOT} && chmod 755 ${TARGET_BACKUP_ROOT}” >> ${LOCAL_LOG_FILE} 2>&1
函数:时间回退(ISO8601格式回退N秒)
offset_time() {
local ISO_TIME=$1
local OFFSET=$2
转换为时间戳 → 减OFFSET秒 → 转回ISO8601
TIMESTAMP=$(date -d “${ISO_TIME}” +%s)
NEW_TIMESTAMP=$((TIMESTAMP - OFFSET))
date -d “@${NEW_TIMESTAMP}” +“%Y-%m-%dT%H:%M:%S+0800”
}
2. 备份逻辑
echo -e “\n===== $(date +”%Y-%m-%d %H:%M:%S") 源${SOURCE_ID}-${DB_NAME} 开始备份 =====" >> ${LOCAL_LOG_FILE}
if [ ! -f ${RECORD_FILE} ]; then
FULL_PATH=“${LOCAL_BACKUP_ROOT}/${SOURCE_ID}full$(date +”%Y%m%d%H%M%S")"
mkdir -p ${FULL_PATH}
全量备份:E参数用当前时间,记录时回退TIME_OFFSET秒
BACKUP_END=$(date +“%Y-%m-%dT%H:%M:%S+0800”)
taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -D ${DB_NAME} -E “${BACKUP_END}” -o ${FULL_PATH} >> ${LOCAL_LOG_FILE} 2>&1
同步全量备份到目标服务器
scp -r ${FULL_PATH} ${TARGET_USER}@${TARGET_IP}:${TARGET_BACKUP_ROOT}/ >> ${LOCAL_LOG_FILE} 2>&1
记录回退后的时间(避免漏数据)
RECORD_END=$(offset_time “${BACKUP_END}” ${TIME_OFFSET})
echo “${RECORD_END}” > ${RECORD_FILE}
同步记录文件到C端
scp ${RECORD_FILE} ${TARGET_USER}@${TARGET_IP}:${TARGET_RECORD_FILE} >> ${LOCAL_LOG_FILE} 2>&1
echo “源${SOURCE_ID}全量备份完成,记录时间(回退${TIME_OFFSET}秒):${RECORD_END}” >> ${LOCAL_LOG_FILE}
else
LAST_END=$(cat ${RECORD_FILE})
增量备份:E参数用当前时间,S参数用上次记录的时间(已回退,无需再改)
BACKUP_END=$(date +“%Y-%m-%dT%H:%M:%S+0800”)
INCR_PATH=“${LOCAL_BACKUP_ROOT}/${SOURCE_ID}incr$(echo ${LAST_END} | sed ‘s/[-T:+]//g’ | cut -c1-14)_$(date +”%Y%m%d%H%M%S")"
mkdir -p ${INCR_PATH}
增量备份:-S 用上次记录的时间(已回退),-E 用当前时间
taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -S “${LAST_END}” -E “${BACKUP_END}” -D ${DB_NAME} -o ${INCR_PATH} >> ${LOCAL_LOG_FILE} 2>&1
同步增量备份到目标服务器
scp -r ${INCR_PATH} ${TARGET_USER}@${TARGET_IP}:${TARGET_BACKUP_ROOT}/ >> ${LOCAL_LOG_FILE} 2>&1
记录回退后的结束时间
RECORD_END=$(offset_time “${BACKUP_END}” ${TIME_OFFSET})
echo “${RECORD_END}” > ${RECORD_FILE}
同步记录文件到C端
scp ${RECORD_FILE} ${TARGET_USER}@${TARGET_IP}:${TARGET_RECORD_FILE} >> ${LOCAL_LOG_FILE} 2>&1
echo “源${SOURCE_ID}增量备份完成,记录时间(回退${TIME_OFFSET}秒):${RECORD_END}” >> ${LOCAL_LOG_FILE}
fi
3. 清理180天前备份
find ${LOCAL_BACKUP_ROOT} -type d -name “${SOURCE_ID}full" -o -name "${SOURCE_ID}incr” -mtime +${KEEP_DAYS} -exec rm -rf {} ;
ssh ${TARGET_USER}@${TARGET_IP} “find ${TARGET_BACKUP_ROOT} -type d -name ‘${SOURCE_ID}full’ -o -name '${SOURCE_ID}incr’ -mtime +${KEEP_DAYS} -exec rm -rf {} ;”
源B:
#!/bin/bash
源B:td_8bu_1 备份同步脚本(修复时间差,避免丢数据)
set -euo pipefail
配置项(仅修改SOURCE_ID和DB_NAME,其余与源A一致)
DB_NAME=“td_8bu_1”
SOURCE_ID=“src_b” # 源B标识
LOCAL_BACKUP_ROOT=“/taos/data/taos_incr_backup_${SOURCE_ID}”
RECORD_FILE=“${LOCAL_BACKUP_ROOT}/last_backup_endtime.txt”
TAOS_HOST=“localhost”
TAOS_PORT=“6030”
LOCAL_LOG_FILE=“${LOCAL_BACKUP_ROOT}/backup_sync.log”
KEEP_DAYS=180
TIME_OFFSET=30 # 时间回退秒数,覆盖备份耗时的时间差(与源A保持一致)
目标服务器配置(与源A一致)
TARGET_IP=“xxx.xx.xxx.xx”
TARGET_USER=“root”
TARGET_BACKUP_ROOT=“/taos/data/taos_backup_sync/${SOURCE_ID}”
TARGET_RECORD_FILE=“${TARGET_BACKUP_ROOT}/last_backup_endtime.txt”
1. 初始化目录
mkdir -p ${LOCAL_BACKUP_ROOT}
chmod 755 ${LOCAL_BACKUP_ROOT}
ssh ${TARGET_USER}@${TARGET_IP} “mkdir -p ${TARGET_BACKUP_ROOT} && chmod 755 ${TARGET_BACKUP_ROOT}” >> ${LOCAL_LOG_FILE} 2>&1
函数:时间回退(ISO8601格式回退N秒,与源A完全一致)
offset_time() {
local ISO_TIME=$1
local OFFSET=$2
转换为时间戳 → 减OFFSET秒 → 转回ISO8601
TIMESTAMP=$(date -d “${ISO_TIME}” +%s)
NEW_TIMESTAMP=$((TIMESTAMP - OFFSET))
date -d “@${NEW_TIMESTAMP}” +“%Y-%m-%dT%H:%M:%S+0800”
}
2. 备份逻辑(仅日志标识适配src_b,其余逻辑与源A一致)
echo -e “\n===== $(date +”%Y-%m-%d %H:%M:%S") 源${SOURCE_ID}-${DB_NAME} 开始备份 =====" >> ${LOCAL_LOG_FILE}
if [ ! -f ${RECORD_FILE} ]; then
FULL_PATH=“${LOCAL_BACKUP_ROOT}/${SOURCE_ID}full$(date +”%Y%m%d%H%M%S")"
mkdir -p ${FULL_PATH}
全量备份:E参数用当前时间,记录时回退TIME_OFFSET秒
BACKUP_END=$(date +“%Y-%m-%dT%H:%M:%S+0800”)
taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -D ${DB_NAME} -E “${BACKUP_END}” -o ${FULL_PATH} >> ${LOCAL_LOG_FILE} 2>&1
同步全量备份到目标服务器C
scp -r ${FULL_PATH} ${TARGET_USER}@${TARGET_IP}:${TARGET_BACKUP_ROOT}/ >> ${LOCAL_LOG_FILE} 2>&1
记录回退后的时间(避免漏数据)
RECORD_END=$(offset_time “${BACKUP_END}” ${TIME_OFFSET})
echo “${RECORD_END}” > ${RECORD_FILE}
同步记录文件到C端
scp ${RECORD_FILE} ${TARGET_USER}@${TARGET_IP}:${TARGET_RECORD_FILE} >> ${LOCAL_LOG_FILE} 2>&1
echo “源${SOURCE_ID}全量备份完成,记录时间(回退${TIME_OFFSET}秒):${RECORD_END}” >> ${LOCAL_LOG_FILE}
else
LAST_END=$(cat ${RECORD_FILE})
增量备份:E参数用当前时间,S参数用上次记录的时间(已回退,无需再改)
BACKUP_END=$(date +“%Y-%m-%dT%H:%M:%S+0800”)
INCR_PATH=“${LOCAL_BACKUP_ROOT}/${SOURCE_ID}incr$(echo ${LAST_END} | sed ‘s/[-T:+]//g’ | cut -c1-14)_$(date +”%Y%m%d%H%M%S")"
mkdir -p ${INCR_PATH}
增量备份:-S 用上次记录的时间(已回退),-E 用当前时间
taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -S “${LAST_END}” -E “${BACKUP_END}” -D ${DB_NAME} -o ${INCR_PATH} >> ${LOCAL_LOG_FILE} 2>&1
同步增量备份到目标服务器C
scp -r ${INCR_PATH} ${TARGET_USER}@${TARGET_IP}:${TARGET_BACKUP_ROOT}/ >> ${LOCAL_LOG_FILE} 2>&1
记录回退后的结束时间
RECORD_END=$(offset_time “${BACKUP_END}” ${TIME_OFFSET})
echo “${RECORD_END}” > ${RECORD_FILE}
同步记录文件到C端
scp ${RECORD_FILE} ${TARGET_USER}@${TARGET_IP}:${TARGET_RECORD_FILE} >> ${LOCAL_LOG_FILE} 2>&1
echo “源${SOURCE_ID}增量备份完成,记录时间(回退${TIME_OFFSET}秒):${RECORD_END}” >> ${LOCAL_LOG_FILE}
fi
3. 清理180天前备份(与源A逻辑一致)
find ${LOCAL_BACKUP_ROOT} -type d -name “${SOURCE_ID}full" -o -name "${SOURCE_ID}incr” -mtime +${KEEP_DAYS} -exec rm -rf {} ;
ssh ${TARGET_USER}@${TARGET_IP} “find ${TARGET_BACKUP_ROOT} -type d -name ‘${SOURCE_ID}full’ -o -name '${SOURCE_ID}incr’ -mtime +${KEEP_DAYS} -exec rm -rf {} ;”
目标服务器C:
#!/bin/bash
目标服务器C:合并两个源库到td_8bu(全量+增量标记均独立存储,适配3.3.8.4)
set -euo pipefail
配置项
TARGET_DB=“td_8bu”
BACKUP_ROOT=“/taos/data/taos_backup_sync”
SRC_A_DIR=“${BACKUP_ROOT}/src_a” # 源A备份目录
SRC_B_DIR=“${BACKUP_ROOT}/src_b” # 源B备份目录
源端备份结束时间文件(源端同步过来)
SRC_A_BACKUP_END=“${SRC_A_DIR}/last_backup_endtime.txt”
SRC_B_BACKUP_END=“${SRC_B_DIR}/last_backup_endtime.txt”
独立标记文件(全量+增量,完全脱离日志)
SRC_A_FULL_RESTORED=“${SRC_A_DIR}/restored_full.txt” # src_a全量恢复记录
SRC_A_INCR_RESTORED=“${SRC_A_DIR}/restored_incr.txt” # src_a增量恢复记录
SRC_B_FULL_RESTORED=“${SRC_B_DIR}/restored_full.txt” # src_b全量恢复记录
SRC_B_INCR_RESTORED=“${SRC_B_DIR}/restored_incr.txt” # src_b增量恢复记录
TAOS_HOST=“localhost”
TAOS_PORT=“6030”
LOG_FILE=“${BACKUP_ROOT}/merge_restore.log”
KEEP_DAYS=180
关键:初始化目录+所有独立标记文件(首次执行自动创建空文件)
mkdir -p ${BACKUP_ROOT} ${SRC_A_DIR} ${SRC_B_DIR}
chmod 755 ${BACKUP_ROOT} ${SRC_A_DIR} ${SRC_B_DIR}
初始化全量/增量标记文件(避免文件不存在报错)
touch ${SRC_A_FULL_RESTORED} ${SRC_A_INCR_RESTORED}
touch ${SRC_B_FULL_RESTORED} ${SRC_B_INCR_RESTORED}
chmod 644 ${SRC_A_FULL_RESTORED} ${SRC_A_INCR_RESTORED}
chmod 644 ${SRC_B_FULL_RESTORED} ${SRC_B_INCR_RESTORED}
初始化日志(仅用于记录过程,不再用于恢复判断)
echo -e “\n===== $(date +”%Y-%m-%d %H:%M:%S") 开始合并恢复 =====" >> ${LOG_FILE}
函数:时间格式转换(ISO8601 → 纯数字,仅日志展示)
convert_time() {
local TIME_STR=$1
echo “${TIME_STR}” | sed ‘s/[-T:+]//g’ | cut -c1-14
}
函数:恢复单个源(全量+增量均查独立标记文件,完全脱离日志)
restore_source() {
local SRC_DIR=“$1” # 源备份目录(src_a/src_b)
local SRC_BACKUP_END=“$2” # 源端备份结束时间文件
local FULL_RESTORED=“$3” # 全量恢复标记文件
local INCR_RESTORED=“$4” # 增量恢复标记文件
local RENAME_RULE=“$5” # 库重命名规则(源B用)
local SOURCE_ID=“$6” # 源标识(src_a/src_b)
echo -e “\n===== 开始处理${SOURCE_ID}数据 =====” >> ${LOG_FILE}
步骤1:检查源端是否有备份记录
if [ ! -f “${SRC_BACKUP_END}” ]; then
echo “【${SOURCE_ID}】警告:未找到源端备份记录文件,跳过” >> ${LOG_FILE}
return
fi
读取源端最新备份结束时间(仅日志展示)
SRC_LAST_BACKUP_ISO=$(cat “${SRC_BACKUP_END}”)
SRC_LAST_BACKUP_NUM=$(convert_time “${SRC_LAST_BACKUP_ISO}”)
echo “【${SOURCE_ID}】源端最新备份结束时间:${SRC_LAST_BACKUP_ISO}(纯数字:${SRC_LAST_BACKUP_NUM})” >> ${LOG_FILE}
步骤2:恢复最新全量备份(查独立全量标记文件,不再查日志)
set +e
找源端最新全量备份(按时间降序取第一个)
SRC_FULL=$(ls -d “${SRC_DIR}/${SOURCE_ID}full”* 2>/dev/null | sort -r | head -n 1)
set -e
if [ -n “${SRC_FULL}” ]; then
FULL_NAME=$(basename “${SRC_FULL}”)
# 核心改:查全量标记文件,判断是否已恢复
FULL_HAS_RESTORED=$(grep -Fq “${FULL_NAME}” “${FULL_RESTORED}” && echo “yes” || echo “no”)
if [ "${FULL_HAS_RESTORED}" = "no" ]; then
echo "【${SOURCE_ID}】首次恢复,执行全量备份恢复:${FULL_NAME}" >> ${LOG_FILE}
eval "taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -i ${SRC_FULL} -D ${TARGET_DB} ${RENAME_RULE}" >> ${LOG_FILE} 2>&1
if [ $? -eq 0 ]; then
echo "【${SOURCE_ID}】全量备份恢复完成:${FULL_NAME}" >> ${LOG_FILE}
# 写入全量标记文件(追加模式,避免覆盖)
echo "${FULL_NAME}" >> "${FULL_RESTORED}"
echo "【${SOURCE_ID}】全量标记已写入:${FULL_RESTORED}" >> ${LOG_FILE}
else
echo "【${SOURCE_ID}】错误:全量备份恢复失败,终止" >> ${LOG_FILE}
exit 1
fi
else
echo "【${SOURCE_ID}】全量备份已恢复,跳过:${FULL_NAME}" >> ${LOG_FILE}
fi
else
echo “【${SOURCE_ID}】警告:无全量备份,跳过” >> ${LOG_FILE}
return
fi
步骤3:筛选增量备份(查独立增量标记文件)
set +e
INCR_LIST=$(ls -d “${SRC_DIR}/${SOURCE_ID}incr”* 2>/dev/null | sort)
set -e
过滤已恢复的增量(查独立增量标记文件)
INCR_UNRESTORED=()
if [ -n “${INCR_LIST}” ]; then
for INCR in ${INCR_LIST}; do
INCR_NAME=$(basename “${INCR}”)
if ! grep -Fq “${INCR_NAME}” “${INCR_RESTORED}”; then
INCR_UNRESTORED+=(“${INCR}”)
fi
done
fi
if [ ${#INCR_UNRESTORED[@]} -eq 0 ]; then
echo “【${SOURCE_ID}】无未恢复的增量备份,跳过” >> ${LOG_FILE}
return
fi
遍历未恢复的增量,执行恢复
for INCR in “${INCR_UNRESTORED[@]}”; do
INCR_NAME=$(basename “${INCR}”)
INCR_END_NUM=$(echo “${INCR_NAME}” | awk -F ‘_’ ‘{print $5}’)
echo "【${SOURCE_ID}】开始恢复增量备份:${INCR_NAME}(增量结束时间:${INCR_END_NUM})" >> ${LOG_FILE}
eval "taosdump -h ${TAOS_HOST} -P ${TAOS_PORT} -i ${INCR} -D ${TARGET_DB} ${RENAME_RULE}" >> ${LOG_FILE} 2>&1
if [ $? -eq 0 ]; then
echo "【${SOURCE_ID}】增量备份恢复完成:${INCR_NAME}" >> ${LOG_FILE}
# 写入增量标记文件
echo "${INCR_NAME}" >> "${INCR_RESTORED}"
echo "【${SOURCE_ID}】增量标记已写入:${INCR_RESTORED}" >> ${LOG_FILE}
else
echo "【${SOURCE_ID}】错误:增量备份${INCR_NAME}恢复失败,终止" >> ${LOG_FILE}
exit 1
fi
done
}
1. 确保目标库存在(适配3.3.8.4语法)
echo “【初始化】创建/检查目标库${TARGET_DB}” >> ${LOG_FILE}
taos -s “CREATE DATABASE IF NOT EXISTS ${TARGET_DB} KEEP 365 BLOCK_SIZE 10;” >> ${LOG_FILE} 2>&1
if [ $? -ne 0 ]; then
echo “【错误】目标库创建失败,查看日志:${LOG_FILE}” >> ${LOG_FILE}
echo “目标库创建失败!”
exit 1
fi
2. 恢复源A(传入全量+增量标记文件)
restore_source “${SRC_A_DIR}” “${SRC_A_BACKUP_END}” “${SRC_A_FULL_RESTORED}” “${SRC_A_INCR_RESTORED}” “” “src_a”
3. 恢复源B(传入全量+增量标记文件)
restore_source “${SRC_B_DIR}” “${SRC_B_BACKUP_END}” “${SRC_B_FULL_RESTORED}” “${SRC_B_INCR_RESTORED}” “-W td_8bu_1=td_8bu” “src_b”
4. 清理180天前备份(仅删备份目录,保留所有标记文件)
echo -e “\n===== 开始清理${KEEP_DAYS}天前的备份 =====” >> ${LOG_FILE}
find “${BACKUP_ROOT}” -type d ( -name “src_full” -o -name “src_incr” ) -mtime +${KEEP_DAYS} -exec rm -rf {} ; >> ${LOG_FILE} 2>&1
echo “【清理】180天前备份清理完成(保留全量/增量恢复标记文件)” >> ${LOG_FILE}
收尾
echo -e “\n===== $(date +”%Y-%m-%d %H:%M:%S") 合并恢复完成 =====\n" >> ${LOG_FILE}
echo “两个源库合并恢复到${TARGET_DB}完成!(全量/增量标记均独立存储)”
echo “src_a全量恢复记录:${SRC_A_FULL_RESTORED}”
echo “src_a增量恢复记录:${SRC_A_INCR_RESTORED}”
echo “src_b全量恢复记录:${SRC_B_FULL_RESTORED}”
echo “src_b增量恢复记录:${SRC_B_INCR_RESTORED}”
echo “详细日志:${LOG_FILE}”
【资源配置】
【报错完整截图】(不要大段的粘贴报错代码,论坛直接看报错代码不直观)