TwitterのBlenderに近いアーキテクチャになっているMessage Pack RPCのJava版の実装を読んでみた

TwitterBlenderはNIOの使い方として面白い使い方だなあと思っていたので、それに比較的近い実装をしているMessagePack-RPCのJava版の実装を読んでみました(MessagePack RPCのJava版でも同様にNettyを使っています)。

読んでみた感じだと、MessagePack RPCのJava版の実装のポイントは、以下の3つでした。

  • NettyによるNon Blocking I/Oサーバーのイベントループ
  • 入力と出力のMessagePackによるエンコード/デコード
  • 入力のメッセージからのRPC先の実装の決定方法(Reflection, JavaAssistの実装でのInvoker実装)

基本的なこの流れは、NettyのPiplineを使って実現しています。コードだと以下のような感じになってますね。ServlerやWSGI, PSGIなどを使っている方は理解しやすいんじゃないかと思います。

	public ChannelPipeline getPipeline() throws Exception {
		ChannelPipeline p = Channels.pipeline();
		p.addLast("msgpack-decode-stream", new MessagePackStreamDecoder());
		p.addLast("msgpack-encode", new MessagePackEncoder());
		p.addLast("message", new MessageHandler(handler));
		return p;
	}

簡単に動作をまとめると、「Nettyでイベントループをまわして、メッセージを受け取ったらMessagePackでデコードして、その後でMessageHandlerで呼び出し先を決めて(Reflection or JavaAssist)、オブジェクトのメソッドを呼び出しをして、結果はMessagePackのフォーマットで従って返す」ということになります。

Nettyはとても綺麗にNIO実装が抽象化されており、さらにPipelineやPiplineへのメッセージのエンコーダ・デコーダを切り替えられる仕組みなどを提供しており、サーバー実装に必要なものを簡単に書けるようになっているので、MesagePack RPCのJava実装もとてもシンプルな実装になってますね。MessagePack RPCのJava実装は、RPC呼び出しをJavaのメソッド呼び出しに変換する部分(Invoker)と、MessagePack形式のメッセージのエンコード/デコード部分が基本で、それをNettyにつなぐという形の実装になっています。

TwitterBlenderでは、メッセージのエンコード/デコードにはThriftを使っているようなので同じようにProxy Layerの部分ではPiplineに、OneToOneDecoder, OneToOneEncoderを実装したThrift用のDecoder, Encoderを実装して実現しているのでしょう。また、Blenderでは、バックエンドサービスの呼び出し手順を規定したワークフローは、NettyのPipelineとして実現されているということなので実装も大分イメージはしやすいですね。シーケンシャルにしたい部分をNettyのPipelineとして実装してるんだろうなと。