npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cx-helloworld-readme-ja

v1.0.15

Published

Japanese transalation of cx-helloworld README.md

Downloads

8

Readme

cx-helloworld

あなたの Nodejs アプリに Concurix profiling and monitoring solution をインテグレーションする方法を解説。10分で試せる cx-helloworld を使う方法から、詳細な機能と使用方法まで、スクリーンショットやリンクを豊富に使って説明しています。

helloworld を使って試してみる

ステップ 1 concurix-server をインストール、実行する:

concurix-server は、貴方のアプリのトレース・データ、ソースコードの情報をメモリ上か貴方の指定するファイルに格納し、どこかに送ることはありません。

グローバル インストール (推奨):

$ npm install -g concurix-server
$ concurix-server

ローカル インストール:

$ npm install concurix-server
$ ./node_modules/concurix-server/bin/server.js

ステップ 2 helloworld をインストール、実行する:

$ npm install cx-helloworld
$ node ./node_modules/cx-helloworld/concurix-root.js

ステップ 3 ブラウザでモニタする: http://localhost:8103/dash/wfp:helloworld

基本設定を理解する

helloworld.js のように、一つのファイルからなるモジュールは次のように走らせますね。

$ node helloworld.js

helloworld.js を Concurix を使ってトレースする場合、一番、手っ取り早い方法は、helloworld.js は、そのままで、別に、wrapper を作り、そこで、トレーサと helloworld.js を require すればよいのです。cx-helloworld/concurix-root.js を見てください。

$ node concurix-root.js

helloworld が、走って、ブラウザからモニタできたら、次は、貴方自身のモジュールをモニタしてみましょう。それが、myapp.js だったとすると、myapp.js を cx-helloworld ディレクトリ下に置き、concurix-root.js の 2 行目にある、

require("./helloworld.js")

require("./myapp.js")

に変えて、

$ node concurix-root.js

とすれば、myapp.jsのトレースができます。次に、トレーサのパラメータを説明します。

4 つのトレーサ パラメータ

concurix-root.js の最初の require 文でトレーサを設定しています。トレーサの設定はトレースしたい全てのモジュールの前に実行する必要があるので、require("concurix") 文をどこに置くかは、大切なポイントです。次に 4 つのパラメータを用途に合わせて、変更します。

var concurix = require("concurix")({
  accountKey: "wfp:helloworld", // 必要  "wfp:"で始まる英数字文字列
  archiveInterval: 5000,    // ミリ秒  規定値 60000
  api_host: 'localhost',        // 規定値 'localhost'
  api_port: 8103                // 規定値 8103
})

accountKey [必要] : 'wfp:'で始まる英数字の文字列を指定します。ベスト プラクティス (best practice) は、プロジェクト名やモジュール名を使うこと。例えば、 プロダクションの「dashboard」というモジュールをモニタするのなら、「wfp:prod-dashboard」、テスト環境で「payment」サブシステムをモニタしたいのなら、「wfp:test-payment」が適当かもしれません。「技を極める」「サーバ設定オプション」で、詳しく説明しますが、特に、データをファイルに残しておく場合、どのプロセスをトレースしたかが分かるように一貫した名前付けをしておくと、解析する際、便利です。適当に「wfp:wer234jwe」とかしてしまうと、トレースはでき、データは残せますが、後で「なんのこっちゃ」と頭を抱えることになりかねません。

archiveInterval [オプション] : (ミリ秒) トレーサが Concurix サーバにデータを送る時間間隔で、5000 (5秒) 以上、 60000 (1分)以下の値を指定します。archiveInterval によらず、一つのトレース ファイルのデータ量に大きな変化はありせんから、archiveIntervalの値を十分の一にすると、データの精度が 10 倍になる代わりに、トレース ファイル数も 10 倍になり、従って、保存に必要なスペースも 10 倍になります。データをメモリに置くか、ファイルするかによって、メモリ量、ディスク スペースへのインパクトを考えておかねばなりません。また、archiveIntervalが小さいほど、トレーサとサーバ間のデータ送受信が、より頻繁に行われるので、パフォーマンスにも多少、影響があります。規定値は 60000 です。

api_host [オプション] : Concurix サーバのURLを指定します。モニタするモジュールを走らせるホスト、すなわち、トレーサが走るのと同じホスト上でサーバを走らせるか、別のホストでサーバを走らせるかを選択することができます。前者の場合は、「localhost」と指定すればよいし、後者の場合は、そのリーモート ホストのURLを指定します。いずれの場合も、サーバ側には、上述のメモリ量、ディスク スペースが必要になります。規定値は 'localhost' です。

