GraphiteとStatsDを使用して、インフラ監視

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/94be852e-dc19-b0f2-a19e-eedacbe0cdb3.png)

#はじめに

サーバー、アプリケーション、およびトラフィックに関するメトリックを収集することは、アプリケーション開発プロジェクトの重要な部分となります。 本番システムでは問題が発生する可能性のある多くの問題があり、データの収集と整理は、インフラストラクチャのボトルネックと問題を特定するのに役立ちます。

この記事では、GraphiteとStatsD、およびそれらがモニタリングインフラストラクチャの基礎を形成するのにどのように役立つかについて説明していきます。 MetricFireの[無料デモ](https://www.metricfire.com/demo/?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Monitoring%20your%20infrastructure%20with%20StatsD%20and%20Graphite)を予約し自分のニーズを確認してから、マネージドされたGraphiteサービスであるHosted Graphiteの無料トライアルにサインアップしてみてください。

Graphiteは、いくつかのコンポーネントで構成されるライブラリです。 ここでは、各コンポーネントについて簡単に説明します。

####Graphite Webアプリケーション
グラファイトWebアプリケーションは、グラフを作成してデータをプロットできる場所です。 Webアプリケーションでは、グラフのプロパティとレイアウトを保存できます。

  

####Carbon
カーボンはGraphiteのストレージバックエンドです。 Carbonは基本的に、TCP / UDPポートで実行するように構成できるデーモンです。 増加する負荷を処理し、レプリケーションとシャーディングを構成するために、複数のCarbonデーモンを同じホストまたは複数のホストで実行し、Carbonリレーを使用して負荷分散することができます。

####Whisper
Whisperは、Graphiteがデータを格納するために使用するデータベース形式です。

Whisperは、最新の高い解像度（1秒あたりの秒数）のデータをより低い解像度に低下させ、履歴データを長期間保持できるようにします。

Graphiteについて説明したので、続いてStatsDについて説明します。

  

####StatsD
StatsDはnode.jsアプリケーションです。 これは、ネットワーク、サーバー、アプリケーションに関するデータポイントを送信するために作成されたもので、グラフにレンダリングできます。

#セットアップ

https://hub.docker.com/r/graphiteapp/docker-graphite-statsd/
にあるdockerイメージを使用します

これは非常にシンプルなdocker-compose.ymlです：

```
version: "3"
services:
  graphite-statsd:
    image: graphiteapp/docker-graphite-statsd
    ports:
      - 2003-2004:2003-2004
      - 2023-2024:2023-2024
      - 8125:8125/udp
      - 8126:8126
      - 80:80
```

このDockerイメージを実行した後、http：// localhostにアクセスすると、ブラウザーは以下のようにGraphite Webアプリケーションをロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/048e9e46-c591-df66-1d5c-f95c9f899759.png)


この時点では、Graphiteのメトリックは空になっているはずです。 デプロイをテストしてみましょう。次のコマンドを使用して、StatsDデーモンに単純なメトリックを送信します。

```
&nbsp;echo "deploys.test.myservice:1|c" | nc -w 1 -u localhost&nbsp; 8125
```

ここでの構文は次のとおりです。

```
bucket:value|type
```

####Bucket (バケット）
バケットはメトリックの識別子です。 同じバケットと同じタイプのメトリックデータグラムは、サーバーによって同じイベントの発生と見なされます。 上記の例では、バケットとして「deploys.test.myservice」を使用しました。

  

####Value （値）
Valueは、メトリックに関連付けられている数値です。 値の意味は、メトリックのタイプによって異なります。

  

####Type (タイプ）
Typeによって、メトリックのタイプが決まります。 タイマー、カウンター、ゲージ、ヒストグラムなど、さまざまなメトリックタイプがあります。


####Timer (タイマー)
タイマーは時間間隔を測定するため、カウンターとは異なります。 たとえば、REST APIが応答するのにかかった時間を測定する場合は、タイマーを使用します。 タイマーの単一のメトリック、たとえば100 msはあまり役に立ちません。 6時間などの時間間隔で組み合わせると、より便利です。 平均、標準偏差、50パーセンタイル、90パーセンタイル、95パーセンタイルなど、さまざまなサブメトリックが各メトリックで自動的に計算されます。

```
echo "deploys.test.myservice.time:55|ms" | nc -w 1 -u localhost 8125‍
```

####Gauge (ゲージ)
ゲージは、増減できる固定値に使用されます。 たとえば、ゲージを使用して、アプリケーション内のスレッド数、またはキュー内のジョブ数を表すことができます。

これが、1つのグラフにカウンター値とタイマー値の両方を示すカーボンWebアプリケーションです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/09ce350e-139f-c1a2-0e94-9b69505d4561.png)


#Node.jsとの統合
たった今、コマンドラインを介してメトリックを送信する方法を見てきました。 実際には、Node.jsやJavaベースのサーバーを実行するアプリケーションなどの一部のアプリケーションによってメトリックが生成されるため、これらの例は当てはまりません。

ここからは、node.jsで作成されたアプリケーションがメトリックを送信する方法を見てみましょう。 以下に示すように、ポート3000で実行されている高速サーバーを考えてみます。

```
const express = require("express");
const app = express();
 
app.get("/", (req, res) =&gt; {
    res.send("Response from a simple GET API");
});
 
app.listen(3000, () =&gt; {
    console.log("Node server started on port 3000");
});
```

最初に、npmを使用してnode-statsdをインストールする必要があります。

```
npm i node-statsd --save
```

次に、StatsDクライアントのインスタンスを次のように作成します。

```
const StatsD = require("node-statsd"), client = new StatsD();
```

