Elasticsearchマッピング爆発を防ぐ5つの方法とシャードサイズ最適化ガイド

ログ基盤を運用していると、ある日突然Elasticsearchのマスターノードが不安定になったり、インデックスの書き込みが拒否されたりする現象に直面します。これは多くの場合、無秩序なフィールド増加による「マッピング爆発」が原因です。

この記事では、マッピング爆発の技術的背景を理解し、クラスタの安定性を確保するための具体的な設定方法とシャードサイジングの最適解を提示します。

TL;DR — マッピング爆発は index.mapping.total_fields.limit で制限し、シャードサイズは10GB〜50GBの範囲で維持することで、クラスタのメモリ消費(Heap)を最小化し検索性能を最大化できます。

1. マッピング爆発とは

💡 イメージで理解する: 図書館の蔵書目録(マッピング)を想像してください。本の内容(データ)が増えるのは問題ありませんが、もし「1ページ目の3単語目の色」といった無意味な項目(フィールド)が1冊ごとに目録に追加されたら、目録を管理する棚(メモリ)が溢れてしまいます。

Elasticsearchにおけるマッピング爆発(Mapping Explosion)とは、インデックス内のフィールド数が膨大になり、クラスタの状態(Cluster State)を管理するマスターノードのメモリを枯渇させる現象です。最新バージョン 8.12.x 以降でも、デフォルトの制限値(1000フィールド)を超えると書き込みエラーが発生します。

Dynamic Mappingが有効な状態で、JSONログのキー名が動的に生成される(例:ユーザーIDがキーに含まれる)場合に発生しやすく、放置するとクラスタ全体のレスポンス低下やOOM(Out Of Memory)を引き起こします。

2. 実務で対策が必要な状況

スキーマレスな柔軟性を活かして大量の分散ログを収集する場合、特に注意が必要です。マイクロサービスごとに異なるログ構造を持つ環境では、共通のインデックスにデータを流し込むと、あっという間に数千のフィールドが作成されます。

また、シャードサイジングが不適切な場合も深刻です。1つのインデックスに対してシャードが多すぎると、各シャードが持つメタデータがオーバーヘッドとなり、少なすぎると検索時の並列処理能力が活かせず、リカバリ速度が著しく低下します。

3. 実装ガイド:防御と最適化

マッピングの制御とシャード管理を自動化することで、運用の負担を大幅に軽減できます。

ステップ 1. Dynamic Mappingの厳格化

予期しないフィールドの追加を防ぐため、dynamic 設定を false または strict に変更します。

PUT /my-index-000001/_mapping
{
  "dynamic": "strict"
}

ステップ 2. インデックステンプレートの適用

共通のプレフィックスを持つインデックスに対して、フィールド数の制限とシャード構成を定義します。

PUT _index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "index.mapping.total_fields.limit": 2000,
      "index.number_of_shards": 2,
      "index.number_of_replicas": 1,
      "index.refresh_interval": "30s"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" }
      }
    }
  }
}

ステップ 3. シャードサイズの最適化(Rollover)

ILM(Index Lifecycle Management)を使用して、1シャードあたり30GB程度を目安にローテーションさせます。

PUT _ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_primary_shard_size": "40gb",
            "max_age": "7d"
          }
        }
      }
    }
  }
}

4. Dynamic vs Strict Mapping

開発効率と運用の安定性はトレードオフの関係にあります。

比較基準Dynamic MappingStrict Mapping
開発スピード高い(定義不要)低い(事前定義が必要)
安定性低い(爆発リスク)高い(予測可能)
メモリ消費予測不可最適化可能
適した環境プロトタイプ・開発本番環境・大規模ログ

初期開発時はDynamicでフィールドを抽出し、本番移行時に必要な項目のみを定義したStrict構成に変更するのがベストプラクティスです。

5. 注意事項

⚠️ よくあるミス: index.mapping.total_fields.limit を安易に1万以上に引き上げると、マッピング爆発は防げても、マスターノードがCluster Stateの更新に失敗し、クラスタ全体がダウンする原因になります。

フィールド数が多いと、1ドキュメントあたりのシリアライズコストが増大し、Indexing Latencyが悪化します。

エラー別の対処法

[IllegalArgumentException] Limit of total fields [1000] has been exceeded
# 原因: 動的マッピングでフィールドが増えすぎた
# 解決: 不要なフィールドを削除し、dynamic: false を設定。または Flattened 型を使用。

6. 実戦的な運用チップス

ログに未知の構造が含まれる可能性がある場合は、flattened 型の利用を検討してください。このデータ型は、ネストされたJSON全体を1つのフィールドとして扱い、マッピング爆発を防ぎながら、キーによる検索を提供します。

シャードサイズについては、読み取りメインのデータセットなら10GB以下、ログのような書き込みメインかつ有効期限があるデータなら20GB〜40GBが最も効率的です。ノードあたりのシャード数は、1GBのHeapに対し20シャード以下に抑えるのが業界標準です。

📌 まとめ

  • dynamic: strict を活用して予期せぬフィールド増加を遮断する。
  • ILMを使用してシャードサイズを10GB-50GBの間に維持する。
  • 構造が不確実なデータには flattened 型を適用する。

よくある質問

Q. 現在のインデックスのフィールド数を確認する方法は?

A. GET /index_name/_mapping の結果を jq 等でカウントします。

Q. シャードが多すぎる場合のデメリットは?

A. メモリ消費増大とマスターノードの負荷増、検索の遅延が発生します。

Q. 既存のインデックス設定を後から変更できますか?

A. 制限値の変更は可能ですが、マッピング定義自体は _reindex が必要です。

Post a Comment