api_port [オプション] : Concurix サーバが聞き耳を立てているポート番号です。規定値は 8103 です。変更する場合は、サーバを起動する時に、同じポート番号を指定することをお忘れなく。

concurix-server

トレーサは Concurix サーバに HTTP プロトコルを使ってデータを送りますが、時に、トレーサ側で次のようなエラー メッセージを目にすることがあります。

Error attempting to send trace file: Error: connect ECONNREFUSED

これは、トレーサの'api_port'で指定したポートで、Concurix サーバ プロセスが動作していないため、サーバ自身は立ち上がっていても、接続が拒否されたというエラーです。例えば、トレーサを走らせたままで、サーバ側の設定を調整するために、一旦、サーバ プロセスを停止した場合などにも起こります。その時点で、トレーサが送ろうとしていたデータは失われますが、他に悪影響はありません。Concurix サーバ プロセスが動作しているにもかかわらず、トレーサ側で、このエラーが発生した場合は、トレーサ側の api_host の設定が違っているか、トレーサ側とサーバ側のポート番号の設定が一致していないことが考えられます。

concurix-server をセットアップするには、 'npm install -g concurix-server' としてグローバルにインストールし、concurix-server でスタートするのがよい方法です。

$ npm install -g concurix-server
$ concurix-server [port]

ここで指定する port は、トレーサの api_port で指定したポート番号と同じ数値を使います。

OSX上に設定する場合の注意 concurix-server のインストールの際には、concurix-server が依存するいくつかのモジュールのコンパイルが行われます。OSX上で、コンパイルするためには、Apple xCode (約2GB) か Apple Command Line Tool (約300KB)が必要です。いずれも設置されていない場合は、ファイル サイズの小さい CLT を、次のようにして設置するのが得策です。OSXのバージョンによっては、別の方法で xCode か CLT の設置が必要です。

$ xcode-select --install

Linux上に設定する場合の注意 concurix-server のインストールの際には、concurix-server が依存するいくつかのモジュールのコンパイルが行われます。そのために g++ が必要です。例えば、Ubuntu上では、次のコマンドで g++ を設置することができます。

$ sudo apt-get update
$ sudo apt-get install g++

以上の設定が完了すると、トレーサから送られたデータは、サーバ側データベースへ格納され、同時に、様々なデータ テーブルもリアルタイムで更新されていきます。そして、ブラウザから、システムの挙動をリアルタイムで、モニタすることができるようになります。

http://<api_host><:api_port>/dash/<accountKey>

ちなみに、cx-helloworldは、 http://localhost:8103/dash/wfp:helloworld で、モニタすることができます。

Concurixを使いこなす

Concurix profiling and monitoring solution は、トレーサ、サーバ、Web UIで、構成されています。

直接、トレーサをインテグレーションする

cx-helloworld では、トレースするモジュール、helloworld.js を変更せずに、concurix-root.js という wrapper を作り、そこに require('concurix') 文を置いてトレーサをインテグレートしました。別のインテグレーション方法は、トレースするサブシステムのルート モジュールの最初、すなわち、他の「require」文の前に、require('concurix') を置くように、当該モジュールファイルを直接、変更することです。次の文を、挿入すれば、「直接、トレーサをインテグレーションする」のは完了です。

var concurix = require("concurix")({
  accountKey: "wfp:helloworld",	// 必要  "wfp:"で始まる英数字文字列
  archiveInterval: 5000,		// ミリ秒  規定値 60000
  api_host: 'localhost',        // 規定値 'localhost'
  api_port: 8103                // 規定値 8103
})

サーバ設定オプション

サーバ側には、6 つの設定オプションがあります。これらは、config.json ファイルに定義してありますから、これを直接、エディットしてオプションを変更してください。concurix-server をグローバル インストールした場合は、/usr/local/lib/node_modules/concurix-server/config.json になります。

var config_options = {
	stale_minutes: 750, // データベースにトレース データを保存する期間を分で指定。 1日は、60 x 24 = 1,440
	chart_minutes: 720, // [timeline ビュー](#timeline_view)に表示するトレース データの期間を分で指定。1日は、60 x 24 = 1,440
	max_transaction_count: 30, // [transaction history ビュー](#transaction_view)に表示するトランザクションの数
 	in_memory: false, // トレース データベースをメモリに置くか、ファイルに置くか。
 	dir_path: "./", // トレース データベースをファイルに置く場合のディレクトリ パス
 	db_name: "minkelite.db" // トレース データベースをファイルに置く場合のデータベース ファイル名
}

