Linkers Tech Blog

リンカーズ株式会社の開発者ブログです。

【Elasticsearch】Validation Failed: 1: this action would add [10] total shards, but this cluster currently has [1992]/[2000] maximum shards open

はじめに

情報システム部の横山です。今回はElasticsearchを利用した機能を本番リリースする直前に発生した、表題のエラーについてご紹介します。このエラーが出るのは一部のアプリケーションだけだとは思いますが、同じエラーが出た人の一助となれば幸いです。

背景

Elasticsearchを利用した全文検索機能のMR(マージリクエスト)をdevelopブランチにマージし、社内で使っているStaging環境でも無事動作確認ができ、別のテスト環境にもデプロイしました。それではお客様にも確認して頂き、それがOKだったら本番にもリリースしよう……という時に、テスト環境からSlackにエラーが通知されました。

エラーの概要

表題にもしたこのエラーをGoogle翻訳すると、「このアクションは[10]の合計シャードを追加しますが、このクラスターは現在[1992]/[2000]の最大シャードを開いています」。最初に見た時は何のことやら?と思いましたが、つまり、「シャード数の上限が2000に設定されている状態で、現在は1992のシャードがあり、そこに10個のシャードを新しく追加しようとしているけどこれを追加したら2002になって上限超えるからエラーだよ」と言っているようです。ではシャードとは何でしょうか?

シャード

シャードについては、Elastic社の公式ページに説明が書かれています。

Elasticsearchのデータは、複数のインデックスに整理されます。各インデックスは1つ以上のシャードで構成されています。各シャードはLuceneインデックスのインスタンスです。(How many shards should I have in my Elasticsearch cluster? | Elastic Blogより引用)

どうも各インデックスは1つ以上のシャードで構成されているようです。

デフォルトでは、Elasticsearchの各インデックスは5つのプライマリシャードと1つのレプリカを割り当てられます。これは、クラスタに少なくとも2つのノードがある場合、インデックスは、インデックスにつき合計10個のシャードのうち、5つのプライマリシャードと5つのレプリカシャード(完全なレプリカ1つ)を持つということです。(基本概念 | Elasticsearchリファレンス [5.4] | Elasticより引用)

そしてそのシャード数のデフォルト値は5で、それぞれにレプリカがあるので、つまりシャード数のチューニングをせずにインデックスを作ると、以下の画像のようになることが分かります。

Elasticsearchが内部で利用しているLuceneという全文検索ライブラリが存在するのですが、そのLuceneのインデックスを作成するために、シャードは存在します。このシャードを単位としてElasticsearchのインデックスからLuceneのインデックスに変換するので、小さいシャードが増えすぎてしまったり、逆にシャードの中身が大きくなりすぎたりするとElasticsearchのパフォーマンスに影響が出てしまうようでした。

では、シャードの中身はどれくらいの大きさであれば良いのでしょうか? 公式には以下のように書かれていました。

シャードサイズに関する決まった上限はありませんが、よく言われているシャードサイズの上限は50GBです。これがさまざまなユースケースで実用可能な大きさと考えられています。(How many shards should I have in my Elasticsearch cluster? | Elastic Blogより引用)

エラーが出た時の構成はどうなっていたか

エラーが起きた時、シャード数はデフォルト設定のまま、つまり1インデックスにつき10個のシャードが作られる状態でした。そして4つのModel(テーブル)に対して個別にインデックスを作成したため、これでシャード数は10 × 4 = 40。更に、このアプリケーションはテナントによってデータベースを分けるように設計されていて、この当時、エラーが起きたテスト環境のテナント数は60程度あり……40 × 60 = 2400。よってElasticsearchのシャード数の上限は2000を超え、エラーが起きてしまいました。

kibanaのコンソールから GET /_cat/shards?v して確認を行うと、確かに1インデックスあたり10のシャードができていました。

どう対応したか

テナント別にデータベースが分けられているので、それぞれのテナントのレコード数はそう多くありませんでした。各インデックスのサイズを調査したところ、大きいものでも200MB程度だったため、プライマリシャードとレプリカシャードを1つずつの構成に変更しました。

searchkickというgemを使っていたため、設定は簡単でした。 以下のように設定できます。

class Product < ApplicationRecord
  searchkick settings: { number_of_shards: 1 }
end

そして設定を変更した後、全てのインデックスを作り直し、無事このエラーは解消しました。

おわりに

AWSブログでもシングルシャードを恐れるなと記載されています。

シングルシャードを恐れるな!

もし、あなたのインデックスのサイズが30GB以下であるのであれば、一つのシャードのみを使うべきです。”more is better”というガッツフィーリングをお持ちの方もいらっしゃいますが、誘惑を断ち切りましょう!(Amazon Elasticsearch Service をはじめよう: シャード数の算出方法 | Amazon Web Services ブログより引用)

シャード数は適切にメンテナンスし、Elasticsearchを使っていきましょう。