mcpField
T
tigris-snapshots-forking

tigris-snapshots-forking

github.com/tigrisdata云与 DevOps2443 次安装14 周前更新
代码仓库

关于 tigris-snapshots-forking

Tigris Snapshots and Forking 介绍 Tigris 对象存储的存储桶快照与分叉操作,适用于需要恢复、测试或隔离数据副本的开发者。快照记录整个存储桶的时间点状态,分叉则基于快照创建隔离副本,删除副本内容不会影响源数据。

主要功能

  1. 01记录整个存储桶的时间点状态
  2. 02列出快照并按版本读取数据
  3. 03从快照创建隔离的存储桶分叉
  4. 04分叉采用写时复制机制

适用场景

  1. 01为生产数据创建开发沙箱
  2. 02为 Agent 环境准备数据副本
  3. 03执行迁移前备份与回滚
  4. 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 会记录当前时间。从快照读取时,会查询时间戳之前最新的对象版本。

分叉会增加递归间接层:子存储桶中的对象会覆盖父存储桶中的对象,但缺失的对象会递归地从父快照中读取。这使分叉可以瞬间完成——无需复制数据,只需添加元数据指针。

评论

支持 Markdown