Apache Kafkaにおいて、client <-> server (broker)間の通信は独自のwire protocolで行う。
ここで、brokerとclientが別のネットワークにあってHTTPでの通信しか許可されていないシナリオを考える。
HTTP上で任意のTCP protocolをtunnelingするのは一般的なニーズであり、既存のソリューションも数多く存在する。
しかしながら、Kafka protocolのtunnelingは単純にはいかない。
これは、clientが接続する先のKafka brokerはMetadata requestによって動的にdiscoveryされるためだ。
動作としては以下のようになる:
- bootstrap-server (clientが最初に接続するbroker)をproxy serverに変えておく
- clientはbootstrap-serverにmetadata requestを送り、responseを受け取ってpartition leader等の接続先情報を得る
- clientは改めてdiscoverされたbrokerに接続しようとするが、これはfirewallでブロックされる
したがって、HTTP上でKafkaを使うには
- proxyをKafka-protocol-awareにして、Metadata responseを書き換える
- client側に手を入れて、Kafkaへの通信をハイジャックする(その上でHTTPでtunnelingする)
- (Kafka protocolを諦めて)HTTPでKafkaの機能を提供する
といった手段を取ることになる。
- Confluent REST proxyは3.の方法
- ただし当然Kafka clientをそのまま使えるわけではないため、既存のライブラリ・フレームワークなどは利用できない。
- kafka-proxyは1.の方法をとっている
- 次の仕組みで動作する:
- Kafka clientと同じネットワーク上にproxy serverを立ち上げる
- また、Kafka broker側ネットワークには(client側ネットワークのproxy serverからの)HTTP CONNECTを受けつけ、通信をtunnelingするサーバーを立ち上げる
- proxy serverは、metadata response内のbroker addressをlocalhost:{random port}に書き換え、かつそのrandom portをlistenするproxy serverを(必要に応じて)立ち上げる
- 次の仕組みで動作する:
HTTPでKafkaを使う場合kafka-proxyはよい候補だが、CONNECTは環境によっては許可されていない場合もあること、またtunnel serverの他にproxy serverをセットアップしなければならない点が面倒だ。
このことから、(Java限定ではあるが)新たなKafka tunnel over HTTP solutionを作ってみている。(現状ではまだPoCレベル)
ユニークな点として、本ライブラリは java.nio.channels.spi.SelectorProvider
を差し替えてtunnelingを実現していることがある。(参考: NIOのSelectorの実装を切り替える)
- Kafka clientのnetwork I/OはJavaのNIO API (SocketChannel, Selector)を使って実装されている
- Network I/OをハイジャックしてHTTPにwrapするSocketChannel実装をSelectorProvider経由で差し込むことで、NIO APIを利用するKafka client側に手を加えずにtunnelingを実現している。
利用方法はREADMEを参照されたい。