Carina の開発中に、AWS Cloud Control APIが遅いことに気づいた。
CarinaでAWSリソースを扱うにあたり、最初はaws-sdk-s3を使ってS3バケットの操作を実装していた。ただ、この方法だとリソースタイプごとに個別実装が必要になる。S3、EC2、IAM...とAWSのサービスは膨大にあるので、全部個別に実装するのは大変だ。生成AIがあるとはいえ、もっと楽にできないかと考えた。
そこで Cloud Control API を使うことを考えた。Cloud Control APIは、CloudFormationと同じリソースハンドラーを使った統一的なAPIで、様々なAWSリソースをCRUD操作できる。
Cloud Control APIを使う大きなメリットとして、CloudFormationのJSON Schemaが公開されていることがある。例えばS3バケットのスキーマは以下のコマンドで取得できる。
aws cloudformation describe-type --type RESOURCE \
--type-name AWS::S3::Bucket --query 'Schema' --output text
このスキーマを使えば、 typify でRustの型を自動生成できる。生成した型を使ってバリデーションすれば、リソースごとに手動でバリデーションロジックを書く必要がなくなる。
というわけで、Cloud Control APIを使うよう 実装してみた 。
S3バケットの
versioning_configuration
を変更する
apply
を実行したところ、完了までに20秒以上かかった。単純なプロパティ変更なのに遅すぎるのでは、と思って調べてみた。
直接S3 APIを叩いた場合と、Cloud Control APIを叩いた場合で比較してみた。
$ time aws s3api put-bucket-versioning \
--bucket carina-test-logs-mizzy-2026 \
--versioning-configuration Status=Suspended
所要時間: 約0.4〜0.5秒
RESULT=$(aws cloudcontrol update-resource \
--type-name "AWS::S3::Bucket" \
--identifier "carina-test-logs-mizzy-2026" \
--patch-document '[{"op":"replace","path":"/VersioningConfiguration","value":{"Status":"Enabled"}}]')
REQUEST_TOKEN=$(echo "$RESULT" | jq -r '.ProgressEvent.RequestToken')
START=$(date +%s)
while true; do
STATUS=$(aws cloudcontrol get-resource-request-status \
--request-token "$REQUEST_TOKEN" | jq -r '.ProgressEvent.OperationStatus')
echo "[$(( $(date +%s) - START ))s] $STATUS"
[ "$STATUS" = "SUCCESS" ] || [ "$STATUS" = "FAILED" ] && break
sleep 1
done
完了までの所要時間: 約23秒
Cloud Control APIはCloudFormationと同じリソースハンドラーを使っており、内部的にリソースの整合性チェックや安定化待ち(resource stabilization)を行っているようだ。
AWSの公式ブログ How we sped up AWS CloudFormation deployments with optimistic stabilization でも、CloudFormationのデプロイが遅い理由として「resource stabilization」に時間がかかることが説明されている。
| 方式 | 所要時間 |
|---|---|
| 直接S3 API | 約0.5秒 |
| Cloud Control API | 約23秒 |
Cloud Control APIは統一的なインターフェースで様々なリソースを扱えるメリットがあるが、個別のAPIを直接叩くより大幅に遅い。速度が重要な場合は、リソースタイプごとに直接SDKを使う方がよさそう。
Carinaでの採用はやめた。