2026年5月31日

2026年5月31日

Elasticsearchのシャード設計と最適化方法(数とサイズの決め方・ILMのロールオーバー・増やし過ぎの直し方)

Elasticsearch のシャード設計は、「1 シャードあたりのサイズを数十 GB 程度に収め、数を必要以上に増やさない」が基本です。プライマリシャードの数はインデックス作成後に変えられないため、データ量の見込みから逆算して決め、増え続けるデータはロールオーバーで新しいインデックスに分けていきます。この記事では、数とサイズの決め方、現状の確認方法、シャードが多すぎるときの直し方までを、小規模な構成を想定して説明します。

コード例は Kibana の Dev Tools(コンソール)の書式です。設定を変える前にスナップショットを取り、可能ならステージング環境で試してください。

シャードとレプリカの基本

インデックスのデータは、シャードと呼ばれる単位に分割して保存されます。シャードには 2 種類あります。

  • プライマリシャード: データの本体。数(number_of_shards)は作成時に決まり、後から直接は変えられない
  • レプリカシャード: プライマリの複製。障害への備えと、検索の分散に使われる。数(number_of_replicas)はいつでも変えられる

レプリカは、プライマリとは別のノードにしか置かれません。1 台構成でレプリカを 1 にするとクラスターが黄色(yellow)になるのはこのためです。データが失われているわけではありませんが、1 台では複製による保護がないことを意味します。

7.0 以降、インデックスの既定のプライマリシャード数は 1 です。古い記事にある「既定は 5」という説明は、現在の版には当てはまりません。

シャードが多すぎても少なすぎても困る理由

シャードは 1 つ 1 つが独立した検索エンジン(Lucene のインデックス)で、数に比例してメモリやファイルハンドル、クラスターの管理情報が増えます。

多すぎる場合(オーバーシャーディング)

  • 小さなシャードが大量にあると、データ量のわりにヒープメモリを消費する
  • 検索のたびに多くのシャードへ問い合わせるため、件数の少ない検索でもかえって遅くなる
  • ノードあたりのシャード数には上限(cluster.max_shards_per_node、既定 1000)があり、超えると新しいインデックスを作れなくなる

大きすぎる場合

  • ノード障害の後の復旧や、ノード間の再配置に時間がかかる
  • 1 シャードに入るドキュメント数には、Lucene の仕様による約 21 億件の上限がある

日付ごとにインデックスを作るログ運用で、データの少ない日にも毎日 5 シャードずつ作る、というのが典型的な失敗例です。1 年で数千シャードになり、データは数 GB しかないのにメモリが足りなくなります。

数とサイズの決め方

Elastic の公式ドキュメントでは、1 シャードのサイズを 10GB〜50GB 程度、ドキュメント数を 2 億件程度までに収めることが目安として示されています(2026年10月現在)。かつて広く使われた「ヒープ 1GB あたり 20 シャードまで」という目安は、新しい版では別の考え方に置き換えられているため、使っている版のドキュメントで確認してください。

決め方の手順は次のとおりです。

  1. インデックスの最終的なサイズを見積もる(レプリカを除いたプライマリ分)
  2. 目安のシャードサイズで割り、プライマリの数を決める
  3. 検索の並列度やノード数を考えて調整する

例として次のように考えます。

  • WordPress のサイト内検索(投稿数万件、数 GB): プライマリ 1 で十分です。分割しても速くはならず、管理対象が増えるだけです。
  • 商品や文書の検索(最終的に 120GB 程度の見込み): 40GB 前後になるよう、プライマリ 3。ノードが 3 台あれば各ノードに 1 つずつ配置されます。
  • アクセスログ(1 日 2GB、30 日保存): 日ごとにインデックスを作るのではなく、後述のロールオーバーで「一定サイズに達したら次へ」とし、プライマリ 1 で運用します。

レプリカは、ノードが 2 台以上あるなら 1 が基本です。レプリカを増やすと検索の処理を分散できますが、書き込みとディスク使用量もその分増えます。

現状を確認する

まず、シャードの数と大きさを一覧で確認します。

GET _cat/indices?v&s=store.size:desc
GET _cat/shards?v&s=store:desc
GET _cat/allocation?v
GET _cluster/health?pretty
  • _cat/indices で、インデックスごとのプライマリ数(pri)・レプリカ数(rep)・サイズを見ます。サイズの小さいインデックスが大量にあれば、オーバーシャーディングを疑います。
  • _cat/shards で、シャードごとのサイズと配置先のノード、状態(STARTED・UNASSIGNED など)を確認します。
  • _cat/allocation で、ノードごとのシャード数とディスク使用量の偏りを見ます。

