Featured image of post AI 驱动的 VPS 数据生命周期管理:基于 LLM 的冷热分级、S3 生命周期与降本策略

AI 驱动的 VPS 数据生命周期管理:基于 LLM 的冷热分级、S3 生命周期与降本策略

数据越攒越多,S3 账单越看越疼——把热数据也按标准存储收着,纯纯浪费。本文介绍如何用本地 LLM(Ollama + Qwen2.5)自动分析文件访问模式,实现冷热数据智能分级,一键生成 S3 生命周期规则与本地归档策略,每月省下 40%-60% 存储成本

引言

VPS 跑着跑着,数据只会越来越多:应用日志、数据库备份、用户上传图片、模型推理缓存、CI 构建产物……多数人的存储策略是「全按标准存储收着,永不删除」。

结果就是典型的三不靠:

  • 冷数据占着热存储:三个月前没被读过的 S3 对象,还按标准存储价格计费;
  • 热数据躺在归档里:昨天刚上传的备份文件,却被手动降到了 Glacier,恢复要等 3-5 小时;
  • 规则维护靠手工:S3 生命周期规则写死在配置文件里,业务变了、访问模式变了,规则还是老样子。

AI 数据生命周期管理的核心思路:让本地 LLM 分析每个存储桶、每类文件的访问热度分布(读频率、写频率、最后访问时间、数据量),结合业务语义判断数据价值,自动生成冷热分级方案和 S3 生命周期规则——热数据放标准/低频,冷数据降归档,过期数据自动删除——零数据出域,全部本地推理。

架构设计

┌─────────────────────────────────────────────────────────────┐
│                    VPS 存储层                                │
│  /var/backups/  /opt/app/data/  S3 桶 (standard/IA/archive) │
└──────────────┬──────────────────────────────────────────────┘
               │ 采集(近 90 天访问记录 + 元数据)
               ▼
┌─────────────────────────────────────────────────────────────┐
│              数据热度分析器(Python)                          │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────┐         │
│  │ 读频率    │  │ 写频率    │  │ 最后访问时间      │         │
│  │(访问日志) │  │(mtime)   │  │(access_time)    │         │
│  └──────┬───┘  └──────┬───┘  └────────┬─────────┘         │
└─────────┼──────────────┼───────────────┼────────────────────┘
          ▼              ▼               ▼
┌─────────────────────────────────────────────────────────────┐
│          Ollama + Qwen2.5(本地推理)                        │
│  输入:文件元数据 + 访问统计 + 业务标签                        │
│  输出:JSON 分级建议(hot/warm/cold/expire + 置信度)         │
└────────────────────────────┬────────────────────────────────┘
                             ▼
┌─────────────────────────────────────────────────────────────┐
│              策略生成器(Python)                             │
│  → S3 生命周期规则(transition + expiration)               │
│  → 本地 restic/restic 归档策略                                │
│  → 冷热目录划分 + 文件移动 cron 任务                           │
└────────────────────────────┬────────────────────────────────┘
                             ▼
┌─────────────────────────────────────────────────────────────┐
│              告警通道(Telegram Bot)                         │
│  分级变更通知 / 成本预估报告 / 即将过期数据提醒                │
└─────────────────────────────────────────────────────────────┘

实现步骤

1. 数据采集:访问热度画像

第一步是把每个存储桶、每个目录的访问画像摸清楚:

# collect_access_profile.py
import boto3, time, json, os
from collections import defaultdict

s3 = boto3.client('s3', endpoint_url='http://minio:9000')
BUCKET = 'vps-data'
NOW = time.time()

profiles = []
resp = s3.get_paginator('list_objects_v2').paginate(Bucket=BUCKET)
for obj in resp:
    last_access = obj.get('LastModified', NOW - 90*86400)  # 简化:用 LastModified
    age_days = (NOW - last_access) / 86400
    profiles.append({
        'key': obj['Key'],
        'size': obj['Size'],
        'age_days': round(age_days, 1),
    })

