树莓派搭建NAS之五:数据同步
- 树莓派
- 10天前
- 61热度
- 0评论
数据同步
由于使用的是32GU盘作为nas存储盘,用不了几天就会出现磁盘空间被占满的情况,需要将nas中存储的录像记录,同步存储到阿里云盘中,并且删除历史的视频释放空间。
定时任务
直接通过ai写一个shell脚本,定时执行就完事了。给ai提出诉求:
- 将源端文件存在、目标端不存在的文件进行同步
- 仅比较文件文件大小,不比较时间和md5值(阿里网盘不允许修改文件时间)
- 启动定时任务,1小时执行1次
vim /opt/sync_xiaomi_camera.sh 文件:
#!/bin/bash
# =============================================
# 小米摄像头视频同步脚本(带磁盘清理)
# 功能:自动清理源端旧文件 + 同步新文件
# 作者:AI 助手
# =============================================
# -------------------------------
# 配置区
# -------------------------------
# 源目录(小米摄像头存储路径)
SOURCE_DIR="/srv/dev-disk-by-uuid-0987bf77-xxxxx/smb_xiaomi_vidoes/XiaomiCamera_00_xxxxx"
# 目标目录(如阿里云盘挂载点)
DEST_DIR="/mnt/aliyun/XiaomiCamera_00_xxxxx"
# 日志文件
LOG_FILE="/var/log/sync_xiaomi_camera.log"
# 网络检测目标
PING_TARGET="223.5.5.5"
TIMEOUT=5
# 磁盘清理阈值(百分比)
DISK_USAGE_THRESHOLD_HIGH=70 # 超过此值开始清理
DISK_USAGE_THRESHOLD_LOW=50 # 清理到此值以下停止
# -------------------------------
# 日志函数
# -------------------------------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
# -------------------------------
# 检查网络连通性
# -------------------------------
check_network() {
log "INFO: 正在检测网络连通性,目标: $PING_TARGET"
if command -v ping >/dev/null 2>&1; then
if ping -c 2 -W $TIMEOUT "$PING_TARGET" >/dev/null 2>&1; then
log "INFO: 网络连通性检测成功"
return 0
else
log "ERROR: ping 到 $PING_TARGET 失败"
return 1
fi
else
log "WARNING: 未安装 ping,尝试使用 curl 检测..."
fi
if command -v curl >/dev/null 2>&1; then
if curl -m $TIMEOUT --head --silent --fail "http://alidns.com" >/dev/null 2>&1; then
log "INFO: curl 检测成功,网络可达"
return 0
else
log "ERROR: curl 检测失败,无法访问外网"
return 1
fi
else
log "ERROR: 未安装 curl 或 ping,无法检测网络"
return 1
fi
}
# -------------------------------
# 检查挂载点
# -------------------------------
check_mounts() {
local mount1=$(findmnt -n -o TARGET /mnt/aliyun)
local mount2=$(findmnt -n -o TARGET /srv/dev-disk-by-uuid-0987bf77-xxxxx)
if [ -z "$mount1" ]; then
log "ERROR: /mnt/aliyun 未挂载"
return 1
fi
if [ -z "$mount2" ]; then
log "ERROR: /srv/dev-disk-by-uuid-... 未挂载"
return 1
fi
log "INFO: 所有挂载点已就绪"
return 0
}
# -------------------------------
# 清理源端磁盘空间(自动删除最老文件)
# -------------------------------
cleanup_source_disk() {
local mount_point=$(dirname "$SOURCE_DIR")
if [ ! -d "$mount_point" ]; then
log "ERROR: 源挂载点不存在: $mount_point"
return 1
fi
# 获取当前磁盘使用率
local current_usage
current_usage=$(df -P "$mount_point" | tail -1 | awk '{print $5}' | tr -d '%')
if ! [[ "$current_usage" =~ ^[0-9]+$ ]]; then
log "ERROR: 无法获取磁盘使用率"
return 1
fi
log "INFO: 当前源磁盘使用率: ${current_usage}% (阈值: >${DISK_USAGE_THRESHOLD_HIGH}% 开始清理,<${DISK_USAGE_THRESHOLD_LOW}% 停止)"
if [ $current_usage -le $DISK_USAGE_THRESHOLD_HIGH ]; then
log "INFO: 磁盘使用率正常,跳过清理"
return 0
fi
log "WARN: 磁盘使用率过高 (${current_usage}% > ${DISK_USAGE_THRESHOLD_HIGH}%),开始清理旧文件..."
local deleted_count=0
# 按修改时间升序(最老的在前)删除 .mp4 文件
while IFS= read -r file; do
[ ! -f "$file" ] && continue
local filename=$(basename "$file")
log "INFO: 删除旧文件: $filename"
if rm -f "$file"; then
((deleted_count++))
log "INFO: 已删除: $filename"
else
log "ERROR: 删除失败: $filename"
continue
fi
# 重新检查磁盘使用率
current_usage=$(df -P "$mount_point" | tail -1 | awk '{print $5}' | tr -d '%')
if ! [[ "$current_usage" =~ ^[0-9]+$ ]]; then
log "ERROR: 获取磁盘使用率失败,停止清理"
break
fi
log "INFO: 删除后磁盘使用率: ${current_usage}%"
# 如果已降到 50% 以下,停止
if [ $current_usage -le $DISK_USAGE_THRESHOLD_LOW ]; then
log "INFO: 磁盘使用率已降至 ${current_usage}% ≤ ${DISK_USAGE_THRESHOLD_LOW}%,停止清理"
break
fi
done < <(find "$SOURCE_DIR" -type f -name "*.mp4" -printf '%T@ %p\n' | sort -n | cut -d' ' -f2-)
log "INFO: 共清理 $deleted_count 个旧文件"
}
# -------------------------------
# 执行同步(基于文件名+大小)
# -------------------------------
sync_files() {
if [ ! -d "$SOURCE_DIR" ]; then
log "ERROR: 源目录不存在: $SOURCE_DIR"
return 1
fi
mkdir -p "$DEST_DIR"
log "INFO: 开始同步所有 .mp4 文件(基于文件名+大小判断)"
log "INFO: 源目录: $SOURCE_DIR"
log "INFO: 目标目录: $DEST_DIR"
START_TIME=$(date +%s)
# 核心同步命令:只同步 .mp4,仅根据大小判断是否传输
OUTPUT=$(rsync -rtv --size-only \
--include='*.mp4' \
--exclude='*' \
--info=progress2,stats2 \
"$SOURCE_DIR/" "$DEST_DIR/" 2>&1)
RSYNC_EXIT_CODE=$?
echo "$OUTPUT" | tee -a "$LOG_FILE"
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
HOURS=$((DURATION / 3600))
MINUTES=$(((DURATION % 3600) / 60))
SECONDS=$((DURATION % 60))
ELAPSED_TIME=$(printf "%02d:%02d:%02d" $HOURS $MINUTES $SECONDS)
FILES_TRANSFERRED=$(echo "$OUTPUT" | grep "Number of files transferred" | awk '{print $4}' || echo 0)
TOTAL_BYTES=$(echo "$OUTPUT" | grep "Total bytes sent" | awk '{print $4}' || echo 0)
if [ $RSYNC_EXIT_CODE -eq 0 ]; then
log "INFO: 同步成功"
else
log "ERROR: rsync 执行失败,退出码: $RSYNC_EXIT_CODE"
fi
log "INFO: 任务开始时间: $(date -d "@$START_TIME" '+%Y-%m-%d %H:%M:%S')"
log "INFO: 任务结束时间: $(date -d "@$END_TIME" '+%Y-%m-%d %H:%M:%S')"
log "INFO: 总耗时: $ELAPSED_TIME"
log "INFO: 成功同步文件数量: $FILES_TRANSFERRED"
log "INFO: 传输总大小(字节): $TOTAL_BYTES"
log "------------------------------------------------------------"
}
# -------------------------------
# 主函数
# -------------------------------
main() {
log "=== 新的同步任务启动 ==="
# 1. 清理源端磁盘(如果使用率 >70%)
cleanup_source_disk
# 2. 检查网络
if ! check_network; then
log "ERROR: 网络不可达,跳过本次同步"
log "------------------------------------------------------------"
exit 1
fi
# 3. 检查挂载
if ! check_mounts; then
log "ERROR: 挂载点未就绪,跳过同步"
log "------------------------------------------------------------"
exit 1
fi
# 4. 执行同步
sync_files
}
# -------------------------------
# 创建日志目录并执行
# -------------------------------
LOG_DIR=$(dirname "$LOG_FILE")
[ ! -d "$LOG_DIR" ] && mkdir -p "$LOG_DIR"
main "$@"
添加到crontab中
crontab -e
添加以下任务
0 * * * * bash /opt/sync_xiaomi_camera.sh
查看结果
tail -f /var/log/sync_xiaomi_camera.log
显示结果为:
[2025-10-03 12:40:06] === 新的同步任务启动 ===
[2025-10-03 12:40:06] INFO: 当前源磁盘使用率: 23% (阈值: >70% 开始清理,<50% 停止)
[2025-10-03 12:40:06] INFO: 磁盘使用率正常,跳过清理
[2025-10-03 12:40:06] INFO: 正在检测网络连通性,目标: 223.5.5.5
[2025-10-03 12:40:07] INFO: 网络连通性检测成功
[2025-10-03 12:40:07] INFO: 所有挂载点已就绪
[2025-10-03 12:40:08] INFO: 开始同步所有 .mp4 文件(基于文件名+大小判断)
[2025-10-03 12:40:08] INFO: 源目录: /srv/dev-disk-by-uuid-0987bf77-xxxxx/smb_xiaomi_vidoes/XiaomiCamera_00_xxxxx
[2025-10-03 12:40:08] INFO: 目标目录: /mnt/aliyun/XiaomiCamera_00_xxxxx
sending incremental file list
0 0% 0.00kB/s 0:00:00 (xfr#0, to-chk=0/45)
Number of files: 45 (reg: 44, dir: 1)
Number of created files: 0
Number of deleted files: 0
Number of regular files transferred: 0
Total file size: 5,905,580,032 bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 2,058
Total bytes received: 148
sent 2,058 bytes received 148 bytes 4,412.00 bytes/sec
total size is 5,905,580,032 speedup is 2,677,053.50
[2025-10-03 12:40:08] INFO: 同步成功
[2025-10-03 12:40:08] INFO: 任务开始时间: 2025-10-03 12:40:08
[2025-10-03 12:40:08] INFO: 任务结束时间: 2025-10-03 12:40:08
[2025-10-03 12:40:08] INFO: 总耗时: 00:00:00
[2025-10-03 12:40:08] INFO: 成功同步文件数量:
[2025-10-03 12:40:08] INFO: 传输总大小(字节): 2,058
[2025-10-03 12:40:08] ------------------------------------------------------------