1954

Thoughts, stories and ideas.

Tunneling Kafka protocol over HTTP

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を使うには

  1. proxyをKafka-protocol-awareにして、Metadata responseを書き換える
  2. client側に手を入れて、Kafkaへの通信をハイジャックする(その上でHTTPでtunnelingする)
  3. (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レベル)

github.com

ユニークな点として、本ライブラリは 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を参照されたい。