クラウドインテグレーション部の渡邊です。
今回はAWS OpenSearchのShrink APIについて説明します。
AWS OpenSearchのシャード数の偏りにより、パフォーマンスに影響が発生する恐れがあります。
本記事でシャード数とはプライマリシャード数を指します。
偏りがある場合、シャード数とノード数のバランスが悪いことが考えられます。 ベストプラクティスにしたがってシャード数がノード数の倍数になるように設定してください。 シャードの変更には_reindex api や _shrink api を用いることができます。
引用元:Amazon OpenSearch Service のパフォーマンストラブル解決のためのファーストステップ
以上の引用から、既存インデックスのシャード数をノード数の倍数へ変更するために、_shrink apiを使用したのですが、面倒でした。
ドキュメントにも簡単ではない旨の記載がありました。
既存のインデックスに対してプライマリシャードの数を簡単に変更することはできません。
引用元:シャード数の選択
なお、新規インデックスの場合は事前にインデックステンプレート(Index templates)を作成しておくことで、作成時にテンプレートの設定が適用されるため、そちらを利用することをオススメします。
以前執筆した、OpenSearchのスローログ設定時の注意点でもインデックステンプレートを利用しました。
_reindex apiによる検証は記事「OpenSearchのシャード再配置のために_reindex apiを使ったら意外と面倒だった」を参考にしてください。
_shrink apiについて以下の制約がありました(一部抜粋)。
各詳細を順番に説明します。
"index.blocks.write": true
を指定する必要がある$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_shrink/index-test-shrink" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 1
}
}'
{"error":{"root_cause":[{"type":"illegal_state_exception","reason":"index index-test must block write operations to resize index. use \"index.blocks.write=true\""}],"type":"illegal_state_exception","reason":"index index-test must block write operations to resize index. use \"index.blocks.write=true\""},"status":500}
Before you can shrink an index: The index must be read-only.
引用元:Shrink index API
$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_shrink/index-test-shrink" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 10
}
}'
{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"the number of target shards [10] must be less that the number of source shards [5]"}],"type":"illegal_argument_exception","reason":"the number of target shards [10] must be less that the number of source shards [5]"},"status":400}
$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_shrink/index-test-shrink" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 2
}
}'
{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"the number of source shards [5] must be a multiple of [2]"}],"type":"illegal_argument_exception","reason":"the number of source shards [5] must be a multiple of [2]"},"status":400}
The shrink index API allows you to shrink an existing index into a new index with fewer primary shards. The requested number of primary shards in the target index must be a factor of the number of shards in the source index.
引用元:Description
"index.routing.allocation.require._name": "<ノード名>"
を指定する必要がある
$ curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-2/_settings" -d '{
"settings": {
"number_of_shards": 6,
"index.blocks.write": true
}
}'
$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-2/_shrink/index-test-2-shrink" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 3
}
}'
{"error":{"root_cause":[{"type":"illegal_state_exception","reason":"index index-test-2 must have all shards allocated on the same node to shrink index"}],"type":"illegal_state_exception","reason":"index index-test-2 must have all shards allocated on the same node to shrink index"},"status":500}
A copy of every shard in the index must reside on the same node.
引用元:Prerequisites
また、既存のインデックスと同名のインデックスを新規のインデックスとして作成できません。
本制約に基づいて、以下の手順で対処しました。
① 既存インデックスへ_shrink apiを使用するための設定をする
② 既存インデックスをシャード数を少なくした新しいインデックスへコピーする(_shrink apiを使用)
③ 既存のインデックスを削除する
④ ②で作成した新しいインデックスを再度、既存インデックスと同名のインデックスへコピーする(_split apiを使用)
任意ですが、頻繁に使用する値を、環境変数として設定しました。
USERNAME=<マスターユーザ名>
PASSWORD=<マスターユーザパスワード>
ENDPOINT=<OpenSearchエンドポイント>
既存のインデックスとしてindex-test
を作成します。
$ curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_doc/1" -d '{ "name" : "TestIndex" }'
{"_index":"index-test","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":2,"failed":0},"_seq_no":0,"_primary_term":1}
インデックスの設定を確認します。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_settings?pretty"
{
"index-test" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"number_of_shards" : "5",
"provided_name" : "index-test",
"creation_date" : "1700834446681",
"number_of_replicas" : "1",
"uuid" : "bUhJNXIQSaulZ9bHGo6zNQ",
"version" : {
"created" : "136327827"
}
}
}
}
}
インデックスの中身を確認します。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_doc/1?pretty"
{
"_index" : "index-test",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "TestIndex"
}
}
設定から、プライマリシャード数が5、レプリカシャードが各プライマリシャードに対して1つ作成されるため、これらの合計が10となるはずです。
シャードの配置を確認すると、インデックスの設定通りに作成されていました。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/_cat/shards?v"
index shard prirep state docs store ip node
(略)
index-test 0 p STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 0 r STARTED 0 208b x.x.x.x fdfd42dea316faeb14b056f7c31461d9
index-test 1 r STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 1 p STARTED 0 208b x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test 2 r STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 2 p STARTED 0 208b x.x.x.x fdfd42dea316faeb14b056f7c31461d9
index-test 3 p STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 3 r STARTED 0 208b x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test 4 r STARTED 1 3.9kb x.x.x.x fdfd42dea316faeb14b056f7c31461d9
index-test 4 p STARTED 1 3.8kb x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test-tmp 0 r STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
(略)
では、初期状態を確認したところで、index-test
のシャード数を5から3へ変更する手順を実施します。
以下の記述にしたがって、ノードの倍数になるようにシャード数を設定します。
今回はデータノードを3つ作成しているため、プライマリシャード数を3とすることを目標とします。
ベストプラクティスにしたがってシャード数がノード数の倍数になるように設定してください。
引用元:Amazon OpenSearch Service のパフォーマンストラブル解決のためのファーストステップ
設定時に、読み込み専用の設定をtrueにする必要があるので対応しましょう。
ここでハマったのですが、インデックス設定で似たような以下のキーがあります。
公式の最新のドキュメントElasticsearch Guide[8.11]を参照すると、メタデータへの設定変更の可否が異なるようです。
各設定値を変更して動作検証します。
Set to true to disable data write operations against the index. Unlike read_only, this setting does not affect metadata. For instance, you can adjust the settings of an index with a write block, but you cannot adjust the settings of an index with a read_only block.
index.blocks.writeをTrueに設定してShrink APIを実施することに成功しました。
$ curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_settings" -d '{
"settings": {
"index.routing.allocation.require._name": "f2071b3f4d78a45206a83fd20122cd88",
"index.blocks.read_only": false,
"index.blocks.write": true
}
}'
設定を確認します。
{
"index-test" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"routing" : {
"allocation" : {
"require" : {
"_name" : "f2071b3f4d78a45206a83fd20122cd88"
}
}
},
"number_of_shards" : "5",
"blocks" : {
"read_only" : "false",
"write" : "true"
},
"provided_name" : "index-test",
"creation_date" : "1700834446681",
"number_of_replicas" : "1",
"uuid" : "bUhJNXIQSaulZ9bHGo6zNQ",
"version" : {
"created" : "136327827"
}
}
}
}
}
現在のプライマリノードのシャード数は5で、素数であるため、因数の1のみ値として設定できます。
$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_shrink/index-test-shrink-cp" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 1
}
}'
{"acknowledged":true,"shards_acknowledged":true,"index":"index-test-shrink"}
Shrink APIによって作成された、シャードの配置を確認します。
index shard prirep state docs store ip node
(略)
.opensearch-observability 0 p STARTED 0 208b x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test-shrink 0 p STARTED 1 3.8kb x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test-shrink 0 r UNASSIGNED
.opensearch-sap-log-types-config 0 p STARTED x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
(略)
レプリカはノードを1つに指定しているため、別ノードにアサインすることができません。
よって、レプリカシャードは別ノードにアサインされていないと思われます。
Shrink APIによって新規作成した、シャードの設定を確認します。allocation
配下の_name
の値がノード名になっております。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-shrink/_settings?pretty"
{
"index-test-shrink" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"routing" : {
"allocation" : {
"initial_recovery" : {
"_id" : "bv9IC0mNSd-QPEuVzj3CeQ"
},
"require" : {
"_name" : "f2071b3f4d78a45206a83fd20122cd88"
}
}
},
"number_of_shards" : "1",
"routing_partition_size" : "1",
"blocks" : {
"read_only" : "false",
"write" : "true"
},
"provided_name" : "index-test-shrink",
"resize" : {
"source" : {
"name" : "index-test",
"uuid" : "bUhJNXIQSaulZ9bHGo6zNQ"
}
},
"creation_date" : "1700835849543",
"number_of_replicas" : "1",
"uuid" : "xxiGBhs3R3umbZaPloLRKA",
"version" : {
"created" : "136327827",
"upgraded" : "136327827"
}
}
}
}
}
インデックスの中身を確認します。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-shrink/_doc/1?pretty"
{
"_index" : "index-test-shrink",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "TestIndex"
}
}
index.blocks.read_onlyをTrueに設定してShrink APIを実施します。
$ curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_settings" -d '{
"settings": {
"index.routing.allocation.require._name": "f2071b3f4d78a45206a83fd20122cd88",
"index.blocks.read_only": true,
"index.blocks.write": false
}
}'
インデックスの設定を確認します。allocation
配下の_name
に、ノード名が値に設定されています。read_only
がtrueに設定されております。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_settings?pretty"
{
"index-test" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"routing" : {
"allocation" : {
"require" : {
"_name" : "f2071b3f4d78a45206a83fd20122cd88"
}
}
},
"number_of_shards" : "5",
"blocks" : {
"read_only" : "true",
"write" : "false"
},
"provided_name" : "index-test",
"creation_date" : "1700834446681",
"number_of_replicas" : "1",
"uuid" : "bUhJNXIQSaulZ9bHGo6zNQ",
"version" : {
"created" : "136327827"
}
}
}
}
}
_shrink apiを実行すると失敗します。
エラーメッセージを見ると、_shrink apiによって実行されるメタデータの変更処理が、index.blocks.read_only
の設定によってブロックされているようです。
$ curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_shrink/index-test-shrink" -d '{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 1
}
}'
{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"target index [index-test-shrink] will be blocked by [index.blocks.read_only=true] which is copied from the source index [index-test], this will disable metadata writes and cause the shards to be unassigned"}],"type":"illegal_argument_exception","reason":"target index [index-test-shrink] will be blocked by [index.blocks.read_only=true] which is copied from the source index [index-test], this will disable metadata writes and cause the shards to be unassigned"},"status":400}
既存のインデックスと同名かつ希望するシャード数のものを新規作成するために、既存のインデックスを削除します。
$ curl -XDELETE -u "${USERNAME}:${PASSWORD}" "https://${ENDPOINT}/index-test"
こちらでは、②で作成したインデックスを既存のインデックスと同じ名前のものへコピーします。
今回は、5つのシャードを3つのシャードにすることを目的としています。
そのため、②で作成したインデックスのシャード数(1つ)から、既存のインデックスと同じ名前のもの(3つ)へコピーする際に、シャード数を変更する必要があります。
1つから3つにシャード数を変更するために、Split APIを使用します。
まず、インデックスへ書き込みをされないように、事前に読み込み専用の設定をTrueにしましょう。
curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-shrink/_settings" -d '{
"settings": {
"index.blocks.write": true
}
}'
Split APIによって分割されたシャードが、複数のノードに配置されるように、index.routing.allocation.require._name
を設定します。
curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-shrink/_split/index-test" -d'
{
"settings": {
"index.routing.allocation.require._name": null,
"index.number_of_replicas": 1,
"index.number_of_shards": 3
}
}'
{"acknowledged":true,"shards_acknowledged":true,"index":"index-test"}
インデックスの中身が想定のものになっております。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" "https://${ENDPOINT}/index-test/_doc/1?pretty"
{
"_index" : "index-test",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "TestIndex"
}
}
シャード数の設定を確認すると、想定通りになっております。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_settings?pretty"
{
"index-test" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"routing" : {
"allocation" : {
"initial_recovery" : {
"_id" : null
},
"require" : {
"_name" : null
}
}
},
"number_of_shards" : "3",
"routing_partition_size" : "1",
"blocks" : {
"read_only_allow_delete" : "false",
"read_only" : "false",
"write" : "true"
},
"provided_name" : "index-test",
"resize" : {
"source" : {
"name" : "index-test-shrink",
"uuid" : "xxiGBhs3R3umbZaPloLRKA"
}
},
"creation_date" : "1700869528292",
"number_of_replicas" : "1",
"uuid" : "qrYnWWXBQoSyRXgTTY3E7Q",
"version" : {
"created" : "136327827",
"upgraded" : "136327827"
}
}
}
}
}
シャードの配置を確認すると、複数のノードに配置されておりました。
(略)
index-test 0 r STARTED 0 206b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 0 p STARTED 0 206b x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test 1 r STARTED 0 206b x.x.x.x fdfd42dea316faeb14b056f7c31461d9
index-test 1 p STARTED 0 206b x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test 2 r STARTED 1 3.8kb x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
index-test 2 p STARTED 1 3.8kb x.x.x.x f2071b3f4d78a45206a83fd20122cd88
index-test-tmp 0 r STARTED 0 208b x.x.x.x 41489d33fe64d3807e1b2dbdd4f8a237
(略)
Index aliasesという設定を利用することで、インデックスにエイリアスを指定できます。
たとえば、index-test
にindex-test-3
というエイリアスを登録します。
curl -XPOST -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test/_alias/index-test-3"
index-test-3
をインデックスとして指定してリクエストを送ると、index-test
へそのリクエストが反映されます。index-test-3
へインデックス設定を表示するリクエストを送るとindex-test
の設定が表示されます。
curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/index-test-3/_settings?pretty"
{
"index-test" : {
"settings" : {
"index" : {
"replication" : {
"type" : "DOCUMENT"
},
"routing" : {
"allocation" : {
"initial_recovery" : {
"_id" : null
},
"require" : {
"_name" : null
}
}
},
"number_of_shards" : "3",
"routing_partition_size" : "1",
"blocks" : {
"read_only_allow_delete" : "false",
"read_only" : "false",
"write" : "false"
},
"provided_name" : "index-test",
"resize" : {
"source" : {
"name" : "index-test-shrink",
"uuid" : "xxiGBhs3R3umbZaPloLRKA"
}
},
"creation_date" : "1700869528292",
"number_of_replicas" : "1",
"uuid" : "qrYnWWXBQoSyRXgTTY3E7Q",
"version" : {
"created" : "136327827",
"upgraded" : "136327827"
}
}
}
}
}
これを利用して、ソースインデックスとは別名のインデックスを_shrink apiで作成しても、エイリアスとしてソースインデックス名を登録することで、④手間が省けるかと思います。
ただし、インデックスの一覧を確認しても、インデックスに設定したエイリアス名index-test-3
は出てきません。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/_cat/indices?pretty"
green open index-test-1125-notallocate rOJ3Jnm5T92cEMrMKdiCrg 3 1 1 0 8.6kb 4.3kb
green open .opensearch-observability V7SoTD9lTM-BaRnDBZpZhA 1 2 0 0 624b 208b
green open .plugins-ml-config 7JrgF6XeQNSi3UN1goU6Nw 5 1 1 0 9.4kb 4.7kb
yellow open index-test-shrink xxiGBhs3R3umbZaPloLRKA 1 1 1 0 3.8kb 3.8kb
yellow open index-test-shrink-1057 mbgkgDkWQee8iYzMhLeBHg 1 1 1 0 3.8kb 3.8kb
yellow open index-test-1125 EIt--n6-ShaMGuwAtlfN2g 3 1 1 0 4.3kb 4.3kb
green open index-test qrYnWWXBQoSyRXgTTY3E7Q 3 1 1 0 8.6kb 4.3kb
green open index-test-tmp vdgoq9YoRamTxDZNdrsxUQ 3 1 1 0 8.6kb 4.3kb
green open index-test-2 6TupyNBEQWSavxR26y27Aw 6 1 0 0 2.4kb 1.2kb
green open .opendistro_security DYyz6zEbQ5aV_OGWzNe9SQ 1 2 10 0 166.5kb 53.2kb
green open index-test-shrink-cp 75MpLnlMQhC2mScCw9uUHA 1 1 1 0 7.7kb 3.8kb
green open .kibana_1 lOTu3GxzQiW9aDjwgPQgMA 1 2 1 0 15.6kb 5.2kb
エイリアスを確認するには以下のようにします。
$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}/_cat/aliases?pretty"
index-test-3 index-test - - - -
.kibana .kibana_1 - - - -
【参考】