tigris-egress-optimizer について
Tigris のオブジェクトストレージで過剰なデータ転送費用を診断し、削減するスキルです。開発者が利用状況やコードのパターンを調べ、キャッシュや配信方法を見直し、帯域幅の変化を検証できます。
主な機能
- 01バケットの帯域幅とオブジェクトサイズの確認
- 02転送量が増えるコードパターンの検出
- 03全体ダウンロードに代わるメタデータ確認
- 04キャッシュヘッダーと直接配信の適用
- 05帯域幅の変化を継続的に検証
活用シーン
- 01想定外に高いストレージ転送費用の調査
- 02静的アセットの再ダウンロード削減
- 03アプリサーバー経由のオブジェクト配信回避
- 04小さな画像サムネイルの配信
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tigrisdata/ skills --skill tigris-egress-optimizerインストール後、Claude Code で/tigris-egress-optimizerを入力して読み込まれたか確認します。
同梱ファイルmetadata.jsonREADME.md
詳細
Tigris Egress Optimizer
過剰なストレージのエグレス(ネットワークデータ転送)コストを診断して削減します。この4段階のフレームワークに従って、アンチパターンを特定し、修正を適用して、削減効果を確認してください。
エグレス料金が高額になる原因の大半は、インフラストラクチャの問題ではなく、アプリケーションが使用する量を超えるデータを取得していることです。
前提条件
ほかの作業を始める前に、まだインストールされていない場合は Tigris CLI をインストールしてください。
tigris help || npm install -g @tigrisdata/cli
インストールが必要な場合は、ユーザーに「Tigris のオブジェクトストレージを使用するため、Tigris CLI(@tigrisdata/cli)をインストールします。」と伝えてください。
ステップ 1:診断
どのバケットとアクセスパターンが最も多くの帯域幅を消費しているかを特定します。
帯域幅メトリクスを確認する
# Check bucket usage
tigris usage
# List objects by size (find large files being served frequently)
tigris ls t3://my-bucket --recursive -l | sort -k3 -rn | head -20
確認する項目
- 帯域幅が最も大きいバケットはどれですか?
- 大容量のファイルが繰り返しダウンロードされていますか?
- オブジェクトにはアプリサーバー経由でアクセスしていますか、それとも直接アクセスしていますか?
- ユーザーに表示されないオブジェクトがダウンロードされていますか?
ステップ 2:コードベースを分析する
アプリケーションのコードを調べ、次のような一般的なアンチパターンがないか確認します。
アンチパターンのチェックリスト
| アンチパターン | 症状 | 影響 |
|---|---|---|
| メタデータの取得にオブジェクト全体をダウンロードする | head() で十分な場面で get() を使用している | 高 — ファイル全体をダウンロードします |
| 変更されないアセットを再ダウンロードする | 静的コンテンツ用のキャッシュレイヤーがない | 高 — 帯域幅が繰り返し消費されます |
| アプリサーバー経由でプロキシする | サーバーがダウンロードしてからクライアントに再配信する | 帯域幅が2倍(Tigris→サーバー + サーバー→クライアント) |
| Cache-Control ヘッダーが設定されていない | ブラウザーがページ読み込みのたびに再取得する | 非常に高 — ユーザー数に応じて増加します |
| CDN を使用していない | 公開コンテンツにプライベートバケットを使用している | 中 — 単一のオリジンで、エッジキャッシュがありません |
| サムネイル用にオブジェクト全体をダウンロードする | 100px のサムネイルを表示するために5MBの画像を取得している | 高 — 必要な量の50倍のデータを使用します |
コード検索
コードベースで次のパターンを探してください。
# Downloads that should be head() calls
grep -rn "get(" --include="*.ts" --include="*.js" | grep -v "test"
# Missing cache headers on put()
grep -rn "put(" --include="*.ts" --include="*.js" | grep -v "cacheControl\|Cache-Control"
# Server-side file proxying
grep -rn "pipe\|stream\|createReadStream" --include="*.ts" --include="*.js"
ステップ 3:修正
修正 1:メタデータには get() ではなく head() を使用する
// Before — downloads entire file just to check if it exists
const result = await get("avatars/user-123.jpg", "file");
if (result.error) console.log("not found");
// After — only fetches metadata (size, contentType, modified)
const result = await head("avatars/user-123.jpg");
if (result.error) console.log("not found");
console.log(result.data?.size, result.data?.contentType);
修正 2:Cache-Control ヘッダーを追加する
// Set cache headers on upload
await put("assets/logo.png", file, {
access: "public",
contentType: "image/png",
});
推奨されるキャッシュ値:
| コンテンツの種類 | Cache-Control |
|---|---|
| ハッシュ化されたアセット(JS、CSS) | public, max-age=31536000, immutable |
| 画像(アバター、アップロード) | public, max-age=86400(1日) |
| 動的コンテンツ | private, no-cache |
| フォント | public, max-age=31536000, immutable |
修正 3:CDN 用にパブリックバケットを使用する
Tigris のパブリックバケットは最も近いグローバルエッジから自動的に配信されるため、別途 CDN を設定する必要はありません。
# Make bucket public
tigris buckets create my-public-assets --public
# Or update existing bucket
tigris buckets update my-bucket --public
パブリックバケットの URL は Tigris のグローバルエッジネットワークから配信されます。これにより、基本的な静的アセットの配信では、CloudFront、Cloudflare などの CDN レイヤーが不要になります。
修正 4:署名付き URL を使用する(サーバー経由のプロキシを回避する)
// Before — server downloads file, then sends to client (2x egress)
app.get("/download/:path", async (req, res) => {
const result = await get(req.params.path, "stream");
result.data.pipe(res);
});
// After — redirect client to download directly from Tigris (1x egress)
app.get("/download/:path", async (req, res) => {
const result = await getPresignedUrl(req.params.path, {
operation: "get",
expiresIn: 300,
});
res.redirect(result.data!.url);
});
修正 5:サムネイルを別に保存する
// Before — serving 5MB original for a 100px avatar
<img src="/api/files/avatars/user-123.jpg" width="100" />
// After — generate and store thumbnail on upload
import sharp from "sharp";
const thumb = await sharp(originalBuffer)
.resize(100, 100, { fit: "cover" })
.jpeg({ quality: 80 })
.toBuffer();
await put("avatars/user-123-thumb.jpg", thumb, {
access: "public",
contentType: "image/jpeg",
});
// Serve the 5KB thumbnail instead of the 5MB original
修正 6:ETag を使用したクライアント側キャッシュ
// Server returns ETag on first request
app.get("/api/config", async (req, res) => {
const result = await head("config/app.json");
const etag = result.data?.modified?.toISOString();
if (req.headers["if-none-match"] === etag) {
return res.status(304).end(); // No body sent, no egress
}
const file = await get("config/app.json", "string");
res.set("ETag", etag);
res.json(JSON.parse(file.data));
});
修正 7:リージョンを固定する
リージョン間転送を減らすため、データをコンピューティングリソースの近くに保管します。
# Pin bucket to specific regions
tigris buckets create my-bucket --locations us-east-1,eu-west-1
ステップ 4:確認
修正を適用した後、次のことを行います。
- 帯域幅を監視する — Tigris のダッシュボードで帯域幅が減少しているか確認します
- 修正前後を比較する — 1~2週間、帯域幅を追跡します
- アラートを設定する — 想定外の帯域幅急増を検知できるよう、監視を設定します
- 定期的に見直す — 新機能によって新たなアンチパターンが生じる可能性があります
すぐにできる改善策のまとめ
| 修正 | 作業量 | 影響 |
|---|---|---|
| Cache-Control ヘッダーを追加する | 低 | 高 |
| パブリックバケット(CDN)に切り替える | 低 | 高 |
| プロキシの代わりに署名付き URL を使用する | 中 | 高 |
チェック処理で get() を head() に置き換える | 低 | 中 |
| サムネイルを別に保存する | 中 | 高 |
| リージョンを固定する | 低 | 中 |
重要なルール
必ず行うこと: ユーザーに配信するコンテンツにはパブリックバケットを使用する | すべてのアップロードで Cache-Control ヘッダーを設定する | プライベートファイルのダウンロードには署名付き URL を使用する | 存在確認やメタデータの確認には head() を使用する
決して行わないこと: 署名付き URL が使える場合に、アプリサーバー経由でファイルをプロキシする | サムネイルで十分な場合に、元の画像を配信する | 不変のアセットのキャッシュを省略する | 帯域幅のメトリクスを無視する
関連スキル
- tigris-image-optimization — サムネイルとバリエーションを生成する
- tigris-static-assets — キャッシュヘッダーを使用した CDN 配信
- tigris-lifecycle-management — アクセス頻度の低いデータをより安価な階層に移動する