Transport Clientによる検索を維持しつつノードを再起動したい

シチュエーション

  1. 3台のノードからなるクラスタにJavaのTransport Clientで接続(接続先IPアドレスに3つのノードすべてを列挙)
  2. 1台のノードをシャットダウン・起動
  3. 20%前後の確率で https://github.com/elastic/elasticsearch/issues/11202 のエラーがJava Client側で発生

概要

Javaアプリケーションを起動したまま、検索できる状態を維持しつつノードを1つずつ再起動したいです(ローリングアップデートなどのため)。
しかしTransport Clientで接続した場合、ノードを再起動するとcatchすることができないエラーが発生する場合があります。

これに対する私が知っている解決策は現状3つあります。

  1. REST API(9200ポート)をLBで束ねてREST APIへアクセスする。ノードのシャットダウン時にはLBからそのノードを一時的に切り離す
  2. Node Clientを使用する(手元で実験してみたところNode Clientによる接続ではエラーは発生しませんでした)
  3. ノードのシャットダウン前にTransport Clientの接続先一覧からそのノードのIPを削除、その後Javaアプリケーションを再起動してTransport Clientがシャットダウンするノードへアクセスしないようにする(起動後には逆の手順を行う)

しかし、現状の私達の環境で採用するにはそれぞれ問題があります。

  1. 現状使用しているelastic4sというライブラリが使えない
  2. ノードサーバからアプリケーションサーバへの接続がネットワーク環境の制約上できないため使えない
  3. 3ノード・2アプリケーションの場合、接続先の書き換えと再起動を8回もする必要があり煩雑。

Transport Clientによる検索を維持しつつノードを再起動する方法はなにかないでしょうか?

@johtani です。

制約について確認ですが、elastic4sがTransportClientを使っているということでいいでしょうか?
あと、2番目のネットワーク環境の制約がちょっと理解できませんでした。

TransportClientはラウンドロビンで接続先を決めているだけで、クラスタの状態まではわかっていないので、難しいかと。

案として、アプリケーションサーバでElasticsearchをクライアントノードとして起動するというのはどうでしょうか?
そして、アプリケーションからは、ローカルのクライアントノードに対してTransportClientで接続してみるというのは?

あとは、elastic4sがTransportClientを利用しているという意味であれば、elastic4s側でExceptionをキャッチして、リトライの処理を行うようにしてもらうというのもいいかもしれないです。
Exceptionである以上、キャッチできないというのはないと思うので。

制約について確認ですが、elastic4sがTransportClientを使っているということでいいでしょうか?

はい、その通りです。

あと、2番目のネットワーク環境の制約がちょっと理解できませんでした。

私達のところではESクラスタのネットワークとアプリケーションサーバが別のサブネットに所属しておりnat越しになっているため、
アプリケーションサーバ → ESクラスタはアクセスできても逆ができない構成になっています。

Node Clientを使用する場合、
Node Client → 接続先のデータノード
への接続だけではなく、
接続先のデータノード → Node Client
へもpingが通らないと(publish_hostが見えないと?)Node Clientが使えない、よって私達のところのネットワークではNode Clientは使えない、と思っていたのですがこの理解は間違っていたりしますか?

案として、アプリケーションサーバでElasticsearchをクライアントノードとして起動するというのはどうでしょうか?
そして、アプリケーションからは、ローカルのクライアントノードに対してTransportClientで接続してみるというのは?

アプリケーションサーバ内でクライアントノードを立ち上げようともしてみたのですが、前述のnat越しの問題のためか同じクラスタとして立ち上げることが出来なかったように思います。

あとは、elastic4sがTransportClientを利用しているという意味であれば、elastic4s側でExceptionをキャッチして、リトライの処理を行うようにしてもらうというのもいいかもしれないです。
Exceptionである以上、キャッチできないというのはないと思うので。

すみません、これは自分の勘違いでした。キャッチできます。

上のようなコードで実験してたのですが、stacktrace上に自分のコードが出てこないのでcatchできていないと勘違いしていました。
実際にはきっちりcatch移行の部分を通っていました。

catchできてるのでリトライを入れるのが一番楽ですかね。

確かにping通らないと厳しいですね。
であれば、クラスタ側にクライアントノードを立てるのも一つの案かと思いますがどうでしょう?
LBの方が運用が楽という話であれば別ですが。

クラスタが存在するネットワーク側にクライアントノードを建てることも考えたのですが、
ローリングアップデートのときは結局クライアントノードもアップグレードする必要が有るためシャットダウン・起動する必要がある → 結局同じエラーが発生する可能性があるのでそれでは解決できないという結論になりました。
あと、クラスタが存在するネットワークが物理サーバー用のネットワークであるためクライアントノードを建てる場合は物理サーバーである必要があり、コスト面でNGというのもあります。