人間とウェブの未来

「ウェブの歴史は人類の歴史の繰り返し」という観点から色々勉強しています。

ngx_mruby v1.20.0で動的listener設定をサポートしました

タイトルの通り、ngx_mrubyのhttpモジュールとstreamモジュール両方で、mrubyによる動的Listener設定をサポートしました。

動的Listenerとは、nginxのlistenの設定をmrubyで書いて、起動時に動的に設定を読み込めるようにできる機能です。以下の例を見た方が分かりやすいかと思います。

# $ ulimit -n 60000

worker_processes  1;

events {
    worker_connections  30000;
}

daemon off;
master_process off;
error_log logs/error.log debug;

stream {
  upstream dynamic_server {
    server 127.0.0.1:8080;
  }

  server {
      mruby_stream_server_context_code '
        (20001..30000).each { |port| Nginx::Stream.add_listener({address: port.to_s}) }
      ';

      mruby_stream_code '
        c = Nginx::Stream::Connection.new "dynamic_server"
        c.upstream_server = "127.0.0.1:#{Nginx::Stream::Connection.local_port * 2}"
      ';

      proxy_pass dynamic_server;
  }
}

http {
    server {
        mruby_server_context_handler_code '
          s = Nginx::Server.new
          (20001..30000).each { |port| s.add_listener({address: (port * 2).to_s}) }
        ';

        location /mruby {
          mruby_content_handler_code 'Nginx.rputs "#{Nginx::Connection.new.local_port} sann hello"';
        }
    }
}

このように書くと、nginxのTCPロードバランサが20001ポートから30000ポートまでListenした上で、接続のあったポート番号の数値の2倍のポート番号へTCPプロキシします。さらに、nginxのhttp側では20001ポートから30000ポートの2倍のポート番号でListenし、そのポート番号に応じてhelloを返します。

この設定でnginxを起動すると、これまでlistenディレクティブを沢山並べる必要があり、CRubyとerbなどを使ってプロビジョニング時にゴニョゴニョ書かなければいけなかった処理を、スッキリとmrubyで書くことができるようになります。また、ポート番号をデータベースやホストの状態に合わせていい感じにリッスンするような実装も可能でしょう。

$ netstat -lnpt | grep nginx | wc -l
20000

上記のような設定でcurlでアクセスすると、以下のようにレスポンスが返ってきます。

[ubuntu@ubuntu-xenial:~]$ curl http://127.0.0.1:20001/mruby
40002 sann hello
[ubuntu@ubuntu-xenial:~]$ curl http://127.0.0.1:20002/mruby
40004 sann hello
[ubuntu@ubuntu-xenial:~]$ curl http://127.0.0.1:29999/mruby
59998 sann hello

ふむふむなるほどべんり!

ということで皆様是非ngx_mruby v1.20.0の新機能をご活用ください。

github.com