timeline ビュー

oz_timeline

ブラウザで、例えば、http://localhost:8103/dash/wfp:helloworld とした時に、このビューが最初に表示されます。上の折れ線グラフは、load average (1m) と process uptime を示します。プロセスが再起動した場合は、process uptime はゼロに戻りますが、Process IDも変わりますから、timeline ビュー上では、process uptime は、常に、右肩上がりの直線となります。下の折れ線グラフは、当該プロセスのメモリ使用状況を示します。RSS とは、「Resident Set Size」です。

timeline ビュー上で、マウスを移動すると、黒い縦線が、カーソル位置に現れます。黒い縦線は、特定の時刻を指し示しています。この状態で、クリックすると、その時刻のトレース データを表示するsummary statistics ビューに表示が移ります。

  • Host リスト と Process ID リスト

timeline ビューの右肩に Host リストと Process ID リストが表示されます。例えば、複数のトレース モジュールを複数のホストで走らせ、一つの Concurix サーバに全てのデータを送るように設定した場合、これらリストから、 Host と Process ID を選択して、表示することができます。初回の表示は、一番、最近のデータを持つ Host / Process ID を自動的に選択し表示します。トレースしているアプリが、再起動した場合、Process ID は変わります。通常、後からスタートしたプロセスは大きな Process ID を持ちますが、OS が再起動した場合、Process ID は小さい値に戻るので、長期間にわたるモニタリングの際は、OS の再起動があると、同じホスト、Process IDでも全く異なるデータであることも起こりえます。ただし、その場合でも、NTPなどを使ってホストのクロックが正しく設定されている限り、時刻は異なりますから見分けることはできます。また、同一のホストでも、OSにより、ホスト名が変化する場合があります。例えば、私の Mac Book Pro は、SetoMBP.local や SetoMBP.home などのホスト名で表示されています。

transaction history ビュー

oz_transactionhistory

Transaction history ビューには、サーバ設定オプションの max_transaction_count で指定された数だけトランザクションを表示します。例えば、上のスクリーンショットでは、2つのトランザクション型:"request GET http://localhost:8123/" と "serve GET /"を表示しています。各々のトランザクション型をクリックすると、どちらも、69 のトランザクション インスタンスが表示されている。

なぜ、69 トランザクション インスタンスがあるのでしょうか。これらグラフは、chart_time を 10分に設定して表示したものです。summary statistics ビューを見ると、実際の archive interval (Profile time duration) は、8.6 秒であることが分かります。10分 = 600 秒 / 8.6 秒 = 69.76 ですから、69 になる訳です。また、 Profile time duration (実際の archive interval) は、トレーサの起動時に、ランダムに決まりますから、cx-helloworldの規定のセットアップを使ったとしても、cx-helloworld を再起動すると、Profile time duration は常に 8.6 秒になる訳ではありません。

各インスタンスは、かかった処理時間の平均と標準偏差を、株価の変化を表示するのによく使われる「ローソク足」というチャートで示しています。各インスタンスは、一つのトレース ファイルに相当し、この場合は、8.6 秒間のデータを含んでいます。helloworld.js を読むと、毎秒一つのHTTP GETリクエストを送っていますから、8.6 秒の間には8つか9つのHTTP GETリクエストが発生しているはずです。それらHTTP GETリクエストの処理時間はばらつくので、標準偏差はゼロでない値を持つことになります。

max_transaction_count は、表示するトランザクション型の数を決めるのに使われます。ただし、Concurix サーバのデータベースには、max_transaction_count にかかわらず、全てのデータが記録されます。「では、全部、表示したらよいではないか」と思われるかもしれません。max_transaction_count を使う理由は以下の通りです。arhiveInterval を1分とすると、負荷の大きなサービスの場合、一つのトレース ファイルに、何千というトランザクションが記録されることも起こりえます。全てを表示するに必要なメモリ量、処理時間は妥当なコストなのか、何千もあるトランザクションを全部検討できるのか、表示するスクリーンの解像度は十分か、などを考えると「常に全部表示する価値がある訳では無い」ということになります。そういう状況に応じて max_transaction_count 値を設定する訳です。

