Hatena::Groupdann

dann's blog このページをアンテナに追加 RSSフィード

Fork me on GitHub

2011-04-16

TwitterのBlenderのアーキテクチャのポイント

 TwitterのBlenderのアーキテクチャのポイント - dann's blog を含むブックマーク はてなブックマーク -  TwitterのBlenderのアーキテクチャのポイント - dann's blog  TwitterのBlenderのアーキテクチャのポイント - dann's blog のブックマークコメント

http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html

「バックエンドサービスのI/Oが同期になると、I/O待ちで遅くなり、フロントが詰まってしまうので遅い。だから、Non BlockingなI/O呼び出しをしI/Oを多重化し、その呼び出し結果を集約することで高速化した」というのがBlenderのポイントのようです。工夫としては、Back Endサービスの呼び出しに依存関係があるので、全部を並列に呼び出すことはできないので、サービス呼び出しの依存関係を考慮して、一部並列にするところは並列に呼び出して、それ以外の部分はシーケンシャルに呼び出していると。そうすることで、I/Oを多重化できる単位を分割して呼び出すことを実現しています。

Non Blocking I/O系サーバーはイベントモデルのなじみにくさから、比較的処理がシンプルな、このようなAPIサーバーの呼び出し結果の集約など、I/Oの多重化をすることで並列化できるところ以外に適用部分はないんだろうなあとは思ってました。ちょっと前だとFriendFeedが、Tornado使って近いことをやってましたよね。

TwitterBlenderは、そのアイデアから一歩踏み込んで、ワークフロー内のサービスの依存関係を考慮して、サービス呼び出しのI/Oを多重化して、一部サービス呼び出しを並列に実行するのを汎用のミドルとして実現したのは面白いですね。

# 実装が透けて見えるレベルで解説されているので、そのうちOSS化されるのかもしれません。

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

 TwitterのBlenderに近いアーキテクチャになっているMessage Pack RPCのJava版の実装を読んでみた - dann's blog を含むブックマーク はてなブックマーク -  TwitterのBlenderに近いアーキテクチャになっているMessage Pack RPCのJava版の実装を読んでみた - dann's blog  TwitterのBlenderに近いアーキテクチャになっているMessage Pack RPCのJava版の実装を読んでみた - dann's blog のブックマークコメント

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

読んでみた感じだと、MessagePack RPCJava版の実装のポイントは、以下の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 RPCJava実装もとてもシンプルな実装になってますね。MessagePack RPCJava実装は、RPC呼び出しをJavaのメソッド呼び出しに変換する部分(Invoker)と、MessagePack形式のメッセージのエンコード/デコード部分が基本で、それをNettyにつなぐという形の実装になっています。

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