id:kizashi1122 です。 2020年ももう終わりですね。今年最後のエントリです。今年も色々ありました。
その色々あった中で nginx がらみで面白いことがあったのでシェアします。
弊社サービス Re:lation では Ruby on Rails を採用しており、AWS 上で稼働させています。 フロントには ALB をおいて、nginx をはさみ、unicorn が動いています。nginx は静的ファイルへのアクセスやHTTPのリダイレクト処理、固定ヘッダの追加など静的な処理を任せています。
nginx に任せている処理の中に gzip 圧縮があります。これは動的生成コンテンツも圧縮することができ、特にレスポンスがテキストの場合などは圧縮率が高くなり転送サイズはぐっと小さくなります。
現在はほとんどのサービスで gzip 圧縮が使われてると思います。
HTTP リクエストヘッダ
ブラウザがサポートしている圧縮アルゴリズムがあればリクエストヘッダに以下のように設定されます。 br
というのは、Brotli というアルゴリズムで圧縮率が高いようです。
Accept-Encoding: gzip, deflate, br
HTTP レスポンスヘッダ
そして、圧縮をサポートしているならば、サーバー側は圧縮してもよいので圧縮して送ります。
content-encoding: gzip
圧縮されたレスポンスのヘッダはこんな感じになります。
nginx の設定で gzip 圧縮を有効にしたい場合は設定ファイルにこのような記述をします(最低限)。
gzip on; gzip_types application/json text/plain text/css application/x-javascript text/xml application/xml application/rss+xml text/javascript application/javascript image/x-icon;
text/html
は指定しなくてもデフォで圧縮がかかるようです。
さて
とある環境からどうも遅く感じるという報告があり、パフォーマンスのボトルネックを探ってたときにある状況を発見しました。 (そのとある環境からの問題はまだ解決してないのですが)
レスポンスによっては gzip 圧縮が効いてないようなのです。
そのリクエストは POST
でした。ははーん、 POST
だと効かないのか?
いやそうではないようだ。ちゃんと POST
のレスポンスでも圧縮されている。
なにが違うのか?
調べていった結果、HTTPのステータスコードが 201 (Created) の場合のみ圧縮が効いてないのです。 nginx のソースをみてみます。
https://github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_gzip_filter_module.c#L228-L240
ここに gzip 圧縮フィルタの関数があります。 if 文をみると HTTP_OK (200)
でも NGX_HTTP_FORBIDDEN (403)
でも NGX_HTTP_NOT_FOUND (404)
でもない場合は処理を抜けて次のフィルタ適用の処理に進んでしまうようです。
微妙だ。
解決策としては、ステータスコードを 201
から 200
に変えるだけ。
これで圧縮が効くようになりました。
めでたしめでたし。