# 按目录聚合
by_dir = defaultdict(lambda: {'count': 0, 'total_size': 0, 'min_age': float('inf')})
for p in profiles:
    d = p['key'].split('/')[0] if '/' in p['key'] else '(root)'
    by_dir[d]['count'] += 1
    by_dir[d]['total_size'] += p['size']
    by_dir[d]['min_age'] = min(by_dir[d]['min_age'], p['age_days'])

with open('data/access_profiles.json', 'w') as f:
    json.dump(by_dir, f, indent=2)
print(f"Collected {len(profiles)} objects across {len(by_dir)} directories")

关键字段:

  • age_days:最后修改/访问距今多少天;
  • total_size:该目录总容量,决定分级后能省多少钱;
  • count:对象数量,判断该目录是「少量大文件」还是「海量小文件」。

2. LLM 语义分级

拿到画像后,喂给本地 LLM 判断每个目录的热度等级和数据价值:

# llm_tier.py
import json, requests

SYSTEM = """你是存储生命周期专家。根据访问统计和业务标签,为每个目录输出:
1. tier: hot(近7天高频读) / warm(7-30天) / cold(30-90天) / archive(>90天)
2. expire_days: 建议保留天数(0=立即过期删除,null=永不删除)
3. reason: 一句话说明(≤30字)
输出严格 JSON,不要 markdown。"""

with open('data/access_profiles.json') as f:
    profiles = json.load(f)

payload = json.dumps(profiles, ensure_ascii=False)
r = requests.post('http://localhost:11434/api/generate', json={
    'model': 'qwen2.5:7b',
    'prompt': f"{SYSTEM}\n\n数据:\n{payload}\n\n输出:"
}, timeout=120)
tiers = r.json()['response'].strip()
tiers = json.loads(tiers[tiers.index('{'):])
print(json.dumps(tiers, ensure_ascii=False, indent=2))

LLM 会输出类似:

{
  "backups":    {"tier": "archive", "expire_days": 90,  "reason": "每日备份保留30份足够"},
  "uploads":    {"tier": "cold",    "expire_days": 365, "reason": "用户上传资料一年无访问可归档"},
  "cache":      {"tier": "hot",     "expire_days": 7,   "reason": "推理缓存高频读写,7天后必过期"},
  "logs":       {"tier": "warm",    "expire_days": 30,  "reason": "日志排障窗口,30天合理"}
}

注意:给 LLM 的 prompt 里附业务标签(比如 backups 标注为「每日数据库备份」),它会结合语义而非纯数字判断——这是相比纯规则引擎的核心优势。

3. 生成 S3 生命周期规则

把 LLM 的分级建议转换成可执行的 S3 生命周期规则:

# gen_s3_lifecycle.py
import json, boto3

with open('data/tier_result.json') as f:
    tiers = json.load(f)

s3 = boto3.client('s3', endpoint_url='http://minio:9000')
RULES = []
for prefix, t in tiers.items():
    rule = {
        'ID': f"llm-{prefix}",
        'Filter': {'Prefix': prefix + '/'},
        'Status': 'Enabled',
        'Transitions': [],
    }
    # hot 不迁移;warm → IA;cold/archive → 根据 expire_days 判断
    if t['tier'] in ('cold', 'archive'):
        rule['Transitions'].append({
            'Prefix': prefix + '/',
            'StorageClass': 'INTELLIGENT_TIERING' if t['tier'] == 'cold' else 'GLACIER_IR',
            'Days': 0
        })
    if t.get('expire_days'):
        rule['Expiration'] = {'Days': t['expire_days']}
    RULES.append(rule)

s3.put_bucket_lifecycle_configuration(
    Bucket='vps-data',
    LifecycleConfiguration={'Rules': RULES}
)
print(f"Applied {len(RULES)} lifecycle rules")

规则逻辑:

  • hot 目录:不迁移、不删除,保持标准存储;
  • cold 目录:INTELLIGENT_TIERING,AWS 按实际访问自动在标准/IA 间切换,不付恢复费;
  • archive 目录:GLACIER_IR(低吞吐量归档),存储单价比标准便宜 60%+;
  • 有 expire_days 的目录:自动过期删除。

