継続的プロファイリング

Google-Wide Profiling: A Continuous Profiling Infrastructure for Data Centers
http://research.google.com/pubs/pub36575.html

継続的プロファイリングの仕組み

  • 測定はOprofileとGoogle Perf Tools
    • OprofileでのHPMのプロファイル
    • Google Perf Toolsを使ってリモートからHTTPでプロファイル結果をとれる仕組み
      • ProfilerStart(), ProfilerStop()などのAPIがあるので、C++のアプリの場合、任意の部分をリモートからプロファイルできそうですね。こういう仕組みは、一部のサーバーのデバッグ用などにもとても良さそうです。
  • 回収・解析・表示の仕組み
    • Oprofileなどの結果をCollectorで集めて、集めた結果をMapReduceで処理してProfile Serverにいれて、Web Serverから表示できるようにしています

Googleの継続的プロファイリングの面白い点

 Hardwareの違いも含めてプロファイリングを通じて最適化するための仕組みを用意しているのはとても面白いなと思いました。処理性能も、コア数、メモリのバンド幅、メモリの構成、L1, L2, L3キャッシュなどの量などの関係、さらにアプリケーションの処理特性(CPU-intensiveな処理か、Memory-intensiveな処理なのかなど)になどによって、まるで性能は変わってしまい、それを完全に予測するのは難しいのは事実です。だからこそ、ハードに近いレイヤで、それを運用を通じて測定することで、性能改善をかけられる仕組みを用意しているのはGoogleらしいと思いました。
また、最適化した結果のコスト削減結果も、‘‘dollar amount per performance change,’’ has become popular among Google engineers. と書かれているように、コスト視点のメトリクスで見られ、性能改善結果を最終的なコストに直結させている点も面白いです

perfの使い方

CPUネックのサーバーの状況をリアルタイムに知りたいケースというのは、科学計算、暗号処理、画像処理などのCPU boundなアプリケーションでは良くあるんじゃないかと思います。

perfはoprofileのリアルタイム版といった感じで、hardware event, software eventの測定をでき、その場の状況を測定できるのでとても便利です。リアルタイムに状況を知りたい場合の使い方を中心にまとめてみました。

全体の測定

まずは、最初何も状況がわからなければ。

perf top

特定関数の測定

perf top実行後、s keyを押して、perf topで表示されたfunction名を入力。
これで、特定関数が測定できる。perf topで眺めながら、問題のある関数が把握できたらその関数だけ見るといった使い方が便利。

特定プロセス・スレッドの測定

問題のあるプロセス・スレッドが特定できているという場合には、それだけをモニタリングするというのは良くやりたくなることの一つです。以下で確認できました。

特定プロセスの測定

perf stat -e cycles -p プロセスID sleep 5
  • e で指定するイベントなどは適宜。

特定スレッドの測定

特定イベントのperformance counterの取得。
ps -L axなどでスレッドIDは決めて、以下を実行。

perf stat -t <スレッドID> sleep 5
  • e で指定するイベントなどは適宜。

特定イベントの測定

問題が特定イベントに絞り込まれている場合に。これは上記のいずれのものとも組み合わせられるので、適宜使うこと。

  • イベントはperf listで確認
  • perf stat -e event1,event2 で絞り込んで測定

call chainを表示してbottleneckを発見

これは、perf top, perf statと違って記録を残して分析するための使い方なのですが、とても便利なので書いておきます。

sudo perf record -g yourprogram
sudo  perf report -g

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として実装してるんだろうなと。

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

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化されるのかもしれません。

Perl CPANモジュールガイド Rocks!

http://www.flickr.com/photos/nophotonolife/5581237818/in/stream

PerlCPANという環境があるからこそ、今も一線で使われ続けているといっても過言ではありません。しかし、その最大の利点は、同時に初中級者にとっては問題にもなりえます。それは、モジュール量が多すぎて、何を選択すればよいかを判断するのが難しいからです。

熟練したユーザーは、モジュールの開発者、モジュールのソース、モジュールの依存量、サービスでの利用実績などから、モジュールの選択をします。しかし、これを数多くのモジュールに対してするのは、なかなか業務で忙しい方がするのは時に難しいでしょう。

だからこそ、良いモジュールを紹介するガイド役として、CPANのソムリエが必要となります。しかし、今まではそのようなノウハウはコミュニティでのみ共有されており、広く一般に知られたものではありませんでした。

富田さんのCPANモジュールガイド(http://cpanbook.koneta.org/)は、まさにこのCPANソムリエ役であり、多くのPerlユーザーにとってモジュール選択の指針となることでしょう。この本を読むことでモジュールの使い方をPOD以上に詳しく学べるだけでなく、今後新しく出てくるモジュール選択の指針の基準としても使うことができるのではないかと思います。

今日のCPANモジュール(http://e8y.net/mag/)は過去に読まれた方も多いのではないでしょうか。その富田さんが書かれたCPANモジュールのレファレンスであり、素晴らしいレファレンスになっています。

初中級者にとっての「実用的」なレファレンスとしてはもちろんのこと、モジュールを選択するための一つの指針にもなりうる本であり、多くのPerlユーザーにお勧めできる本ではないかと思います。

# 献本頂きありがとうございました!これだけ数多くのモジュールを丁寧にまとめられた富田さんの素晴らしい仕事にはただただ感動しますね。お疲れさまでした!