gRPCを使ったシステムのサービスレベルを外形監視で観測する

所要時間:約 10分

システムのユーザーのトラフィックを外部からシミュレーションし、システムの可用性や機能性、パフォーマンスを外部から監視することは一般的に外形監視と呼ばれています。外形監視により、システムのサービスレベルを継続的に計測・把握することができ、実ユーザーに影響が出る前に問題を検知して解決することが可能になります。

New Relic Syntheticsは外形監視のための機能であり、WEBアプリやAPIの死活監視やユーザーの操作シナリオの監視などを行うことができます(Syntheticsの紹介記事)。New Relic Syntheticsの提供機能の一つであるAPI Testは、スクリプトからのHTTPコールを通じてAPIエンドポイントの監視を行うことができます(オンラインドキュメント)。

gRPCを利用するシステムについても同様に監視することが可能です。この投稿では、gRPCを利用するシステムをSyntheticsにて監視するための手順について説明します。注意点としては、通常SyntheticsはNew Relicがグローバルに用意している拠点からシステムにアクセスすることができますが、今回のgRPCの例のように追加のパッケージが必要となる場合は、自分の環境にContainerized Private Minionというコンテナベースのエージェントをインストールする必要があります。自分の環境に導入するという点を除いては、UIでの操作やレポートは通常のSyntheticsのグローバルの拠点を使う場合と同様です。

 

セットアップの大まかな流れは以下の通りです。

  1. パッケージ定義(package.json)を置くためのディレクトリを作成する
  2. パッケージ定義(package.json)を作成する
  3. New RelicのUIからPrivate Locationを追加し、Location Keyを取得する
  4. Containerized Private Minionをインストールする
  5. Synthetics API Testのスクリプトを設定する
  6. Syntheticsチェックを実行する

 

1. パッケージ定義(package.json)を置くためのディレクトリを作成する

任意の場所にパッケージ定義(package.json)を置くためのディレクトリを作成します。ここでは/example-custom-modules-dirとします。このディレクトリ配下にgRPCで必要となる追加のパッケージの定義(package.json)を配置し、コンテナ起動時にマウントします。

 

2. パッケージ定義(package.json)を作成する

API Test用のスクリプトにてgRPC用のパッケージ利用するため、当該パッケージをインストールするためのパッケージ定義(package.json)を作成し、前のステップ#1で作成したディレクトリ(/example-custom-modules-dir)の直下に配置する。package.jsonの中身は以下の通りです。バージョンはその時点で最新のものに合わせてください。本件に限らず、追加のパッケージをインストールする際の構成や手順の詳細はドキュメントを参照してください。

{
    "name": "custom-modules",
    "version": "1.0.0",
    "description": "Custom modules for CPM",
    "dependencies": {
        "grpc": "^1.22.2",
        "@grpc/proto-loader": "^0.5.1"
    }
}

3. New RelicのUIからPrivate Locationを追加し、Location Keyを取得する

New RelicのUIにログインし、Synthetics → Private locations → Create private locationから、Private Locationを作成します。これはSyntheticsのモニターを実行させる場所を表し、今回自分の環境にデプロイするコンテナが関連付けられます。Private Locationを作成した時に付与されるLocation KeyをContainerized Private Minionのデプロイ時に指定することで、Private LocationとでプロいしたContainerized Private Minionが関連付けられます。Syntheticsのモニターの実行場所として、今回作成したPrivate Locationを指定すると、関連付けられたContainerized Private Minionがモニターを実行するという仕組みです。

Private Locationを作成すると、以下のスクリーンショット のようにNRSPから始まるLocation Keyが割り当てられるのでをメモしておきます。まだコンテナイメージをデプロイしていないのでMinionsの数は0になっています。

4. Containerized Private Minionをインストールする

以下のコマンドでContainerized Private Minionをインストールします。今回はDockerを例にしていますが、Kubernetesの場合はドキュメントに記載の方法にしたがってください。<Containerized Private MinionのLocation Key>には前のステップ#3でメモしたLocation Keyを指定します。また、コンテナにマウントするディレクトリとして、ステップ#1で作成した/example-custom-modules-dirを指定しています。ディレクトリが異なる場合は適宜変更してください。

docker run -e MINION_PRIVATE_LOCATION_KEY=<Containerized Private MinionのLocation Key> -v /tmp:/tmp:rw -v /var/run/docker.sock:/var/run/docker.sock:rw -v /example-custom-modules-dir:/var/lib/newrelic/synthetics/modules:rw quay.io/newrelic/synthetics-minion:latest

デプロイがうまくいくと、Containerized Private Minionが認識され以下のスクリーンショット のようにMinionsの数が増えます。これでSyntheticsのモニター定義の中でこのLocationを選んでも問題なく動くようになります。

5. Synthetics API Testのスクリプトを設定する

gRPCを使ったアプリケーションへアクセスするためのスクリプトを定義します。ここでは、gRPCを使ったアプリケーションのインタフェース定義が以下のようになっているとします。

helloworld.proto

syntax = "proto3";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

 

したがい、クライアント側であるSyntheticsのスクリプトは、GreeterサービスのsayHelloというリモートプロシージャを呼び出すものになります。以下がSyntheticsのスクリプトの例です。サーバーサイドのエンドポイントを、host.docker.internal:50051としていますがリモートの場合やポート番号が異なる場合はここを変更すれば大丈夫です。

const assert = require('assert')
const fs = require('fs')
const grpc = require('grpc')
var protoLoader = require('@grpc/proto-loader')

const PROTO_PATH = './helloworld.proto'

const PROTO = 'syntax = "proto3";\
 service Greeter {\
 rpc SayHello (HelloRequest) returns (HelloResponse) {}\
 }\
 message HelloRequest {\
 string name = 1;\
 }\
 message HelloResponse {\
 string message = 1;\
 }'

fs.writeFileSync(PROTO_PATH, PROTO, function (err) {
    assert.ok(!err, "Error writing proto file to file system.")
    console.log("Proto file written")
})

// Read the package definition from the file system.
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofus: true
})

const Greeter = grpc.loadPackageDefinition(packageDefinition).Greeter
// Create a gRPC client that connects to the system hosting our CPM on port 50051 using the NoteService
const client = new Greeter('host.docker.internal:50051', grpc.credentials.createInsecure())
// Create a timer to be used to determine call duration.
var beforeCall = Date.now()
// Execute the list service on the client, check for errors, add duration as a custom attribute, and check for response content.
client.sayHello({ name: 'DataNerd' }, (error, res) => {
    assert.ok(!error, "Error occurred: " + error)
    var now = Date.now()
    var duration = now - beforeCall
    console.log('Duration (ms): ' + duration)
    console.log('Successfully got response')
    console.log(JSON.stringify(res))
})

6. Synthetics チェックを実行する

Syntheticsのモニターを有効にして定期的にチェックが走るようにします。以下のスクリーンショット の通り、無事にエンドポイントへのアクセスができていることを確認できました。チェック結果はデータベースに格納されているため、NRQLを活用して稼働率を可視化したりアラートを設定することが可能になります。

 

以上、gRPCを使ったシステムに対して外形監視で可用性を観測する方法を示しました。今回の例はAPIのエンドポイントの死活監視程度ですが、レスポンスのデータを検証したり、複数のAPIを組み合わせることによってアプリケーションの論理不正も検出することが可能になり、運用時だけでなく、開発や検証フェーズでも効果的にお使いいただけます。是非お試しください。

 

New Relicを試してみたい方はこちらこちらへ。