Concurix サーバが max_transaction_count で指定された数だけ、トランザクションを選ぶ際、処理時間の最大値が大きいものから優先的に選んで表示し、分析を効率的に行うことを助けるようになっていることも大切な点です。開発環境では、できるだけ多くのトランザクションを表示し、プロダクション環境では少なく設定するのが効率的であると言えます。開発環境とプロダクション環境で推奨されるサーバ設定オプションで詳述します。

transaction history ビュー上でも、黒い縦線カーソルを移動し、クリックすると、timeline ビューと同様に、summary statistics ビューに移行し、特定の時刻のトレース データを更に分析することができます。

summary statistics ビュー

oz_summarystatistics

「Profile time duration」は、実際のデータ送信間隔 ( archive interval ) を示します。トレーサは初期化の際、archiveInterval としてユーザが設定した値に、5 秒以下のランダムな値を加えたものを実際のデータ送信間隔とします。「Total time executing javascript」は、実際に Javascriptの実行にかかった時間を、「Synchronous code execution」は 、その時間をパーセントで示しています。

transaction sequences ビュー

oz_transactionsequences

transaction sequences ビューは、非同期 callback がいつ呼ばれたのか、実行時間はどのくらいだったのかを示しています。上のグラフでは、緑色のバーをクリックすると flame graph ビューに移行します。

flame graph ビュー

oz_waterfall oz_flamegraph

最後に、flame graph ビューでは、コード パスを階層的に、二次元で表示しています。flame graph ビューの下には、同じ情報を図ではなく文字列を使って、いわば一次元的に表示します。flame graphを見ると構造が、一目瞭然で、文字列による表示と比べると、複雑な情報をより効果的に表示できるのがお分かりいただけると思います。更に、詳細は flame graphの読み方を参照してください。

技を極める

Error: Cannot find module 'jade'

サーバ、トレーサを設定し、データが記録されていることを確認したあと、ブラウザで、例えば、localhost:8103/dash/wfp:helloworld の様にして、初めてモニタしようとすると、「 jade が見つからない」というエラーになったという方のための技です。このエラーは、「 express が jade にアクセスしようとしたが、見つからない」という意味です。このエラーが起こった場合、concurix-server の package.json には、express と jade の両方に依存すると記述してあるにもかかわらず、concurix-server/node_modules のディレクトリ下には jade しかインストールされていない。concurix-server/node_modules に両方がインストールされていない場合、concurix-server 下で、「 npm install 」を行い、concurix-server/node_modules に express と jade の両方が存在することを確認してから、concurix-server を再起動すれば、正しく設定されます。これは Concurix に限ったことではなく、他にも同じ苦労をされている方がいらっしゃるようで、この Stackoverflow の投稿 に事情が書いてあります。興味のある方はご一読ください。

トレーサがうまく起動しないのだが、なぜ ?

flame graphs で分かるように、トレーサは、我々のモジュールはもちろん、依存するモジュールの全ての関数もトレースして、何十万行にも及ぶ、アプリ全体の挙動を記録しています。なかなか大変な仕事をしている訳です。で、時として、トレーサが根をあげることも起こる。setTimeout に自らの関数を callback として引き渡す場合が、一例です。筆者の場合は、setIntervalを使って書き直しましたが、常にそれができる訳ではありません。リファクタリングは工数がかかりすぎるかもしれないし、第三者のモジュールでは、難しい。

簡単な対応策は、「 black list 」です。 以下に示すように、トレーサを初期化する際に「 ここに落とし穴があるよ 」と知らせておくのです。

var concurix = require("concurix")({
  accountKey: "wfp:helloworld", // 必要  "wfp:"で始まる英数字文字列
  archiveInterval: 5000,    // ミリ秒  規定値 60000
  api_host: 'localhost',        // 規定値 'localhost'
  api_port: 8103,               // 規定値 8103
  blacklist: [
	"*/foo.js",  // block any file named "foo.js"
	"*node_modules/foo/*" // block anything under module "foo"
  ]
})

開発環境とプロダクション環境で推奨されるサーバ設定オプションは何ですか?

