Undertowでリバースプロキシを書く

APIサーバーとWEBサーバーを分けて、その手前に認証用のリバースプロキシを建てたくなったのでやってみた。

Undertow?

さいきんのTomcatJBossがつくったTomcat

くらいの理解しかしてない。 組み込みができる。あとリバースプロキシになれる。

## まずシンプルなやつ 実は公式が @Deprecated な超絶シンプルなリバースプロキシの実装を置いておいてくれている。

undertow/SimpleProxyClientProvider.java at master · undertow-io/undertow · GitHub

これを見ると、どうやら僕は以下のものを実装しなければいけないらしいということがわかる。

  • ProxyClientの実装クラス
  • ClientCallbackの実装クラス

まずProxyClientは2つのメソッドを持ってて、それぞれ

  • findTarget: プロキシ先を選定する。既存のProxyClientだとまともに使われてないので本当の役割は違うのかも。
  • getConnection: プロキシ先とのコネクションを確立する。

をやれば良いらしいことがわかる。 ProxyClientを使うクラスであるProxyHandlerの中身を見るにURIとかクエリストリングとかはなんかよしなにやってくれるっぽい。実際よしなにやってくれた。(ref: https://github.com/undertow-io/undertow/blob/946e98e4e46b31cfe7eb1d290a9596f76698c567/core/src/main/java/io/undertow/server/handlers/proxy/ProxyHandler.java#L412-L423)

とりあえず真似して書いたら、一つのプロキシ先に通信を転送することはできた。

2つに振り分ける

今回は findTarget 内で振り分けることにした。これで良いのかは正直わからん。 で、 getConnection では振分先に流すだけ。

わりとさっくりイケた。 ただ、コネクションがすでにあれば流用する、みたいなロジックが挟まってるとAPIに流れてほしいものがWEB側に流れたりしててうまくなかったので一旦消した。

すると、10秒くらいアクセスが途切れると次のアクセスがクソ雑魚パフォーマンスになる事象が発生した。多分内部で持ってるコネクションを手放すんだと思うけどわからん。現時点で完全に雰囲気で書いている。

でもできた。書いたものは以下にあげてあるので随意に見てくれ。

examples/undertowreverseproxy at master · blackawa/examples · GitHub

次やること

  • Clojureで書き直す
  • DBを見て特定のリクエストヘッダーを埋め込んだ状態でバックエンドアプリケーションに転送する
  • 今書いてる趣味アプリに組み込んでデプロイしてみる
  • コネクションを再利用する