From d51e907ceec8239ad3321787ccf715ac21f7f1b7 Mon Sep 17 00:00:00 2001 From: amos Date: Wed, 31 Dec 2025 17:34:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=E6=95=B0=E6=8D=AE=E7=9A=84=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup.sh | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 backup.sh diff --git a/backup.sh b/backup.sh new file mode 100644 index 0000000..8139eba --- /dev/null +++ b/backup.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Memory 数据库备份脚本 +# 功能:备份 SQLite 数据库到 R2,保留最近 7 天的备份 + +set -e + +# ============ 配置区域 ============ +# R2 配置 +R2_ACCOUNT_ID="ebf33b5ee4eb26f32af0c6e06102e000" +R2_ACCESS_KEY_ID="8acbc8a9386d60d0e8dac6bd8165c618" +R2_ACCESS_KEY_SECRET="72935e23b5b4be8fda99008e75285e8ac778f8926656c42780b25785bb149443" +R2_BUCKET_NAME="memory" +R2_BACKUP_PATH="memory-backup" + +# 数据库路径 +DB_PATH="/amos/memory/data/memory.db" + +# 备份保留天数 +KEEP_DAYS=7 + +# 日志文件 +LOG_FILE="/var/log/memory-backup.log" + +# ============ 函数定义 ============ + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +# 上传备份到 R2 +upload_backup() { + local backup_file=$1 + local remote_name=$2 + + AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ + aws s3 cp "$backup_file" "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/${remote_name}" \ + --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" +} + +# 清理旧备份,只保留最近 N 天 +cleanup_old_backups() { + log "清理旧备份..." + + # 列出所有备份文件,按时间倒序排列 + local backup_list=$(AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ + aws s3 ls "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/" \ + --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" \ + | grep "memory-.*\.db" \ + | sort -r \ + | awk '{print $4}') + + # 跳过前 N 个(最新的),删除其余的 + local count=0 + for backup in $backup_list; do + count=$((count + 1)) + if [ $count -gt $KEEP_DAYS ]; then + log " 删除: $backup" + AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ + aws s3 rm "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/${backup}" \ + --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" + fi + done + + if [ $count -le $KEEP_DAYS ]; then + log " 无需清理,当前共 ${count} 个备份" + else + log " 已清理 $((count - KEEP_DAYS)) 个旧备份" + fi +} + +# ============ 主流程 ============ + +log "========== 开始备份 ==========" + +# 检查数据库文件是否存在 +if [ ! -f "$DB_PATH" ]; then + log "❌ 数据库文件不存在: $DB_PATH" + exit 1 +fi + +# 生成备份文件名(带日期) +DATE=$(date '+%Y-%m-%d') +BACKUP_NAME="memory-${DATE}.db" +TEMP_BACKUP="/tmp/${BACKUP_NAME}" + +# 使用 sqlite3 的 .backup 命令进行热备份(避免数据损坏) +log "备份数据库..." +sqlite3 "$DB_PATH" ".backup '$TEMP_BACKUP'" + +# 上传到 R2 +log "上传到 R2..." +upload_backup "$TEMP_BACKUP" "$BACKUP_NAME" + +# 清理临时文件 +rm -f "$TEMP_BACKUP" + +# 清理旧备份 +cleanup_old_backups + +log "✅ 备份完成: ${BACKUP_NAME}" +log "========== 备份结束 =========="