開発段階では起こっていることをリアルタイムに、注目している短い時間だけ、精度よくモニタしたいでしょう。プロダクション環境では、1日とか3日とか比較的長い時間、データを残し、オフライン解析のためにデータベースをファイルとして保存し、プロダクション システムへのパーフォーマンスのオーバヘッドを低く抑えるために、archiveInterval を大きくし、リアルタイムのモニタリングも軽量化するために max_transaction_count を小さい値に設定する方がよいでしょう。「オフライン解析」 については後述します。規定値、ここに示したサーバ設定オプションの規定値ここに示したトレーサ パラメータの規定値 は、その両方に使える設定になっています。

サーバ設定オプションとトレーサ パラメータのうち、数値で指定するものは全て、トレース データを格納するメモリ、或いは、ディスク容量に影響を与えます。トレースの目的と、トレースのコストを考え合わせて、決める必要があります。Concurix profiling and monitoring solution は、開発段階だけでなく、プロダクション システムへの展開も考慮して設計されています。我々自身の使用経験から、種々のパラメータとオプションを作り込んでありますから、様々な環境で、それぞれの目的に合った設定を選択して使っていただけます。

以下に、我々の推奨するトレーサ パラメータとサーバ設定オプションを開発段階とプロダクションに分けて示します。実際は、それぞれの状況に合わせて、変更して設定していただければよいのです。

トレーサ パラメータ

| | 開発環境 | プロダクション | 定義 | | ------------- | ----------- | ----------- | ----------- | | archiveInterval | 5000 ミリ秒 | 60000 ミリ秒 | トレーサからサーバにデータを送る時間間隔の目安 | | api_host | "localhost" | リモートサーバの URL | Concurix サーバの URL | | api_port | 8103 (規定値) | システムに合わせて設定 | Concurix サーバのポート番号 |

archiveInterval はトレースデータの精度を決める重要なパラメータです。10倍大きな値にすると、精度は十分の一に落ちますが、データ量も十分の一になるので、データ格納スペースを効率化できます。

api_host と api_portは Concurix サーバの設置場所を示します。トレーサとサーバーは、HTTP APIを使ってやりとりします。例えば、複数のモニタするアプリ(トレーサ)とサーバを全て同じホスト上で動かすと、サーバ プロセスを動かすための、メモリ、CPUバンド幅は、アプリに影響を与えます。サーバをリモート ホストで動かすと、そのようなメモリ、CPUバンド幅の影響は無くなるものの、HTTPによるネット上の通信のための時間がかかるようになります。

サーバ設定オプション

| | 開発環境 | プロダクション | 定義 | | ------------- | ----------- | ----------- | ----------- | | stale_minutes | 15 分 | 1450 分 | データベースにトレース データを保存する期間 これ以上古くなったデータは順次削除する | | chart_minutes | 10 分 | 1440 分 | Timeline ビューに表示するデータ期間 | | max_transaction_count | 500 | 20 | Transaction ビューに表示するトランザクション数 | | in_memory | true | false | トレース データベースをメモリに置くか、ファイルに置くか | | dir_path | 不要 | "./" | トレース データベースをファイルに置く場合のディレクトリ パス | | db_name | 不要 | "minkelite.db" | トレース データベースをファイルに置く場合のデータベース ファイル名 |

archiveInterval と同様、stale_minutes を変えることにより、ストレージ容量、パーフォーマンスへの影響を調整できます。例えば、開発環境用の値 (archiveInterval: 5 秒、stale_minutes: 15 分)の場合、データベース サイズは、数MBであり、メモリ上に置いても問題なく、システム、モニタの反応も速い設定になります。メモリ上に置くので、サーバを再起動するとデータは失われますが、私は、開発段階ではラップトップで、この設定値を使っています。 一方、障害発生時など、詳細なオフライン解析を目的とするプロダクションへの設置には、archiveInterval: 60 秒、stale_minutes: 4320 分 = 3 日としています。また、プロダクション環境では、Concurix サーバを別のホストで走らせ、かつ、定期的にトレース データベース ファイルをコピーして保存しておくのが運用上、良い方法です。

留意点: Timeline ビューに表示するデータ点、すなわち、トレース データ数は最大5,000で、それ以上になるとチャートには何も表示されなくなります。この値は過度にシステムリソースを使うことを防ぎ、且つ、実用上十分に多くのデータを表示できるように、決めました。archiveIntervalを1分とすると、3日分のデータ、4,320 点を表示するのに十分な値です。データベースに保存するデータ数は、この制限はありませんから、stale_minutes を大きな値に設定しても、chart_minutes を、小さい値に設定して、Timeline ビューに表示するデータ点が、5,000 を超えないようにしてください。

