Kuroco API パフォーマンス/コストレビュー
このスキルでやること
Admin MCP の読み取り専用ツールだけで、Kuroco サイトの 「どこに費用がかかっているか」「どのエンドポイントが遅い/キャッシュに乗っていないか」を 特定し、対策を費用対効果順に並べたレポートを作る。
調査の主軸はキャッシュである。Kuroco の従量課金はリクエスト件数が支配的で、 キャッシュに乗るかどうかで単価が一桁変わる。したがって 「リクエストを減らす」「キャッシュ比率を上げる」の 2 つが対策のほぼすべてになる。
このスキルは調査と提案までを担当する。 設定変更(キャッシュ期間・CORS・エンドポイント定義)は ユーザーの承認を得てから行い、原則として管理画面での実施を案内する(→ 変更の境界)。
前提
- Admin MCP に接続済みであること。 接続方法・認証・スコープは
/kuroco-admin-mcpを参照。 調査だけならx/all/readonlyまたはmcp:tools.readスコープで足りる - ツール名と引数は
tools/listの inputSchema が正。 本スキルに記載の引数は 実装から確認済みだが、呼ぶ前にtools/listで存在を確認する。 必要なモジュール:site(usage)、logs(api_analytics / api_log)、rcms_api(api) - Admin MCP のリクエスト自体も課金対象。 生ログの全件取得のような無駄打ちをしない
(集計は
api_analytics-list、生ログは必要な時間帯だけ)
課金モデル(最小限)
詳細は references/cost-model.md。ここでは判断に必須のものだけ。
- 費用 = ceil(実カウント ÷ UNIT) × 単価。 例: APIリクエストの UNIT が 1000hit・単価 55円なら、 100hit でも ceil(0.1)=1 → 55円
- キャッシュ HIT も課金される。 無料になるのではなく単価が下がるだけ。 「CDN で HIT しているから費用に関係ない」は誤り
- 請求は月内合算。ただしファイルストレージのみ集計期間の最大値が使われる
- 単価は契約により異なる。 金額を語るときは
usage-getの実績から 円/リクエストを逆算して使う(→ ステップ2) - 利用状況の表示項目と課金費目は 1:1 ではない。対応表は
references/cost-model.md
使うツール
| ツール | 用途 | 主な制約 |
|---|---|---|
usage-get |
月次/日次のコストと利用量。費目別の推移 | 接続中サイトのみ(site_id 指定不可)。日次系列は前日まで |
api_analytics-list |
エンドポイント別の集計(件数・平均実行時間・平均レスポンスサイズ) | 1回の範囲は最大35日。12時間制限・レート制限の対象外(実装で明示的に除外) |
api_log-list |
生ログ1行=1リクエスト(UA・国・referer・トークン・IP等) | 直近12時間のみ(timestamp_start で判定)。5秒スロットにメンバー単位で1回のレート制限 |
api-list |
API 定義の一覧(api_id・タイトル・セキュリティ) | — |
api_uri-list |
エンドポイント定義+直近8日間の利用集計とキャッシュ設定 | api_id 必須(API ごとに呼ぶ)。返却は uri_list[]。見るのは uri_data(→ references/mcp-tools.md) |
front_log-list / img_log-list / edge_log-list |
転送量の内訳切り分け(フロント/画像/Edge) | api_log と同じ12時間・レート制限 |
集計は api_analytics-list を優先する。 生ログは「集計では説明のつかない挙動」を
確かめるためだけに使う(1リクエスト1行なので、傾向を見る用途には高くつく)。
各ツールの引数・返却フィールド・値のフォーマットは references/mcp-tools.md。
返却値は表示用に整形された文字列("15.61 KB" "426 ms" "1,234hits"、
HIT 行の実行時間は " - ")である点に注意。フィルタ・ソートは生の数値に対して効く。
標準ワークフロー
依頼が「利用料が増えた原因を調べて」のような包括調査ならステップ1から順に実施する。 依頼が特定済みの症状(例: このエンドポイントが遅い)に限定されている場合は、 該当ステップだけを実施してよい(各ステップに省略条件を記載)。
ステップ1: コスト構造を把握する
// tool: usage-get
{ "ym": "<調査対象月 YYYY-MM>", "chart_begin_ym": "<開始月>", "chart_end_ym": "<終了月>" }
cost_monthlyが費目別の月次系列(key/disp_nm/data配列)。1回の呼び出しで 長期トレンドが取れるので、月ごとに呼び分けないcost_siteは接続中サイトのym月の費目別コスト、cost_all_sitesは親サイト配下の 全環境(dev/stg/prod 等)の合計。混同すると金額が過大になる。断りがなければcost_siteを使うusage_listは日別の生カウント(api_count/cached_api_count/api_traffic/db_bytes/files_bytesほか)+末尾に合計行。当日行は含まれない- 「増えた」の判定は前年同月または前月と、同じ日数で比較する。 進行中の月をそのまま比較しない
省略条件: 依頼が費用ではなく特定エンドポイントの性能に限定されている場合。
ステップ2: 単価を逆算する
同一月の費目別金額と usage_list 合計行(費目別カウント)から
円/リクエスト・円/GB を割り出す。キャッシュ有無の単価比を必ず出す
(この比が、以降のすべての優先順位を決める)。
cost_site は disp_nm / value だけで機械可読なキーを持たないため、
費目とカウントを機械的に対応づけるならキー付きの cost_monthly(該当月の要素)を使う。
得た単価は「この契約での実効単価」であり、公式価格表の転記ではない旨をレポートに書く。
省略条件: 金額に言及しないレポート(純粋な性能調査)の場合。
ステップ3: エンドポイント別に集計する
// tool: api_analytics-list
{ "timestamp_start": "<YYYY-MM-DD HH:MM>", "timestamp_end": "<YYYY-MM-DD HH:MM>",
"sort": "hit", "desc": true, "cnt": 100 }
- 返るのは
api_id(API タイトルに解決済み)・api_uri_id(/rcms-api/{id}/{uri}に解決済み)・request(HTTPメソッド)・cache_status・status・hit・execution_time(平均)・execution_time_additional(300ms超過分の合計 = コンピューティング課金の実体)・body_size(平均) - 同じ URI でも
cache_statusごとに別行になる。HIT 行と MISS 行を足して母数を作る - 比較の作り方が肝心: 前年同期(同じ日数)を別呼び出しで取得し、 まず全体の伸び率(=ベースライン)を出す。その上で 「ベースラインを大きく超えて伸びた/新規に現れた」エンドポイントだけを異常として扱う
- 1回の範囲は最大35日。年次比較は2回に分けて取得する
- フィルタは生の数値・生の api_id に対して効く(表示はタイトルでも
api_id = 3と書く)
省略条件: なし(このステップが調査の中核)。
ステップ4: キャッシュ設定と直近実績を突き合わせる
// tool: api-list(引数なし。MODE はサーバー側で付与される)
{}
// tool: api_uri-list
{ "api_id": <ステップ3で問題が出た API の api_id> }
uri_data にキャッシュ設定と直近8日間の利用集計が両方入っている:
cache_settings(JSON):maxage(キャッシュ秒数。未設定/0 ならキャッシュしていない)、cache_by_group(Topics::list / Topics::details のみ設定可能なグループ単位キャッシュ)rate_settings:limit_req/limit_slotapi_count/cached_api_count/body_avg/exec_avg(直近8日間。データなしは"-")
ここで「TTL 未設定なのか、TTL はあるのに当たっていないのか」を切り分ける。 この2つは対策がまったく違う(前者は設定、後者はキャッシュキーの分散か認証方式)。
省略条件: 依頼がコスト内訳の把握のみで、エンドポイント改善を含まない場合。
ステップ5: 生ログで裏を取る
集計だけでは説明できない現象(0バイト応答、400 の連発、想定外の referer、 クローラー比率、同一クライアントの連続呼び出し)を確認する場合のみ。
// tool: api_log-list
{ "timestamp_start": "<直近12時間内 YYYY-MM-DD HH:MM>", "timestamp_end": "<同上>",
"filter": "cache_status = \"MISS\"",
"columns": ["timestamp", "uri", "cache_status", "status", "body_size", "execution_time",
"request_user_agent", "geo_country_code", "request_referer", "api_access_token"],
"cnt": 200 }
- 12時間より前は取得できない。 過去の事象は
api_analytics-listで見る - 5秒に1回のレート制限。連続呼び出しは間隔を空ける
columnsで必要な列に絞る(ログ行は横に広い)- 30分〜1時間の代表サンプルを取り、比率で語る。サンプルから月次を外挿したら、 外挿である旨と根拠期間をレポートに明記する
省略条件: ステップ3・4で原因が特定でき、追加の仮説検証が不要な場合。
ステップ6: 症状から原因を特定する
references/diagnostics.md の症状別レシピを使う。代表例:
| 症状 | 主な原因 |
|---|---|
キャッシュ比率が低い(cached_api_count が小さい) |
maxage 未設定 / Cookie認証・動的トークンでキャッシュが分割 / PASS になる設計 |
| TTL は十分なのに MISS が多い | URL のカーディナリティが高い(詳細ページ)+クローラーの網羅巡回 |
| 1ページビューあたりのリクエストが多い | フロントの N+1 ファンアウト(一覧の各要素ごとに個別 API) |
| 同一 URI で PASS + 4xx が定常的に出る | フロントのバグ(未定義値をクエリに渡す等)。PASS は永久にキャッシュされない |
| 実行時間が長い | 300ms 超過分がコンピューティング課金。execution_time_additional で寄与を見る |
| 転送量が増えた | API・フロント・画像のどれかを費目で切り分けてから対策する |
| 0バイト応答が大量にある | CORS プリフライトの可能性(→ references/diagnostics.md の判別手順と確認方法) |
ステップ7: 対策を費用対効果順にまとめる
references/cache-tuning.md の対策カタログから、該当するものを選び、
削減見込み額・工数・副作用を添えて並べる。レポートの型は下記。
判断ルール
レポートの誤りは、ほぼこの 6 点のどれかから生まれる。
- 優先順位は「率」ではなく「金額の寄与」で決める。 増加率が最大の費目と、 増加額が最大の費目は一致しないことが多い
- 削減見込みは単純合計しない。 対策同士は削減対象が重なる。重なる場合は 「対策Aを先に実施すると対策Bの見込みは約N割に縮む」と明記する
- 相関から実装を断定しない。 ログから読み取った仕組み(例: リクエストの並び方から 推定したフロントの挙動)は仮説として書き、確認手段(フロント実装の確認・ ブラウザの HAR・レスポンスヘッダ・Kuroco サポートへの照会)まで書く
- 既に最適化されている項目を戻さない。 過去に急減している費目があれば、
その時期に入った最適化を打ち消す提案になっていないか確認する(推移は
cost_monthlyで分かる) - 単価・件数は必ず出典を書く(どのツールの、どの期間の値か)
- 分からなかったことを「限界」として明記する。 12時間しか遡れないログ、 サンプルからの外挿、未確認の仮説は、結論と同じ場所に並べて書く
変更の境界
| 操作 | 可否 |
|---|---|
| 読み取りツールでの調査 | そのまま実施してよい |
キャッシュ期間(maxage)の変更 |
api_uri-upsert の inputSchema に cache_settings は無く、渡すと拒否される。 MCP からは変更できないため、管理画面での手順を案内する(更新時に省略したフィールドは保持されるので、他の更新で既存設定が消えることはない) |
CORS 設定(cors.maxAge 等)の変更 |
api-upsert で可能。ユーザー承認必須。 反映は Access-Control-Max-Age の残存時間だけ遅れる |
| セキュリティ方式の変更(Cookie→静的トークン等) | api-upsert で可能。発行済みトークンが全て無効化されるため、フロント改修とセットでの計画が必要。承認必須 |
CDN キャッシュパージ(api-cdn_cache_purge) |
対象は api_uri_id(1件)/ api_uri_ids(複数)/ all: true(全エンドポイント)のちょうど 1 つで指定する(選択子なしは 400)。直後にオリジンへの MISS が集中する(all はサイト全体)。承認必須。調査目的では実行しない |
annotation キャッシュのパージ(api-annotation_cache_purge) |
全 API エンドポイントの CDN キャッシュも同時に破棄される。 承認必須。調査目的では実行しない |
| エンドポイントの作成・削除 | このスキルの範囲外。/kuroco-api-content を使う |
レポートの型
1. 結論(3行)— 何が費用/遅延の主因か、金額規模、最大の対策
2. コスト内訳と推移 — 費目別の差分と寄与率(出典: usage-get, 期間)
3. エンドポイント別の変化 — ベースライン成長率と、それを超えた異常値(出典: api_analytics-list, 期間)
4. 原因(要因ごとに: 根拠データ / 確定か仮説か / 影響度)
5. 対策一覧(費用対効果順: 削減見込み・工数・副作用・重複の注意)
6. 調査方法と限界(データ源・取得条件・未確認事項)
仮説と確定事実を同じ節に混ぜない。 後から誤りが判明した項目は、 消さずに「旧見立て/訂正後」の形で残すと、読み手が判断根拠を追える。
トラブルシューティング
| 症状 | 原因と対処 |
|---|---|
api_log-list がエラー/空 |
12時間より前を指定している。範囲を直近12時間内にする |
api_log-list がレート制限エラー |
5秒スロットにメンバー単位で1回の制限。間隔を空けて再実行する(api_analytics-list は対象外) |
api_analytics-list が範囲エラー |
1回の範囲は最大35日。期間を分割する |
usage-get に site_id を渡せない |
仕様。MCP は接続中サイトに束縛される。他環境は該当サイトの MCP エンドポイントに接続して調べる |
| 金額が想定より大きい | cost_all_sites(全環境合計)を読んでいないか確認する |
| フィルタが効かない | 表示値(API タイトル・"15.61 KB")ではなく生の値(api_id 数値・バイト数)で書く |
| ツールが見えない | スコープに site / logs / rcms_api が含まれているか確認(/kuroco-admin-mcp のチェックリスト) |
参照
| ファイル | 内容 |
|---|---|
references/mcp-tools.md |
各ツールの引数・返却フィールド・値のフォーマット・制約 |
references/cost-model.md |
課金モデル、利用状況項目と費目の対応、単価逆算の手順 |
references/diagnostics.md |
症状別の調査レシピ(クエリ例と判定基準) |
references/cache-tuning.md |
キャッシュ設計のレバー一覧と適用条件・副作用 |
他スキルとの連携
| スキル | 使い分け |
|---|---|
/kuroco-admin-mcp |
接続・認証・スコープ・ツール命名の基礎 |
/kuroco-api-content |
エンドポイント設計・認証方式・filter クエリの書き方 |
/kuroco-frontend-integration |
SSG 化・フロント側のリクエスト削減 |
/kuroco-server-processing |
内部API呼び出し({api_internal} / {api_method})の課金差、purge_cdn_cache |
/kuroco-docs |
公式ドキュメント(利用状況・APIキャッシュ・利用料の最適化)の原文確認 |