Elasticsearch のシャード数削減の実例 （運用現場での事例から）

## 最初に :information_desk_person:
### このページで話すこと
Elasticsearch のシャード数削減の説明だけではなく、
実際の運用現場での事例をもとに、
どのような問題があって、どう対処したのか、
にフォーカスして説明します

### 検証環境
+ Elasticsearch 7.17
  - 以前： Elasticsearch 6.8
+ OS： Rocky Linux8


## 月次インデックスの年次集約による削減
### 背景
いろいろな需要から、
各種用途の月次インデックスを、数年分残していました。

あるとき、Elasticsearch 6.8 から 7.17 に移行したところ、
すぐにシャード数があふれてしまいました。

原因は2つ
* インデックス1つのシャードを、プライマリ5台＋レプリカ1台の6台に分散していた
* Elasticsearch6系から7系に移行したことで、シャード数の上限管理が厳しくなった

1年間で72シャード、それが複数インデックス分×数年保持なので、
7.17 のデフォルトの限界値（シャード数 1000）を超えたようです。

対処としては、
* 暫定的に、月次インデックスを年次インデックスに集約する
* かつ、年次インデックスのシャード数を減らす
* 恒久的には、最初から年次インデックスを使用する


### 暫定対処
1. health で現在のシャード数を確認 （エビデンスとして残すため）
    ```
    curl localhost:9200/_cat/health
    ```
1. 現在の月次インデックスの状態を確認 （エビデンスとして残すため）
    ```
    curl -s localhost:9200/_cat/indices/daily_report_2024*?pretty
    ```
1. 集約用（年次）のインデックスを作成する
    ```
    curl -XPUT -H 'Content-Type: application/json' localhost:9200/daily_report_2024?pretty -d '
    {
      "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 1
      }
    }'
    ```
    * データを参照する場合でも、頻度が低ければ number_of_shards は減らしていいはず
    * 参照しないのであれば、ILM でコールドフェーズやフローズンフェーズに移動するのもあり
1. 月次のインデックスを年次のインデックスにコピー（集約）する
    ```
    curl -XPOST -H 'Content-Type: application/json' localhost:9200/_reindex?pretty -d '
    {
      "source": {
        "index": ["daily_report_202401", ... "daily_report_202412"]
      },
      "dest": {
        "index": "daily_report_2024"
      }
    }'
    ```
1. 年次インデックス作成確認
    ```
    curl -s localhost:9200/_cat/indices/daily_report_2024?pretty
    ```
    * 出力結果
        ```
        green open daily_report_2024  <uuid> 1 1 1234 0  4.4mb  2.2mb
        ```
        * 1234 の部分がプライマリのシャード数。ここが増えるまで待つ
1. シャード数確認
    ```
    curl -s localhost:9200/_cat/shards/daily_report_2024?pretty
    ```
    * 出力結果
        ```
        daily_report_2024 0 p STARTED 1234 2.2mb 192.0.2.1 els-1
        daily_report_2024 0 r STARTED 1234 2.2mb 192.0.2.2 els-2
        ```
        * 1234 の部分がプライマリのシャード数。ここがレプリカと同じ数値ならOK
1. 検索確認
    * 意図したレコードが出てくればOK
    ```
    curl -s localhost:9200/daily_report_2024/_search?pretty
    ```
1. 月次インデックスの削除
    ```
    curl -XDELETE localhost:9200/daily_report_20240*?pretty
    curl -XDELETE localhost:9200/daily_report_20241*?pretty
    ```
    * 名前を工夫すればもっと簡単に消せると思います
1. 月次インデックス削除確認
    * 年次インデックスだけ出てくればOK
    ```
    curl -s localhost:9200/_cat/indices/daily_report_2024*?pretty
    ```
1. health でシャード数低下の確認
    ```
    curl localhost:9200/_cat/health
    ```
    * 出力結果
        ```
        174000xxxx 00:01:36 els-cluster green 3 3 1192 596 0 0 0 0 - 100.0%
        ```
        * 1192 の部分が、全ノードの合計シャード数

### 恒久対処
* 少量のデータしか入れないのであれば、月次単位ではなく年次単位のインデックスを作る
* 過去分は閲覧頻度も低いはずなので、shrink でプライマリの数を減らす（例： 5 => 1）
* 可能であれば、2年保存など区切りをつけておく（要関係者と相談）

:::note info
シャード数のあふれ確認
1ノードのシャード上限数はデフォルトで1,000。

例えばノードが3つなら、`/_cat/health` の結果が 3,000シャード未満であればOK。

増え方にもよりますが、体感70％未満なら安全圏だと思います。
:::


## ILM による保存期間の変更による削減
### 背景
前述のシャード数あふれの対応後、
1か月でまたシャード数があふれてきました。

今回の原因は、定期的に削除している日次インデックスの増加によるもの。

定期的な削除をしていても、
インデックスのと保持日数が多ければ、シャード数は超過します。

対策としてはシンプルに、
保持日数を減らす、というのが、
需要の面、対応難度の面からみても対処しやすいでしょう。

### 暫定対処
1. health で現在のシャード数を確認 （エビデンスとして残すため）
    ```
    curl localhost:9200/_cat/health
    ```
1. 現在のポリシーの確認
    ```
    curl localhost:9200/_ilm/policy/report_policy?pretty
    ```
    * 以下、確認ポイント
        ```
        "phases" : {
          "delete" : {
            "min_age" : "60d",   => 削除するまでの期間
        ```
        ```
        "in_use_by" : {
          "indices" : [
            daily_report_202401   => ILM対象のインデックス
            daily_report_202402
        ```
1. ポリシー更新
    ```
    curl -XPUT -H 'Content-Type: application/json' localhost:9200/_ilm/policy/report_policy?pretty -d '
    {
      "policy" : {
        "phases" : {
          "delete" : {
            "min_age" : "30d",
            "actions" : {
              "delete" : {
                "delete_searchable_snapshot" : true
              }
            }
          }
        }
      }
    }'
    ```
1. 更新後のポリシーの確認
    ```
    curl localhost:9200/_ilm/policy/report_policy?pretty
    ```
    * min_age が変更後の値に変わっていること
1. 一番古いインデックスの ILM の状態を確認する
    ```
    curl localhost:9200/_ilm/policy/daily_report_202401?pretty
    ```
    * 以下、確認ポイント
        ```
        "age" : "40.98d",
        "phase" : "delete",
        ```
        * 変更後の期間を過ぎたインデックスの phase が delete になっていればOK

### 恒久対処
保持日数削減によるシャード数低下は一時的なものです。
今後、インデックスが増えればまた再発します。

なので、インデックスを使用する関係者と相談し、
最低限必要な保持日数を減らしたり、
不要なインデックスを削除するなどの検討が必要です。


:::note info
phase = delete になったインデックスはすぐには消えません。
しばらくすると消えます。
:::