🔥

[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公式のナレッジセンターに同様の事象が報告されていました。
https://repost.aws/ja/knowledge-center/opensearch-domain-stuck-processing

Amazon OpenSearch Service ドメインが「処理中」状態でスタックしています。この問題を解決するにはどうすればよいですか?

主な原因として以下が挙げられています。

  • クラスターのヘルスステータスが赤色
  • クラスターの負荷が高すぎる
  • シャードの移行がスタックしている
  • 内部エラー

今回のケースは、GC地獄によりクラスターが不健全な状態で設定変更を実行したことが原因と考えられます。

最終的な解決:削除と再作成

待っていても進まないため、ドメインを削除して再作成する判断をしました。

判断理由

  • dev環境である
  • DBがマスターデータで、OpenSearchは検索用インデックス(再構築可能)
  • AWSサポートを待つより早い

手順

Terraformで管理していたため、以下の手順で対応しました。

  1. Terraformコードで該当リソースをコメントアウト
  2. terraform apply でドメインを削除(5-10分)
  3. コメントアウトを解除し、インスタンスタイプをt3.mediumに変更
  4. terraform apply で再作成(15-20分)
  5. アプリ側で再インデックスを実行

結果

変更前後の比較

メトリクス t3.small t3.medium
JVMメモリプレッシャー 40-80% 20-60%
GC警告(1時間あたり) 数十〜数百件 3件
クラスター状態 NotAvailable Green

JVMメモリプレッシャーが安定し、GC地獄から脱出できました。

教訓

予めメモリに余裕を持たせよう(OpenSearchは特に)

GitHubで編集を提案

Discussion