UNASSIGNED(未割り当て)のシャードがある場合は、理由を問い合わせます。

GET _cluster/allocation/explain

レプリカの置き場所となるノードがない、ディスク使用率がしきい値を超えている、といった理由が文章で返ってきます。

増え続けるデータは ILM のロールオーバーで分ける

ログのように時間とともに増えるデータは、インデックスライフサイクル管理(ILM)のロールオーバーを使うと、シャードのサイズを一定に保てます。書き込み先のインデックスが条件に達すると、新しいインデックスが自動で作られ、書き込み先が切り替わります。

PUT _ilm/policy/nginx-logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": { "max_primary_shard_size": "50gb", "max_age": "7d" }
        }
      },
      "warm": {
        "min_age": "3d",
        "actions": {
          "forcemerge": { "max_num_segments": 1 }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": { "delete": {} }
      }
    }
  }
}

この例では、プライマリシャードが 50GB に達するか 7 日経つと次のインデックスに切り替わり、書き込みが終わったものは 3 日後にセグメントを統合し、30 日後に削除します。min_age はロールオーバーした時点から数えられます。データの少ない環境では max_age が先に効くため、小さなシャードが毎週できることになりますが、毎日作るよりはずっと少なく済みます。

ポリシーは、インデックステンプレートの settings に "index.lifecycle.name": "nginx-logs-policy" を書いて適用します。Logstash や Elastic Agent などの取り込みツールを使う場合は、データストリームと組み込みのポリシーが使われることもあるため、そちらの設定と重複しないか確認します。

シャードの数を後から変えたいとき

プライマリの数を変える方法は 3 つあります。

  • 再インデックス: 新しいシャード数でインデックスを作り、_reindex でコピーしてからエイリアスを付け替える。マッピングの見直しも同時にでき、もっとも柔軟
  • **分割(_split)**: シャード数を整数倍に増やす。元のインデックスを書き込み禁止にする必要がある
  • **縮小(_shrink)**: シャード数を約数に減らす。書き込み禁止に加え、元のシャードのコピーを 1 台のノードに集める必要がある

小規模な構成なら、手順がわかりやすく失敗しても元のインデックスが残る再インデックスが扱いやすい方法です。_split と _shrink は条件が細かく、版によって制約が異なるため、使う場合は公式ドキュメントの手順に沿って進めます。

日付ごとの小さなインデックスが大量にある場合は、月単位にまとめて再インデックスし、元のインデックスを削除すると数を大きく減らせます。削除の前に、件数が一致しているかを _cat/indices で確かめます。

書き込み・検索を最適化する設定

シャードの数以外にも、負荷に効く設定があります。

初回の大量投入: 投入中だけレプリカを 0 にし、更新間隔(refresh_interval)を延ばすと速くなります。終わったら元に戻します。

PUT wp-posts-v2/_settings
{ "index": { "number_of_replicas": 0, "refresh_interval": "30s" } }

PUT wp-posts-v2/_settings
{ "index": { "number_of_replicas": 1, "refresh_interval": null } }

null を指定すると既定値(1 秒)に戻ります。レプリカ 0 の間はデータの複製がないため、元データから入れ直せる状況でだけ使います。

書き込みが終わったインデックス: _forcemerge でセグメントを統合すると、検索が軽くなりディスクも減ります。書き込み中のインデックスに実行すると逆効果になるため、ロールオーバー済みのものに限定します。

ノードの配置: 複数のデータセンターやアベイラビリティゾーンにノードを置く場合は、シャード割り当ての awareness 設定で、プライマリとレプリカが同じ場所に偏らないようにできます。

まとめ

  • プライマリ数は作成後に変えられない。レプリカ数はいつでも変えられる
  • 1 シャード 10GB〜50GB 程度を目安に、データ量から逆算して数を決める
  • 小規模な WordPress 検索ならプライマリ 1 で十分。分けすぎると遅く、重くなる
  • _cat/indices・_cat/shards・_cluster/allocation/explain で現状と原因を確認する
  • 増え続けるデータは ILM のロールオーバーでサイズを揃え、古いものは自動で削除する
  • 数を変えるときは、再インデックスとエイリアスの付け替えがもっとも扱いやすい

お気軽にご相談ください

お見積りへ お問い合わせへ
▲