オフライン解析( Flight Recorder 機能 )

Concurix サーバはトレース データをデータベースとして保存します。サーバは、stale_minutes で指定されたデータを保存し、古いデータは削除する「 pruning 」処理を常時行っています。一般に、TTL (time to live) と呼ばれる処理です。 「 in_memory 」を false とすると、トレース データを「 dir_path 」と「 db_name 」で指定されたファイルに格納します。ファイルに格納すると、次のような使い方ができます。

プロダクション システムの障害発生時には、当該データベース ファイルをコピーし、「 localhost 」に、Concurix サーバを設置し、 「in_memory 」を false として、そのデータベースファイルを、「 dir_path 」と「 db_name 」で指定することにより、障害発生前のシステムの挙動をオフラインで解析することができます。いわば、航空機に搭載されている Flight Recorder と同じ機能です。オフライン解析の際、忘れてはならないのは「 stale_minutes : 0 」と設定して「 pruning 」処理を行わないようにすることです。また、オフライン解析時には、トレーサは設置しません。

Concurix がシステムに与えるオーバーヘッドはどのくらいですか ?

設定に応じて、必要なリーソスは大きく変わりますから、一言ではいえませんが、開発環境とプロダクション環境で推奨されるサーバ設定オプションを使った場合、オーバヘッドは小さく、いわゆる「 ノイズ レベル 」です。様々なニーズにあった設定が、開発環境でも、プロダクション環境でも、十分に見合うコストで実現できると考えています。

flame graph の読み方、解析の仕方を教えてください

flame graph は、システムの挙動を細部に渡って表示してくれます。貴方のモジュールと依存する全てのモジュールの情報を含んでいますから、初見では「取りつく島がない」と思えるかもしれません。ここでは、flame graph の解析は、どこから取り掛かると良いかをご紹介します。

まず最初に、自分の最もよく知っているモジュールを選びます。たとえば、cx-helloworld とします。次に、flame graph を鳥瞰して、あるいは、ブラウザの Find を使って、そのモジュール名を探し、flame graph では、何色で表示されているかを把握します。例えば、helloworld の例では、「 cx-helloworld#app.get() fn argument 」が、「淡緑色」で表示されています。これは、全ての flame graphs を通して、cx-helloworld モジュールは、「淡緑色」で表示されることを意味しますから、まず、この色を頭に入れておきます。本READMEで使っているスクリーンショットは、規定のパラメータとオプションを使って、私の Mac Book Pro 上で、動作している cx-helloworld の動作を示しています。貴方が同様に設定した cx-helloworld では、ほぼ同じ flame graph になるはずですが、様々な条件が違うので、cx-helloworld モジュールの色も含めて、全く同じにはならないことは言うまでもありません。

app.get("/", function(req, res) {
  res.end((new Date()).toString()+" Hello world!");
});
},1000);

helloworld.js を読むと、app.get に引き渡された callback は、res.end 関数を呼ぶことが分かります。この flame graphは、それを示しています。すなわち、 cx-helloworld#app.get() fn argument 」の淡緑色のバーのすぐ上には、「 http#OutgoingMessage.prototype.end 」が載っています。淡緑色のバーの下には 28 の「緑色」のバーが階層的に並んでいて、これらは全て同じ「 express 」 モジュールを示しています。よく知られているように、Express が大きな助けになっていることが、その階層の厚さから、分かります。また、「紫色」の、小さなバーにも気がつきます。マウスをその上に移動するか、ブラウザの拡大機能を使うと、その「紫色」のバーは、「 parseurl 」 モジュールであることが分かります。

さて、他の flame graph から、「淡緑色」のバーを見つけてみましょう。「 cx-helloworld#setInterval() fn argument 」と「 cx-helloworld#setInterval() fn argument>request() fn argument 」が見つかります。それらは、helloworld.js の次の関数呼び出しに対応しています。

setInterval(function(){
	request("http://localhost:8123",
		function(error, response, body) {console.log(body);});
},1000);

helloworld.js は単純なモジュールなので、一目して app.get と setInterval 以外に app.listen も呼んでいることが分かります。app.listen に引渡した 無名 callback 関数は、この flame graph ビューのどこかに登場しているのでしょうか。

app.listen(port, function() {
  console.log("Listening on " + port);
});