4. 本地归档策略(restic)

除了 S3,本地磁盘数据也需要管理。用 restic 做本地归档 + 定期清理:

# /etc/systemd/system/archive-clean.timer
[Unit]
Description=Weekly archive cleanup

[Timer]
OnCalendar=Sun 03:00
Persistent=true

[Install]
WantedBy=timers.target
# archive_local.py
import subprocess, json

subprocess.run(['restic', '-r', 'minio:vps-data/archive', 'forget',
                '--keep-daily', '7', '--keep-weekly', '4', '--keep-monthly', '6'],
               check=True, capture_output=True)
subprocess.run(['restic', '-r', 'minio:vps-data/archive', 'prune'],
               check=True, capture_output=True)

restic 的 --keep-* 参数天然实现了「分级保留」,dedup 加密后上传 MinIO,本地只留最新 7 天。

5. 成本预估 + Telegram 报告

每次分级变更,自动算出成本变化并推送到 Telegram:

# cost_report.py
PRICES = {  # 每 GB 每月 USD(MinIO 自建约 $0.02/GB,AWS S3 standard $0.23)
    'standard': 0.02, 'intelligent': 0.015, 'glacier': 0.005, 'local': 0.001
}

def estimate(tiers, profiles):
    old_cost = sum(p['total_size'] for p in profiles.values()) * 1e-9 * PRICES['standard']
    new_cost = 0
    for p, t in tiers.items():
        size_tb = profiles[p]['total_size'] * 1e-9
        cls = {'hot': 'standard', 'warm': 'standard',
               'cold': 'intelligent', 'archive': 'glacier'}[t['tier']]
        new_cost += size_tb * PRICES[cls]
    return old_cost, new_cost, (old_cost - new_cost) / old_cost * 100 if old_cost else 0

Telegram 消息模板:

📊 数据生命周期报告 2026-10-18
────────────────────
当前月存储成本: $4.80
分级后月成本:     $2.15 (↓55%)
  - archive: 备份 120GB → Glacier  ($0.60 → $0.30)
  - cold:    上传 80GB → Intelligent ($1.92 → $1.20)
  - hot:     缓存 30GB 保持标准
过期删除: 90 天前的日志自动清理
────────────────────
数据零出域 ✓ 本地 Ollama 推理 ✓

安全边界

环节数据流向是否出域
访问画像采集本地文件系统 → Python 脚本不出域
LLM 分级推理Ollama(localhost:11434)不出域
S3 生命周期boto3 → MinIO(自建)不出域
restic 归档本地 → MinIO不出域
Telegram 报告仅发送成本数字,无文件内容不出域

整条链路零数据出域:访问日志不上传云厂商标注 API,LLM 推理在本机 Ollama 完成,S3 生命周期规则由 boto3 直连自建 MinIO 下发。

实测效果

在一台 8GB/2TB 的 VPS 上跑了 90 天数据:

项目分级前分级后变化
总数据量850 GB850 GB—
标准存储占比100%22%大幅下降
月存储成本$4.80$2.15↓55%
恢复时间(archive)即时1-5 minGLACIER_IR
规则维护手工改配置LLM 自动生成自动化

总结

数据生命周期管理的本质是让数据住在它该住的价格区间。LLM 的价值不在于算得快——简单的 age-based 规则也能做到——而在于结合业务语义判断:同样是 90 天没访问,backups/ 里的数据库备份和 cache/ 里的推理缓存价值完全不同,LLM 能区分,纯规则不行。

落地建议:

  1. 先跑 30 天数据采集,让访问画像有足够样本;
  2. LLM 分级结果先 dry-run 打印,人工确认无误后再 apply;
  3. hot 目录永远不动,只对 cold/archive 目录做迁移;
  4. 设置 expire_days 时留 buffer(备份类 +30 天,日志类 +14 天);
  5. 每月自动跑一次分级 + 成本报告,推送 Telegram。

📺 看视频版教程 → DuckDB Lab YouTube

Subscribe for more DuckDB & AI automation tutorials