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

  • 0
    いいね
  • 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-Idを付与し、それをプロキシ先でも読み取るには以下のような設定になります。
    プロキシ先ではカスタムヘッダーの変数である $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だけでマイクロサービス間のトレースを行うのがお手軽にできるので良いですね。便利!