StatsDコンストラクターは、StatsDサーバーを実行しているマシンのホストやポートなど、いくつかのオプションの引数を取ります。 完全なドキュメントは
https://github.com/sivy/node-statsd
にあります。

私の場合、デフォルトのオプションである[http：// localhost](http：// localhost)とport8125でStatsDを実行していました。

クライアントのインスタンスを作成したら、さまざまなメソッドを呼び出して、アプリケーションにメトリックを送信できます。 たとえば、次のようにAPI呼び出しの数とタイミングを追跡できます。

```
app.get("/", (req, res) =&gt; {
    res.send("Response from a simple GET API");
    client.increment("api_counter");
    client.timing("api_response_time", 110);
});
```

ブラウザに[http：// localhost：3000](http：// localhost：3000)と入力するとすぐに、APIが呼び出され、StatsDクライアントが実行されます。 グラファイトWebアプリケーションで更新されたメトリックを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/e5e5815b-ccf2-6f83-794c-ce47d2ffec35.png)

クライアントインスタンスで使用可能なすべての方法については、[https：//github.com/sivy/node-statsd](https：//github.com/sivy/node-statsd)のドキュメントを確認してください。

#Javaとの統合
Javaベースのクライアントとの統合は、Node.jsとよく似ています。 MavenやGradleなどのビルドシステム（強く推奨）を使用している場合は、この統合を容易にするための[ユーティリティjar](https://mvnrepository.com/artifact/com.timgroup/java-statsd-client/3.1.0)を利用できます。 以下をビルド構成に追加して、自動的に含めるようにします。

####Mavenの場合：

```
&lt;dependency&gt;

      &lt;groupId&gt;com.timgroup&lt;/groupId&gt;

      &lt;artifactId&gt;java-statsd-client&lt;/artifactId&gt;

      &lt;version&gt;3.1.0&lt;/version&gt;

&lt;/dependency&gt;
```
####Gradleの場合：

```
compile group: 'com.timgroup', name: 'java-statsd-client', version: '3.1.0'
```

クライアントライブラリがインポートされたら、StatsDサーバーが実行されている目的のプレフィックス、ホスト名、およびポートを提供する実装クラスNonBlockingStatsDclientを使用して、StatsDClientインターフェイスのインスタンスを作成します。

以下に示すように、このインターフェースでは、GraphiteをStatsDサーバーに送信するtime（）、incrementCounter（）などの簡単なメソッドを使用できます。 完全なドキュメントについては、[https：//github.com/tim-group/java-statsd-client](https：//github.com/tim-group/java-statsd-client)を参照してください。

```
package example.statsd;

import com.timgroup.statsd.NonBlockingStatsDClient;
import com.timgroup.statsd.StatsDClient;

public class App {

   private static final StatsDClient statsd = new NonBlockingStatsDClient("java.statsd.example.prefix", "localhost", 8125);

   public static void main(String[] args) {
       statsd.incrementCounter("java_main_method_counter");
       statsd.time("java_method_time", 125L);

       statsd.stop();
   }
}
```

#StatisticsDの水平スケーリング

インフラストラクチャに関しては、単一のStatsDサーバーはすべての負荷を処理することができず、最終的に水平方向のスケーリングが必要になります。 StatsDでも集計を実行できるため、StatsDを使用した水平スケーリングは単純なラウンドロビンロードバランシングにはなりません。 同じキーのメトリックが複数のノードに分散されている場合、単一のStatsDがメトリック全体を正確に集約することはできません。

したがって、SatsDの作成者は、一貫したハッシュを使用して同じメトリックが常に同じインスタンスに送信されることを確認するStatsDクラスタープロキシをリリースしました。

以下は、StatsDクラスタープロキシの非常にシンプルな構成です。

```
{
    nodes: [
    {host: 'host1', port: 8125, adminport: 8128},
    {host: 'host2', port: 8125, adminport: 8130},
    {host: 'host3', port: 8125, adminport: 8132}
    ],
    server: './servers/udp',
    host:  '0.0.0.0',
    port: 8125,
    mgmt_port: 8126,
    forkCount: 4,
    checkInterval: 1000,
    cacheSize: 10000
    }
```

設定ファイルがセットアップされたら、次のように実行するだけです。

```
node proxy.js proxyConfig.js
```

Proxy.jsは、StatsDインストールディレクトリのルートにあります。

設定キーのいくつかは説明に値します：

- **CheckInterval**：ヘルスチェックの間隔を決定します。 ノードがオフラインの場合、クラスタープロキシはそのノードを構成から外します。
- **サーバー**：サーバーバイナリは、「ノード」構成で指定されたノード構成から読み込まれます。

#まとめ
StatsDとGraphiteは、インフラストラクチャの監視に最適です。 上記のすべてのコードと構成は、[githubリポジトリ](https://github.com/madhur/graphite-statsd)で入手できます。

主な利点は次のとおりです。

- **低メモリフットプリント**：StatsDは非常にシンプルなnode.jsベースのサーバーであり、その結果、メモリフットプリントが非常に低くなります。つまり、インフラストラクチャでこの設定を簡単に開始できます。

- **効率的なネットワーク**：StatsDは、接続の少ないプロトコルであるUDPを介して動作できるため、大量のデータを非常に短い時間で転送できます。

これらのプロセスを試してみたい方は、MetricFireの日本語対応の[デモをご予約](https://www.metricfire.com/demo/?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Monitoring%20your%20infrastructure%20with%20StatsD%20and%20Graphite)ください。
最適な監視ソリューションについてもお話しすることもできます。

それでは、またの記事で！