はじめに
ながーくかかるクエリを実行している時に、ふとキャンセルしたい時ってありませんか?
そんな時に使える手がX-Opaque-Id
を使ったキャンセルです。
長くかかるクエリのキャンセル
普通に実行した場合
例えばこんなクエリを投げて見ます。
curl -i -H 'Content-type: application/json' http://localhost:9200/.monitoring-*/_search -d'{"size": 10000}'
環境にもよるとは思いますが、レスポンスが返ってくるまで結構かかります。
レスポンスが返るまではTask Management APIを使えば、実行中のクエリを見ることはできます。
ただし、どんなクエリを実行しているのかまでは、このAPIでは見ることができません。
単発のクエリを実行し値得る場合は、
# curl 'http://localhost:9200/_tasks?pretty&actions=*search'
で出てきたタスクのIDを使ってキャンセルすれば良いでしょう。
でも、複数のクエリを実行している場合は、どれが本当にキャンセルしたいものかわかりません。
X-Opaque-Idを使用したリクエストの特定
リクエスト時にX-Opaque-Id
ヘッダを付加して実行します。
curl -i -H "X-Opaque-Id: 123456" -H 'Content-type: application/json' http://localhost:9200/.monitoring-*/_search -d'{"size": 10000}'
この状態でタスクを確認すると、
# curl 'http://localhost:9200/_tasks?pretty&actions=*search,*fetch*'
{
"nodes" : {
"RqHPIcbRRIyDb3uqTwzmDQ" : {
"name" : "RqHPIcb",
"transport_address" : "127.0.0.1:9300",
"host" : "127.0.0.1",
"ip" : "127.0.0.1:9300",
"roles" : [
"master",
"data",
"ingest"
],
"attributes" : {
"ml.machine_memory" : "16681828352",
"xpack.installed" : "true",
"ml.max_open_jobs" : "20",
"ml.enabled" : "true"
},
"tasks" : {
"RqHPIcbRRIyDb3uqTwzmDQ:9252" : {
"node" : "RqHPIcbRRIyDb3uqTwzmDQ",
"id" : 9252,
"type" : "transport",
"action" : "indices:data/read/search",
"start_time_in_millis" : 1553242069549,
"running_time_in_nanos" : 475068030,
"cancellable" : true,
"headers" : {
"X-Opaque-Id" : "123456"
}
},
"RqHPIcbRRIyDb3uqTwzmDQ:9278" : {
"node" : "RqHPIcbRRIyDb3uqTwzmDQ",
"id" : 9278,
"type" : "direct",
"action" : "indices:data/read/search[phase/fetch/id]",
"start_time_in_millis" : 1553242069698,
"running_time_in_nanos" : 326060299,
"cancellable" : true,
"parent_task_id" : "RqHPIcbRRIyDb3uqTwzmDQ:9252",
"headers" : {
"X-Opaque-Id" : "123456"
}
}
}
}
}
}
てな感じで、レスポンスにヘッダ情報が付加されて返ってきます。
これでどのクエリか特定できるので、そのタスクIDを使ってキャンセルをする、と。
おわりにらない
curlで実行している分には、curlのプロセスをkillしちゃえば(=コネクションが切れる)、Elasticsearch的にはクエリがキャンセルされるらしいので、それでも良いといえば良いかと。
コネクションを切ったときにキャンセルされるのかどうか、確証が持てない・・・
コネクションを強制的に切った場合
調べて見たら、どうやらキャンセルはされずにElasticsearch内部では処理が続く。なので、コネクションをぶちぶち切って、都度新しいリクエストを送るとリソースを使いまくる(Rallyなんかはデフォルト60秒でコネクションを切るので、それはそれはヤバイことになるかな・・・)。
タイムアウト(クエリパラメータ、リクエストボディ)を指定した場合
QueryPhase でシャードに対して実行したクエリが timeout 指定時間以内に戻らない場合にタイムアウトと判定。タイムアウトになると、当該シャードに対する FetchPhase は実行されない。結果として、FetchPhase が実行されたシャードに関する結果だけが返る。
タイムアウトが起きていなければ、レスポンスは
{"took":704,"timed_out":false,"_shards":{...
となるが、タイムアウトになった QueryPhase があると、
{"took":704,"timed_out":true,"_shards":{...
となる。