Elastic Cloud と Amazon Elasticsearch Service を選ぶ上で考えたこと

この記事は [ZOZOテクノロジーズ #4 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/zozo_tech4) の24日目の記事になります。
ZOZOテクノロジーズでバックエンドのエンジニアをしている @calorie です。よろしくお願いします。

昨日の記事は @hiro0218 による「[竈門炭治郎をCSSだけで再現する](https://b.0218.jp/202012230000.html)」でした。こちらもぜひご覧ください。

# この記事について

Elasticsearch のメジャーなマネージドサービスとして [Elastic Cloud](https://www.elastic.co/jp/cloud/) と [Amazon Elasticsearch Service(以下 Amazon ES)](https://aws.amazon.com/jp/elasticsearch-service/) が挙げられますが、
これらのサービスに関して Elastic 社や AWS 社にヒアリングしつつ見積もりと技術選定を行った際に考えたことについてまとめます。

Elasticsearch の用途としてウェブサイトの検索等で用いる「存続期間の長いインデックス」と、ログ分析等で用いる「ローリングインデックス」がありますが主に前者を想定して書きます。

# まとめ

各サービスの特徴を理解しサービスの要件を詰めてサイジングしました。

# サイジング

サイジングとは、構成要素について必要とされる規模や性能を見積もることを指します。
サービスを選ぶ上で構成の規模感や料金を知る必要があり、それらを測るためにまずは導入するサービスの要件を整理しサイジングを行います。

Elasticsearch のサイジングでは、必要とするデータサイズからノード数やシャード数を見積もるのと、サービス要件からインスタンスタイプやレプリカ数を決めます。

## ノード数、シャード数

まずは必要とするデータサイズとリクエスト数を把握します。以下に把握しておく内容を列挙します。

| 内容 | 説明 |
|---|---|
| ドキュメント数 | リリース時に必要とする Elasticsearch 上のドキュメントの数です |
| ドキュメントサイズ | Elasticsearch 上の1ドキュメント容量です。 <br> 実際にデータを入れて _cat/indices などで確認するのが良いです。 <br> または、実際のデータに転置インデックスなどのバッファで2倍程度かけた容量を見積もると良いそうです。 |
| 1日に増えるドキュメント数 | ユーザやメンテナが1日に Elasticsearch に POST するドキュメント数です。 |
| 1日に増えるドキュメントサイズ | ドキュメントサイズ * 1日に増えるドキュメント数 |
| 運用日数 | 将来的にデータサイズがどれくらいになるか把握するため、サービスがどれくらい継続するかを把握しておきます。 |
| レプリカ数 | Elasticsearch のレプリカシャードの数です。 <br> リード性能がどれくらい必要かによって変わり、 パフォーマンステスト時に調整します。デフォルトは1です。 |
| ソースデータサイズ | リリース時に必要なデータサイズです。 <br> 計算式 : ドキュメント数 * ドキュメントサイズ |
| 将来的なデータサイズ | ソースデータサイズに拡張の余地を足したものです。 <br> 計算式 : ソースデータサイズ + (1日に増えるドキュメント数 * 運用日数) |

これらの情報から Elastic Cloud、 Amazon ES それぞれでノード数とシャード数を決めます。
決め方はそれぞれのサービスで異なるため下記に記載します。

### Elastic Cloud

まず、 [Elastic 社の資料](https://www.elastic.co/pdf/elasticsearch-sizing-and-capacity-planning.pdf)のp40の計算式に沿って、 `Total Data (GB)` と `Total Storage (GB)` を算出します。
例としてソースデータサイズ100GB、1日に増えるドキュメントサイズ1GB、運用日数1095日(3年)、レプリカ数1の場合は以下のようになります。

- Total Data (GB) : (100GB + 1GB * 1095日) * (1レプリカ数 + 1) = 2390GB
- Total Storage (GB) : 2390GB * (1 + 0.15 + 0.05) = 2868GB

ノード数は [pricing](https://cloud.elastic.co/pricing) の「Size your deployment」で将来的なデータサイズにあったものを選べば自ずと決まります。

シャード数は下記の資料にそって1シャードあたり20GB程度かつ、JVM のヒープ(RAMの50% or 最大30GB)あたりのシャード数が20以下に設定します。
https://www.elastic.co/jp/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

RAM 8GB, Storage 240GB, 3AZ の場合、 `240 * 3 / 20 = 36シャード`
1ノードあたり12シャードとなり、ヒープ4GBの1GBあたりのシャード数は3なので、シャード数20以下を満たしています。

### Amazon ES

サイジングのドキュメントに沿って計算を行えば特に詰まることなくノード数、シャード数は決まるため割愛します。
https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/sizing-domains.html

## インスタンスタイプ

インスタンスタイプは Elasticsearch で重いスコア計算などをするかによって変わり、重い計算をする場合は CPU のリソースが多いものを選ぶと良いとのことでした。
Elastic Cloud なら highcpu 、 Amazon ES なら c5 などがこれにあたります。

それ以外の場合は規模にもよりますが Elastic Cloud の場合は highmem 、 Amazon ES なら m5 を選んでおくと良いようです。

## レプリカ数

サービス要件としてより高いリード性能が求められる場合、レプリカ数を増やすことで解決できます。ただし、レプリカ数を増やすほど必要なストレージサイズは増えコストも増えます。

レプリカ数を決定するには実際にデータを入れてパフォーマンステストをする必要がありますが、予めリード性能が必要なことがわかっているならレプリカ数を多めに設定した場合の見積もりを出すと良いでしょう。

# ネットワーク

Elasticsearch がどこからどのように使われるかによってネットワーク構築の難易度が変わるためこれを検討しました。

パフォーマンスに関して、Elasticsearch に高頻度でリクエストをするアプリケーションと同じ Cloud provider に Elasticsearch を構築すると、Cloud provider のネットワーク最適化の恩恵を受けられるはずです。
例えば、アプリケーションが AWS 上にある場合、Elastic Cloud の Cloud provider を AWS で選ぶか、Amazon ES を選ぶと基本的にレイテンシは小さくなるはずです。

セキュリティ要件によってもネットワーク構成は変わってきそうです。
例えば、アプリケーションと Elasticsearch 間のネットワークを閉域で構築する必要があるなら、Elastic Cloud の場合 [AWS PrivateLink を用いた構成](https://www.elastic.co/jp/blog/improve-network-security-elastic-cloud-traffic-filters) になるでしょうし、 Amazon ES であれば、VPC 内に構築して同じ VPC 内のリソースとやり取りするか、VPCエンドポイントなどを使用するのが容易だと思います。
https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-vpc.html

閉域で構築する必要がない場合でも、 VPC 内に Amazon ES を立てるなら VPC 外からアクセスするには、リバースプロキシを立てるなど一工夫が必要なことを念頭においておく必要がありそうです。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/kibana-outside-vpc-nginx-elasticsearch/

# 特徴

それぞれのサービスには特徴があり一長一短なので自身のプロダクトのサービス要件と合致するか検討しました。

## Elastic Cloud

Elastic 社が Elastic Cloud と Amazon ES の比較を出しています。
https://www.elastic.co/jp/aws-elasticsearch-service

やはり、最新の Elastic 社のプロダクトを制限なく使え、それらのプロのサポートを得られる点がメリットです。

逆に気になる点としては、Infrastructure as Code しづらい点などが挙げられそうです。
最近 API が公開され [Terraform のサポートをするリポジトリ](https://github.com/elastic/terraform-provider-ec) も出てきましたが、執筆時(2020/12/24)はまだ active development の状態のようです。

## Amazon ES

メリットとしては、AWS のリソースとの親和性が高いことが挙げられそうです。
VPC 内に構築すれば比較的容易にセキュアな構成が作れそうです。
また、サービスの要件やディスカウントの状況によるため一概には言えませんが、私の構成では Amazon ES の方が料金が安くなることが多かったです。

気になる点としては、Elasticsearch の最新のバージョンが使えないことや、以下のような機能の制限があるという点です。

- [使えない API のエンドポイントがある](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/aes-supported-es-operations.html)
    - /index-name/_close など
- [プラグインを追加できない](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/aes-supported-plugins.html)
    - 日本語の Analyzer は kuromoji を使うことになります

# 最後に

色んな観点で考えましたが最後には Elastic 社や AWS 社の方々のレビューを頂いたことがサービスを決めるにあたって大変有益でした。
また、弊社は AWS のサポートを受けていたり、Elastic Cloud の導入実績があったりとやりやすい環境でした。