NginxでWebサーバ間をトレースするrequest_id

  • 85
    いいね
  • 0
    コメント

$request_id

Nginx 1.11.0 以降に限りますが、リクエスト毎に発番されるIDの変数として $request_id が追加されたようです。
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_id

この変数を利用することにより、Nginxコアだけでサービス間のトレースを簡単に行うことが可能になります。

シンプルな例

以下のように、$request_idをログに含めるだけでリクエスト毎のIDを記録できます。

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_id"';
    access_log  logs/access.log  main;

    # クライアントにも返しておくと調査が楽ですね
    #add_header X-Request-ID $request_id;

プロキシ先でもリクエストIDを引き継ぎたい

プロキシした先にもrequest_idを渡すことにより、同一リクエストかどうかを判別することが可能になります。
プロキシヘッダにX-Request-Id1 を付与し、それをプロキシ先でも読み取るには以下のような設定になります。
プロキシ先ではカスタムヘッダーの変数である $http_x_request_id を参照しています。

###########################################
# プロキシ元 nginx
###########################################
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_id"';

    access_log  logs/access1.log  main;
    server {
        listen 80;

        location / {
            proxy_pass http://backend/;
            proxy_set_header X-Request-ID $request_id;
        }
    }
}

###########################################
# プロキシ先 nginx
###########################################
http {
    # http_x_request_id を記録する
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$http_x_request_id"';

    access_log  logs/access2.log  main;
    server {
        listen 80;

        location / {
            # ...
        }
    }
}

プロキシ先でもリクエストIDを引き継ぎつつ、設定も共通化したい

ただ、プロキシ元とプロキシ先で設定変えるのは少し面倒ですね。
そこで X-Request-Idが渡ってきたときにはそちらを優先し、なければ $request_idを参照する という処理を共通化してしまえばどの環境でも同一設定かつ、request_idの引き継ぎを行うことができます。

x_request_id.conf
# 独自の $_request_id を定義し、設定する
set $_request_id $request_id;
if ($http_x_request_id) {
    set $_request_id $http_x_request_id;
}
nginx.conf
http {
    # $_request_id を参照する
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$_request_id"';

    server {
    listen 80;
        include ../conf.d/x_request_id.conf;
        access_log logs/access1.log  main;

        # ...
    }
}

動作するフルのconfigはgistに置いてあります。
https://gist.github.com/toritori0318/2dc2b64ff696822b02d202bf1fc2f5b2

上記を実行してみたところ、request_id が問題なく引き継ぎ出来ています!

$ tail -1 logs/access1.log
127.0.0.1 - - [08/Apr/2017:16:13:25 +0000] "GET / HTTP/1.1" 200 44 "-" "curl/7.47.1" "-" "8e77df77bdec1eef154d5f819596cb0e"

$ tail -1 logs/access2.log
127.0.0.1 - - [08/Apr/2017:16:13:25 +0000] "GET /fake HTTP/1.1" 200 44 "-" "curl/7.47.1" "-" "8e77df77bdec1eef154d5f819596cb0e"

Nginxだけでマイクロサービス間のトレースを行うのがお手軽にできるので良いですね。便利!


  1. もちろん、 X-Request-Id は任意なのでサービスごとにお好きなヘッダ名に変えてもOKです