1. devneko

    No comment

    devneko
Changes in body
Source | HTML | Preview

実現したいこと

Nginxを使ってアプリケーションサーバーのレスポンスをキャッシュしたいケースは多いと思いますが、
厄介なのが認証が必要なケースです。単純にキャッシュしてしまうと認証が回避されてしまいます。
仕方ないので認証が必要なリクエストは毎回アプリケーションサーバに流すとなると、やはりパフォーマンスは下がってしまいます。
なんとか認証をアプリケーションサーバを介さずに実現し、高速な認証つきのキャッシュを実現できないか考えてみました。

仕組み

例えば、リクエストヘッダーなどに認証トークンが付いており、これをMemcachedに問い合わせることで認証をチェックできるというシステムである場合、どうやらNginxの既存のモジュールだけで実現できることがわかりました。
使うのはproxy_cacheの他に下記の2つの標準モジュールです。

  • ngx_http_auth_request_module
  • ngx_http_memcached_module

ngx_http_auth_request_moduleに含まれるauth_requestというディレクティブを使うと、指定したURIのレスポンスが
正常系(2xx)である場合だけリクエストを処理させることができます。
ngx_http_memcached_moduleは、$memcached_key変数に指定したキーの内容をmemcached_passディレクティブで指定した
ホストから取得するといったことができるモジュールです。キーがあればステータス200ですが存在しない場合は404となります。

memcachedの内容を返すURIを用意しておき、auth_requestを使ってそれを認証URIにすれば、認証つきのキャッシュを実現できます。

設定例

前提となる構成と認証

アプリケーションサーバ: 127.0.0.1:8080
Memcachedサーバ: 127.0.0.1:11211
認証:リクエストヘッダX-TOKENに認証用のトークンが設定される。Memcachedサーバには有効な認証トークンだけがキーとして設定されている。

nginx.conf
http {
    proxy_cache_path /var/cache/nginx/cache levels=1 keys_zone=zone:4m inactive=7d max_size=50m;

    upstream backend {
        server 127.0.0.1:8080;
    }

    server {
        location / {
            auth_request /auth;
            proxy_pass http://backend;
            proxy_cache zone;
            proxy_cache_key $scheme$proxy_host$uri$is_args$args;
            proxy_cache_valid  200 1d;
        }
        location /auth {
            set $memcached_key "$http_x_token";
            memcached_pass 127.0.0.1:11211;
        }
    }
}

Memcachedの部分は実際にはDBやRedisへの問い合わせが必要だったり、単なる認証だけでなく複雑なアクセス条件チェックが必要だったり
々なケースがあると思います。その場合、組み込みのLuaを使うか、認証やアクセス条件のチェックを高速に処理する専用のサーバを用意するというのも良い策な気がします。