forked from scratchfoundation/scratch-gui
-
-
Notifications
You must be signed in to change notification settings - Fork 16
Closed
Description
概要
meshV2拡張機能のAWS AppSyncコストを追跡するため、切断後に予想コストをログに記録する機能を実装します。
関連ドキュメント
- meshV2コスト分析 - 詳細なコスト計算とシナリオ分析
コスト計算式
ホストの場合(1秒あたり)
const costPerSecond =
// Heartbeat
(1/15) * 0.000004 +
// REPORT_DATA (8回/秒と仮定、実際は変更検出による)
8 * 0.000004 +
// FIRE_EVENTS (2回/秒と仮定、実際はイベント発火頻度による)
2 * 0.000004 +
// LIST_GROUP_STATUSES (5分ごと)
(1/300) * 0.000004 +
// ON_DATA_UPDATE受信
(otherNodeCount * 8) * 0.000002 +
// ON_BATCH_EVENT受信
(otherNodeCount * 2) * 0.000002 +
// Subscription接続 (3種類)
(1/60) * 3 * (0.08/1000000);
// 他ノード1台の場合: 約 $0.00008693/秒メンバーの場合(1秒あたり)
const costPerSecond =
// Heartbeat
(1/120) * 0.000004 +
// REPORT_DATA (8回/秒と仮定)
8 * 0.000004 +
// FIRE_EVENTS (2回/秒と仮定)
2 * 0.000004 +
// LIST_GROUP_STATUSES (5分ごと)
(1/300) * 0.000004 +
// ON_DATA_UPDATE受信
(otherNodeCount * 8) * 0.000002 +
// ON_BATCH_EVENT受信
(otherNodeCount * 2) * 0.000002 +
// Subscription接続 (3種類)
(1/60) * 3 * (0.08/1000000);
// 他ノード1台の場合: 約 $0.00008360/秒実装箇所
ファイル: gui/scratch-vm/src/extensions/scratch3_mesh_v2/mesh-service.js
1. コスト追跡用の変数追加(constructorに追加)
constructor (blocks, meshId, domain) {
// ... 既存のコード ...
// Cost tracking
this.costTracking = {
connectionStartTime: null,
queryCount: 0, // LIST_GROUPS_BY_DOMAIN, LIST_GROUP_STATUSES
mutationCount: 0, // CREATE_DOMAIN, CREATE_GROUP, JOIN_GROUP, etc.
heartbeatCount: 0, // RENEW_HEARTBEAT, SEND_MEMBER_HEARTBEAT
reportDataCount: 0, // REPORT_DATA
fireEventsCount: 0, // FIRE_EVENTS
dataUpdateReceived: 0, // ON_DATA_UPDATE
batchEventReceived: 0, // ON_BATCH_EVENT
dissolveReceived: 0 // ON_GROUP_DISSOLVE
};
}2. 接続開始時刻の記録
// createGroup() メソッド内、成功時に追加
this.costTracking.connectionStartTime = Date.now();
// joinGroup() メソッド内、成功時に追加
this.costTracking.connectionStartTime = Date.now();3. 各GraphQL操作のカウント
// 各Query実行後に追加
this.costTracking.queryCount++;
// 各Mutation実行後(種別に応じて)
this.costTracking.mutationCount++;
// renewHeartbeat()とsendMemberHeartbeat()では
this.costTracking.heartbeatCount++;
// _reportData()では
this.costTracking.reportDataCount++;
// fireEventsBatch()では
this.costTracking.fireEventsCount++;
// handleDataUpdate()内
this.costTracking.dataUpdateReceived++;
// handleBatchEvent()内
this.costTracking.batchEventReceived++;
// ON_GROUP_DISSOLVE subscriptionのnextハンドラ内
this.costTracking.dissolveReceived++;4. 切断時のコスト計算とログ出力(cleanup()メソッドに追加)
cleanup () {
// コスト計算とログ出力
if (this.costTracking.connectionStartTime) {
const connectionDurationSeconds = (Date.now() - this.costTracking.connectionStartTime) / 1000;
const connectionDurationMinutes = connectionDurationSeconds / 60;
// Query/Mutation costs
const queryCost = this.costTracking.queryCount * 0.000004;
const mutationCost = this.costTracking.mutationCount * 0.000004;
// Subscription message costs
const dataUpdateCost = this.costTracking.dataUpdateReceived * 0.000002;
const batchEventCost = this.costTracking.batchEventReceived * 0.000002;
const dissolveCost = this.costTracking.dissolveReceived * 0.000002;
// Subscription connection cost (3 subscriptions)
const connectionCost = (connectionDurationMinutes / 1000000) * 3 * 0.08;
const totalCost = queryCost + mutationCost + dataUpdateCost + batchEventCost + dissolveCost + connectionCost;
log.info(`Mesh V2: Cost Summary for ${connectionDurationMinutes.toFixed(2)} minutes connection`);
log.info(` Role: ${this.isHost ? 'Host' : 'Member'}`);
log.info(` Queries: ${this.costTracking.queryCount} ops = $${queryCost.toFixed(8)}`);
log.info(` Mutations: ${this.costTracking.mutationCount} ops = $${mutationCost.toFixed(8)}`);
log.info(` - Heartbeats: ${this.costTracking.heartbeatCount}`);
log.info(` - REPORT_DATA: ${this.costTracking.reportDataCount}`);
log.info(` - FIRE_EVENTS: ${this.costTracking.fireEventsCount}`);
log.info(` Subscription Messages:`);
log.info(` - Data Updates: ${this.costTracking.dataUpdateReceived} msgs = $${dataUpdateCost.toFixed(8)}`);
log.info(` - Batch Events: ${this.costTracking.batchEventReceived} msgs = $${batchEventCost.toFixed(8)}`);
log.info(` - Dissolve: ${this.costTracking.dissolveReceived} msgs = $${dissolveCost.toFixed(8)}`);
log.info(` Subscription Connection: ${connectionDurationMinutes.toFixed(2)} min × 3 = $${connectionCost.toFixed(8)}`);
log.info(` TOTAL ESTIMATED COST: $${totalCost.toFixed(8)} (${(totalCost * 1000000).toFixed(2)} per million operations equivalent)`);
log.info(` Average cost per second: $${(totalCost / connectionDurationSeconds).toFixed(10)}`);
}
// 既存のクリーンアップ処理
this.pendingBroadcasts = [];
// ... 以下略 ...
}実装例の出力イメージ
Mesh V2: Cost Summary for 60.00 minutes connection
Role: Host
Queries: 13 ops = $0.00005200
- LIST_GROUPS_BY_DOMAIN: 1
- LIST_GROUP_STATUSES: 12
Mutations: 36,242 ops = $0.14496800
- Heartbeats: 240
- REPORT_DATA: 28,800
- FIRE_EVENTS: 7,200
Subscription Messages:
- Data Updates: 28,800 msgs = $0.05760000
- Batch Events: 7,200 msgs = $0.01440000
- Dissolve: 1 msgs = $0.00000200
Subscription Connection: 60.00 min × 3 = $0.00001440
TOTAL ESTIMATED COST: $0.21703640 (217.04 per million operations equivalent)
Average cost per second: $0.0000603435
テスト方法
- ホストとメンバーそれぞれで接続・切断を実行
- コンソールログでコストサマリーが出力されることを確認
- 計算値が妥当か検証(接続時間、操作回数など)
コスト分析結果のサマリー
1時間接続時の概算コスト
| シナリオ | 総ノード数 | 総コスト(USD/時) |
|---|---|---|
| ホスト1+メンバー1 | 2 | $0.43 |
| ホスト1+メンバー9 | 10 | $7.93 |
| 10グループ×40ノード | 400 | $1,180.89 |
1秒あたりの概算コスト(接続中)
- ホスト(他ノード1台): $0.00008693/秒
- メンバー(他ノード1台): $0.00008360/秒
コスト内訳の特徴
- 最大のコスト要因: Subscription受信メッセージ(特にREPORT_DATAの受信)
- グループ規模の影響: 他ノード数に比例してコスト増加
- ハートビートの影響: 全体コストの約0.5-1%程度(軽微)
優先度
Medium - 開発環境でのコスト把握と本番環境でのコスト監視のため
関連Issue
- EPIC: Mesh v2 拡張機能の実装 #444 - Mesh V2統合(完了)
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Metadata
Metadata
Assignees
Labels
No labels