关于 tigris-snapshots-forking
Tigris Snapshots and Forking 介绍 Tigris 对象存储的存储桶快照与分叉操作,适用于需要恢复、测试或隔离数据副本的开发者。快照记录整个存储桶的时间点状态,分叉则基于快照创建隔离副本,删除副本内容不会影响源数据。
主要功能
- 01记录整个存储桶的时间点状态
- 02列出快照并按版本读取数据
- 03从快照创建隔离的存储桶分叉
- 04分叉采用写时复制机制
适用场景
- 01为生产数据创建开发沙箱
- 02为 Agent 环境准备数据副本
- 03执行迁移前备份与回滚
- 04使用生产数据进行负载测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tigrisdata/ skills --skill tigris-snapshots-forking安装后在 Claude Code 中输入/tigris-snapshots-forking确认已加载。
附带文件metadata.jsonREADME.md
详细介绍
Tigris 快照与分叉
前置条件
在进行任何操作之前,如果尚未安装 Tigris CLI,请先安装:
tigris help || npm install -g @tigrisdata/cli
如果需要安装,请告知用户:“我正在安装 Tigris CLI(@tigrisdata/cli),以便我们使用 Tigris 对象存储。”
概述
快照会捕获某一时刻整个存储桶的状态。分叉则使用写时复制,从快照即时创建隔离副本。
**核心原则:**快照和分叉可保护你的数据免遭删除。即使删除分叉中的所有内容,源存储桶中的数据仍会保持完整。
快照为何重要
对象存储是许多系统的主要数据存储。它需要具备安全功能:
- 时间点恢复 - 意外删除或数据损坏后进行恢复
- 版本控制 - 为发布等重要状态添加标签
- 可复现性 - 为调试或测试重建完全相同的环境
- 删除保护 - 销毁分叉不会影响源数据
传统的对象版本控制仅适用于单个对象。要将存储桶恢复到某个时间点,你必须逐个检查并恢复每个对象。Tigris 快照可以即时捕获整个存储桶的状态。
分叉为何重要
分叉可以即时创建隔离的存储桶副本,即使数据量达到数 TB 也不例外:
- 开发者沙箱 - 安全地使用真实生产数据进行测试
- AI Agent 环境 - 启动已预加载依赖项的 Agent
- 负载测试 - 使用生产数据,避免风险
- 功能分支测试 - 为实验创建并行环境
- 训练实验 - 分叉数据集进行测试,不影响源数据
**工作原理:**Tigris 使用带有逆序时间戳的不可变对象。分叉会从父快照读取数据,直到新数据覆盖这些数据。因此,分叉几乎无需成本——不需要复制数据。
快速参考
| 操作 | 函数 | 关键参数 |
|---|---|---|
| 创建快照 | createBucketSnapshot(options) | name, sourceBucketName |
| 列出快照 | listBucketSnapshots(sourceBucketName) | sourceBucketName |
| 创建分叉 | createBucket(name, options) | sourceBucketName, sourceBucketSnapshot |
创建快照
import { createBucketSnapshot } from "@tigrisdata/storage";
// Snapshot default bucket
const result = await createBucketSnapshot();
if (result.error) {
console.error("Error:", result.error);
} else {
console.log("Snapshot version:", result.data?.snapshotVersion);
// Output: { snapshotVersion: "1751631910169675092" }
}
// Named snapshot for specific bucket
const result = await createBucketSnapshot("my-bucket", {
name: "backup-before-migration",
});
if (result.error) {
console.error("Error:", result.error);
} else {
console.log("Named snapshot:", result.data?.snapshotVersion);
}
**前置条件:**创建存储桶时必须启用 enableSnapshot: true。
列出快照
import { listBucketSnapshots } from "@tigrisdata/storage";
// List snapshots for default bucket
const result = await listBucketSnapshots();
if (result.error) {
console.error("Error:", result.error);
} else {
console.log("Snapshots:", result.data);
// [
// {
// name: "backup-before-migration",
// version: "1751631910169675092",
// creationDate: Date("2025-01-15T08:30:00Z")
// }
// ]
}
// List snapshots for specific bucket
const result = await listBucketSnapshots("my-bucket");
从快照创建分叉
import { createBucket, createBucketSnapshot } from "@tigrisdata/storage";
// First, create a snapshot
const snapshot = await createBucketSnapshot("agent-seed", {
name: "agent-seed-v1",
});
const snapshotVersion = snapshot.data?.snapshotVersion;
// Fork from snapshot
const agentBucketName = `agent-${Date.now()}`;
const forkResult = await createBucket(agentBucketName, {
sourceBucketName: "agent-seed",
sourceBucketSnapshot: snapshotVersion,
});
if (forkResult.error) {
console.error("Error:", forkResult.error);
} else {
console.log("Forked bucket created");
// agent-${timestamp} has all data from agent-seed at snapshot time
// Can modify/delete freely - agent-seed is unaffected
}
读取快照版本中的数据
无需分叉即可访问历史数据:
import { get, list } from "@tigrisdata/storage";
// Get object as it was at snapshot
const result = await get("config.json", "string", {
snapshotVersion: "1751631910169675092",
});
// List objects as they were at snapshot
const result = await list({
snapshotVersion: "1751631910169675092",
});
删除保护实战
import { remove, get } from "@tigrisdata/storage";
// In forked bucket, delete everything
await remove("hello.txt", { config: { bucket: "agent-fork" } });
// Fork appears empty
const forkResult = await get("hello.txt", "string", {
config: { bucket: "agent-fork" },
});
// forkResult.error === "Not found"
// But source bucket still has data
const sourceResult = await get("hello.txt", "string", {
config: { bucket: "agent-seed" },
});
// sourceResult.data === "Hello, world!"
删除分叉中的内容只会影响该分叉。源数据仍可在父存储桶和所有快照中访问。
使用场景
开发者沙箱
// Create snapshot of production data
await createBucketSnapshot("production", {
name: "dev-sandbox-seed",
});
// Fork for each developer
const devBucket = await createBucket(`dev-${developerName}`, {
sourceBucketName: "production",
sourceBucketSnapshot: "...",
});
// Developer can test and modify freely
AI Agent 环境
// Store agent dependencies in seed bucket
await put("model.bin", modelData);
await put("config.json", agentConfig);
// Snapshot the seed
const snapshot = await createBucketSnapshot("agent-seed", {
name: "v1",
});
// Spin up new agent instance with fork
const agentBucket = `agent-${Date.now()}`;
await createBucket(agentBucket, {
sourceBucketName: "agent-seed",
sourceBucketSnapshot: snapshot.data?.snapshotVersion,
});
// Agent has everything and can modify freely
await startAgent(agentBucket);
迁移前备份
// Before risky operation
await createBucketSnapshot("production", {
name: "before-migration-v2",
});
// Run migration
// If disaster strikes, fork from snapshot to recover
const rollback = await createBucket("production-restored", {
sourceBucketName: "production",
sourceBucketSnapshot: "...",
});
常见错误
| 错误 | 解决方法 |
|---|---|
| 对未启用快照的存储桶创建快照 | 使用 enableSnapshot: true 重新创建存储桶 |
| 以为分叉会影响源数据 | 分叉彼此隔离——源数据保持不变 |
| 未为快照命名 | 命名有助于查找快照 |
| 使用错误的存储层级 | 快照存储桶必须使用 STANDARD 层级 |
限制
- 现有存储桶无法启用快照(必须创建新的存储桶)
- 快照存储桶需要使用 STANDARD 存储层级
- 快照存储桶不支持生命周期转换或 TTL
工作原理(深入解析)
快照是一个表示自 Unix 纪元以来纳秒数的单个 64 位整数。Tigris 使用逆序时间戳存储对象,因此最新版本排在最前面。创建快照时,Tigris 会记录当前时间。从快照读取时,会查询时间戳之前最新的对象版本。
分叉会增加递归间接层:子存储桶中的对象会覆盖父存储桶中的对象,但缺失的对象会递归地从父快照中读取。这使分叉可以瞬间完成——无需复制数据,只需添加元数据指针。