[AWS]OpenSearchでメモリ不足が発生するとめんどくさい
はじめに
ある日、CFnで作ったリソースのterraform移行とインフラのあれこれを主務としている案件でdev環境の検索機能が動かなくなりました。
環境
- AWS OpenSearch Service
- エンジンバージョン: OpenSearch 2.19
- インスタンスタイプ: t3.small.search × 1台
- EBS: gp3, 10GB
- 構成: 単一AZ、VPC内
- IaC: Terraform
症状
- 検索機能が応答しない
- AWSコンソールでクラスターの状態が「-」と表示される
- 「The node information is not available now, please try again later.」というAPIエラー
調査
AWS CLIでの確認
aws opensearch describe-domain-health --domain-name <domain-name> --region ap-northeast-1
{
"DomainState": "Active",
"ClusterHealth": "NotAvailable",
"DataNodeCount": "1",
"AvailableDataNodeCount": "NotAvailable",
"ZoneStatus": "NotAvailable"
}
ドメイン自体は「Active」なのに、クラスターヘルスが「NotAvailable」。ノードが応答していない状態でした。
CloudWatch Logsの確認
アプリケーションログを確認したところ、大量のGC警告が出力されていました。
aws logs filter-log-events \
--log-group-name "/aws/aes/domains/<domain-name>/application-logs" \
--start-time $(date -d '24 hours ago' +%s)000 \
--region ap-northeast-1
[WARN] [gc][9061842] overhead, spent [17.3s] collecting in the last [17.4s]
[WARN] [gc][9064109] overhead, spent [54.2s] collecting in the last [55.1s]
[WARN] [gc][9067070] overhead, spent [1m] collecting in the last [1m]
GCに17秒〜1分以上かかっているのでGC地獄の可能性が高まる
原因
正常なGC
アプリ動作 → メモリにゴミが溜まる → GCが掃除(数ミリ秒)→ アプリ再開
GC地獄
アプリ動作 → すぐメモリ満杯 → GC発動(数十秒〜数分)→ 少し空く →
すぐ満杯 → またGC(数十秒)→ 少し空く → すぐ満杯...
メモリが足りないと、GCが頻繁に長時間発生し、本来の処理ができなくなります。
ログから読み取れる証拠
| 証拠 | 内容 |
|---|---|
| GC時間 | 17秒〜1分以上(正常は数ms) |
| オーバーヘッド | 99%の時間をGCに消費 |
| 頻度 | 数分おきに発生 |
| 効果 | GCしてもメモリが解放されない |
なぜt3.smallで起きたか
┌─────────────────────────────────────┐
│ t3.small インスタンス (メモリ2GB) │
├─────────────────────────────────────┤
│ OS・システム用 │ 約1GB │
├─────────────────────────────────────┤
│ JVMヒープ(検索用) │ 約1GB │
│ ├ Old領域: 350MB常に使用中 │
│ └ 検索処理用: 残り650MB ← 足りない │
└─────────────────────────────────────┘
対応
t3.small → t3.medium に変更すれば、JVMヒープが1GB → 2GBに増え、問題が解決するはずでした。
Terraformでインスタンスタイプを変更し、terraform apply を実行しました。
resource "aws_opensearch_domain" "example" {
# ...
cluster_config {
instance_type = "t3.medium.search" # t3.small.search から変更
instance_count = 1
}
# ...
}
二次災害
変更処理が開始されましたが、「Creating a new environment」ステージで1時間以上スタックしました。
aws opensearch describe-domain-change-progress --domain-name <domain-name> --region ap-northeast-1
{
"ChangeProgressStages": [
{ "Name": "Validation", "Status": "COMPLETED" },
{ "Name": "Creating a new environment", "Status": "IN_PROGRESS" },
{ "Name": "Provisioning new nodes", "Status": "PENDING" },
{ "Name": "Copying shards to new nodes", "Status": "PENDING" },
{ "Name": "Deleting older resources", "Status": "PENDING" }
]
}
「Creating a new environment」で停止したまま、1時間経っても進捗がありませんでした。
キャンセルもできない
aws opensearch cancel-domain-config-change --domain-name <domain-name> --region ap-northeast-1
An error occurred (ValidationException) when calling the CancelDomainConfigChange operation:
CancelDomainConfigChange only allowed when domain's config change status is in ValidationFailed.
キャンセルは「ValidationFailed」の場合のみ可能で、「PROCESSING」中はキャンセルできません。
実はよくある事象
調査したところ、AWS公式のナレッジセンターに同様の事象が報告されていました。
Amazon OpenSearch Service ドメインが「処理中」状態でスタックしています。この問題を解決するにはどうすればよいですか?
主な原因として以下が挙げられています。
- クラスターのヘルスステータスが赤色
- クラスターの負荷が高すぎる
- シャードの移行がスタックしている
- 内部エラー
今回のケースは、GC地獄によりクラスターが不健全な状態で設定変更を実行したことが原因と考えられます。
最終的な解決:削除と再作成
待っていても進まないため、ドメインを削除して再作成する判断をしました。
判断理由
- dev環境である
- DBがマスターデータで、OpenSearchは検索用インデックス(再構築可能)
- AWSサポートを待つより早い
手順
Terraformで管理していたため、以下の手順で対応しました。
- Terraformコードで該当リソースをコメントアウト
-
terraform applyでドメインを削除(5-10分) - コメントアウトを解除し、インスタンスタイプをt3.mediumに変更
-
terraform applyで再作成(15-20分) - アプリ側で再インデックスを実行
結果
変更前後の比較
| メトリクス | t3.small | t3.medium |
|---|---|---|
| JVMメモリプレッシャー | 40-80% | 20-60% |
| GC警告(1時間あたり) | 数十〜数百件 | 3件 |
| クラスター状態 | NotAvailable | Green |
JVMメモリプレッシャーが安定し、GC地獄から脱出できました。
教訓
予めメモリに余裕を持たせよう(OpenSearchは特に)
Discussion