答えは、「どこにも登場していない」です。なぜかというと、app.listen とその無名 callback 関数は、helloworld.js が起動された直後に呼ばれて、その helloworld HTTP サーバが HTTP リクエストを受け付ける状態になった後では、二度と呼ばれません。この flame graph ビューは helloworld.js が起動されてから、しばらくたった状態のものですから、どこを見ても見つからないのは当然です。もし、app.listenの無名 callback 関数が、flame graph ビューのどこかに見つかったとすると、その時点で helloworld.js が再起動したことを意味します。

次のことを試してみましょう。Concurix サーバを走らせたままで、helloworld プロセスをマニュアルで、停止し、再起動してみます。ここでは、「 node concurix-root.js 」として再起動します。再起動すると、サーバには、新しい Process ID が現れます。10 秒ほど待つと、最低一つのトレース ファイルがサーバ側のデータベースに格納されますから、ブラウザを使い timeline ビューの右上にある Process ID リストから、その新しい Process ID を選びます。そして、timeline ビュー上で、一番左端、すなわち、時間軸で一番古いポイントをクリックし、flame graph ビューまで進みます。

二つの事に注目してください。まず、気がつくことは、summary statistics ビューのパーチャートのオレンジ色の部分が大きいことです。これは、起動時に負荷がかかったことを意味します。次に、flame graph ビューの構成が、上のスクリーンショットに示されている定常状態に達した後の構成とずいぶん違います。これも、起動時には、システムの動態が全く異なることを意味しています。

そして、同じように、注目する色を見つけようとブラウズしていると、「 cx-helloworld#app.listen() fn argument 」を発見できます。

これまで見てきたように、flame graph は、関数呼び出しの構造を理解するための強力な助けになります。最後に、cx-helloworld より複雑な構造を示す flame graph の一例を示します。

ghost_flamegraph6

timeline ビューの時間軸に時々見られるオレンジ色の三角マークは一体、何ですか?

オレンジの三角マークは、簡単な統計処理から、その時点のトレース データにある「 system loadavg 」か「 process memory used 」の値が、3シグマの外にあることを示しています。シグマは、標準偏差値で、3シグマは、平均値に標準偏差の3倍の値を加えたものより大きいことになります。ここで、「 process memory used 」は、注目しているプロセスの heap 使用量を示していますが、「 system loadavg 」は、システム全体のロードを示していることをお忘れなく。

transaction sequences ビューに現れる 'Untagged Waterfalls' とは何ですか?

'Untagged Waterfalls' は、HTTP リクエストなどの特定のトランザクションに関係付けられなかったコードパスを示します。他の関係付けられたコードパスと同じように、クリックすれば、flame graph を使った詳細の解析が可能です。

Concurix サーバが書き出す console log の意味は?

morgan からのアウトプットで 'combined' フォーマットです。

:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"

例えば,

127.0.0.1 - - [26/Nov/2014:18:04:44 +0000] "POST /results/1.1.0 HTTP/1.1" 202 - "-" "-"

Heroku で concurix-server は動作しますか?

はい。concuix-server のバージョン 0.2.19 以降をご使用ください。クライエント側の tracer parameters では、api_host として concurix-server が動作している Heroku app 名を指定し、 api_port として 80 を指定してください。

その先にあるもの

npmjs.com に登録されている Nodejs/Javascript パッケージ数は、104,000を越え、Maven CentralのJavaパッケージ数、Rubygems.comのRubyパッケージ数を凌いで、2014年、トップに躍り出ました。 2012年初頭の登録パッケージ数は、Java、Rubyの 2 割以下だったこと、現在、1日の増加数が、Java、Rubyの 70 以下であるのに対して、Nodejs/Javascriptは、210 以上であることを考えあわせると、Nodejs/Javascript は、メインストリームになったと言っても過言ではありません。( http://www.modulecounts.com調べ )

我々、Concurix は、比類のない machine generated time-series data analytics の実現と、Nodejs コミュニティへの貢献を目的として、様々な技術を開発しています。 一例として、 このブログでは、機械学習を使ったデータ サンプリング手法について紹介しています。また、Concurix トレーサ、サーバ、cx-helloworld は、いずれも、github、npm に公開しています。

これら公開モジュールやカスタム データ ロギング、マルチ ユーザ版 Concurix など高度な機能を擁する Concurix Enterprise Edition に、ご興味をお持ちのは、私、[email protected] 宛、あるいは、[email protected] 宛に、ご連絡お待ちしています。