最近 ngx_mruby をいじり始めて「ビルドできた!」「おぉ、簡単にWebサーバーの振る舞いを変えられる!」ところまでいったので、
何を作ろうかと考えて初めに思いついたのがシャドウプロキシでした。
とはいえシャドウプロキシが何なのかはよくわかっていなかったので予め下記を参考にさせていただきました。
シャドウプロキシサーバーの実装
シャドウプロキシの仕組み
まとめると、
- 本番のリクエストをバックエンド(Shadow環境)に複製することで、本番に限りなく近い状態を再現できる。
- それによって、いきなり本番投入するのが怖い何かを安全に試運転させてバグの検知ができる。
- 心穏やかにリリースに臨める。
mruby-ngx-shadow_proxy
ざっくりした実装しかしていませんが、github で公開しています。
ackintosh/mruby-ngx-shadow_proxy
mruby-ngx-shadow_proxy - HTTP shadow proxy using ngx_mruby.
mrbgem を作るのは初めてだったのですが、mruby-mrbgem-template を使うと必要なディレクトリ構造やファイルを生成してくれるので便利でした。
mrubyの拡張モジュールであるmrbgemのテンプレートを自動で生成するmrbgem作った
試行錯誤
実装を始めた当初は、上記に挙げたサーバーのように ngx_mruby で本番とバックエンドそれぞれに並列にリクエストを複製しようとしたのですが下記理由で別の方法にしました。
- 漠然とした違和感(何か ngx_mruby らしい方法があるのではないか)
- できるだけフロントに手を入れたくない
- そもそも mruby がスレッドセーフではない
- この辺がまだ理解できていないので語弊があるかもしれません
- 参考 https://github.com/mruby/mruby/issues/1657
- 実際に mattn/mruby-thread を使って試行錯誤していたのですがスレッド間のデータのやりとりがうまくできませんでした
なので最終的に、バックエンドにリクエストを複製するだけにしました。
READMEに例を載せていますが、
ngx_mruby にはいろんなディレクティブがあって nginx のフェーズにフックして制御できるようになっているので、
mruby_log_handler というディレクティブを使うことで、クライアントにレスポンスを返した後のフェーズでバックエンドにリクエストを複製するようにしています。