エンジニアリングや研究開発について思うことをこれまで色々とツイートしたりしてきたが、それを改めて短編エッセイ集のようにまとめて整理し、自分の行動原理や思考を言語化して振り返っていた。以下目次。
続きを読むIMAPサーバのdovecotをmrubyでハックする
上記のエントリで言及していたメールの受信サーバdovecotをmrubyで制御するpluginが概ね完成しましたので紹介します。というのも、一月前ぐらいにはできていたのですがバタバタしておりブログにできていませんでした。
dovecot-mruby-pluginはメール受信のIMAPサーバとして動くdovecotをmrubyで色々制御することができます。今日はその制御の例を幾つか紹介します。
続きを読む僕を育ててくれた技術雑誌 WEB+DB PRESS Vol.100記念
7年前の僕はひとたび外に出ると何者でもないエンジニアでした。会社で周りよりも仕事を覚えてこなすのが少しだけ早い、会社の独自仕様に詳しい、それぐらいだったように思います。
ある日、自分が本屋に行ってふと一冊の技術雑誌を開いた時に、そこに書かれている技術はほとんどわからず、自分の得意分野の技術でさえ、社内でやっていることは当たり前のこととして書かれていた上で、さらにそれを高度に一般化し解決する技術が解説されていました。それを見た時に、自分の技術が単に社内独自の業務を経験的に知っているだけであったことになんとなく気付かされました。
ただ、この雑誌に書いている人は本当にプロフェッショナルな専門家なのだろうとしばらくは思っていたのですが、後に執筆陣も自分と同様に会社で働いているエンジニアであり、何も状況は変わらないことに気づき、その人達の経験に基づく一般化された知識とその応用力、それを可能とする視座の高さに憧れと同時に悔しさを感じたのを今でも覚えています。そしてどうすればこういう記事を技術的にも機会としても書くことができるのだろうかと考えたものでした。
そこからオークションや古本屋でその雑誌の古い号を沢山購入しては暇があったら読んで、自分がいかに視座が低かったか、自分の経験をいかに一般化できていなかったかを反省し、その雑誌を読みながらも、内容を真似しつつ、どうにか自分の学んだ技術を自分の中で整理し、自分なりに一般化しながらおそるおそるブログに記事として書き始めました。
ブログに対するフィードバックや多数の優秀なエンジニアの指摘や共有の中で、少しずつ自分の経験から得た技術を一般化できるようになり、その一般化した基礎を積み重ねていくような技術の習得の仕方を学ぶことができました。WEB+DB PRESSは僕にそのきっかけを与えてくれた上で、さらに成長を促し、常にその見本を見せ続けてくれた雑誌でした。
それから2017年になって、ある日一通のメールが届き、その内容は「100号記念選書 TOPエンジニアを支える1冊」への執筆依頼でした。7年前に出会い、僕のエンジニアとしての取り組み方に多大なる影響を与え、一つの行動指針を示し続けてくれたWEB+DB PRESSは僕の最も思い入れのある技術雑誌です。そして、記念すべきvol.100の記念記事にこうやってお誘い頂けたこと、とても嬉しく思います。同時に、7年前の自分のように、自分のエンジニアとしての生き方や学び方に迷っている人達に、是非ともWEB+DB PRESSを手にとって頂けると良いのではないかと思います。そして、Webに関わるエンジニアの行動指針と成長を促す雑誌になり続けられるように、また、僕が体験したようなサイクルが周り続けるように、自分を育ててくれたWEB+DB PRESSにこれからも何らかの形で協力しつつも恩返しできたら良いなと思っています。
WEB+DB PRESS vol.100おめでとうございます!
発売は 8/24 です!
メール送受信システムを幸せにするべく受信サーバdovecotのmruby拡張を書き始めた
以前、メール送信(SMTP)サーバの振る舞いを制御するために、mrubyで機能拡張できるpmilterというMilterプロトコルベースのミドルウェアを作りました。
その流れで、メール受信(POPやIMAP)サーバの振る舞いも同様に制御することによって、トータルでメール送受信システムの流量制限だけでなく、アクセス制御や不正な認証の検知、DoSのようなアクセスや大量メールの送受信をうまくプログラマブルな設定を書くことによって解決していきたいと思いはじめ、昨日からpmilterだけでなくメール受信サーバの開発にも取り組みはじめました。
それらのメール系ミドルウェアを組み合わせることにより、既に使われているメールの定番ミドルウェア(Postfixやdovecot)はそのままに、平易に導入できて、性能を落とすことなく自由にRubyで拡張ができるようになる基盤を作りたいと考えています。
メールは使いたくないと言われる時代の中でも、やはり今でもメールでのやり取りというのはなかなか避けることができず、極端に言えばWeb以上に、メールが止まったりスパムや不正アクセスがあったり、IPレピュテーションの問題でメールが止まった時には、クレームに繋がったり、サービスの売上低下などに繋がったりと、未だに社会的に影響の大きいプロトコルだと言えるでしょう。
そこで、これからメール受信サーバを弄るならどのミドルウェアかなぁと思ってtwitterで色々聞いていると、dovecotでしょ、という話を沢山頂いたので、昨日と今日でdovecot-mruby-pluginのプロトタイプを作りました。プロトタイプといっても、先ずはビルドシステムとテスト環境を作るところに力をいれて、今後の開発をやりやすくして、概ねプロトタイプが動くような状態を目指しました。後は地道に引き続き機能開発をしていく予定です。
大体READMEの通りですが、以下のようにまずはMRUBYコマンドを作って引数のコードを実行できるようにしました。ドキュメントはほぼなかったので、dovecotの実装を読みながら書いています。
$ telnet 127.0.0.1 6070 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready. 1 login test testPassword 1 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE MRUBY] Logged in 1 MRUBY 3*9 #=> 3*9は27という結果が返ってきている 1 27 (0.001 + 0.000 secs).
引き続き受信サーバの振る舞いをIMAP/POPのセッションレベルから多岐に渡ってmrubyで制御できるように実装していこうと思います。
最終的にはdovecot-mruby-pluginとpmilterを連携させて、その基盤の上にRubyでイケてる振る舞いを実装したメールシステムを作って、メールのシステムが幸せになる時代を見てみたいものです。
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の新機能をご活用ください。
nginxのworkerプロセス数をCPUコア数の倍数で自動的に設定できるモジュールを書いた
nginxはworkerプロセスの数をCPUコア(スレッド)数で決定するworker_processes auto
という便利設定があります。
これが多用されているのは、nginxがノンブロッキングでリクエスト処理を行うため、コンテキストスイッチなどを考慮した場合に、コア数で立ち上げておけば効率よくCPUを使い切れるという前提があるからです。
一方で、例えば僕の用途では、現在画像の処理だったりとか、ngx_mrubyのようにリクエストの過程で一部ブロッキングされるような処理も増えてきているため、コア数以上の値に設定しておいた方が性能を発揮できるような状況も増えてきています。
そうなると、現状、非常に便利な設定であるauto
設定を使えずに静的に数字を設定する必要があり、例えばサーバリプレース時には古いコア数を考慮した値になっていたりして、リプレース後にCPUのコア設定がそのままで性能が出せていないという事故が起きる場合もあります。また、だいたいCPUコア数の2倍ぐらいにしておけば、処理を効率的にさばけることがわかっていても、サーバのコア数に応じてworkerプロセスの値を静的に書き換えないと行けないこともあり面倒でした。
そこで、auto
設定によってコア数を自動で取得した上で、そのコア数の何倍のworker数とするかをルールとして記述できるようにしておけば、サーバのコア数に依存しないworker数を定義できる上に、設定が動的になりメンテナンスしやすくなります。
ということで、論文の解放感から勢いで作りました。
設定はREADMEの通りで、例えばCPUコア数が4の場合は、autoで設定すると4個のworkerプロセスが起動します。そのような状況で、
worker_processes auto; worker_processes_factor 3;
のように設定すると、4コアの3倍の12個のworkerプロセスとして起動するようになります。
是非ご活用ください。
また、倍数だけでなく、autoで取得した値を色々カスタマイズできると良いなとは思っているので、何か案がありましたら是非PRを頂けるとマージします。
Webサーバのベンチマーク結果をレスポンスタイムの時系列データとして計測する簡単な方法
単純に特定のURLに対してミドルウェアの性能を計測したい場合などには、今でもabやwrk、h2loadのようなシナリオベースではないシンプルなベンチマークはとても有用です。
一方で、最近ではgatlingやtsungといった、豊富な機能やリッチな計測結果を取得できるベンチマークソフトウェアも豊富になってきました。
ただ、例えば、単に「Webサーバのベンチマーク結果をレスポンスタイムの時系列データとして計測したい」時に、僕のようなめんどくさがりの人間はcliで適当にオプションを渡して1回の実行でシュシュシュっと取りたいものですが、それができるツールが見当たらず、うーむ、gatlingやtsuningでやるかなぁとおもっていたところ、なんとApache Bench(ab)で簡単にシュシュシュっとできてしまうことに気づいたのでした。
続きを読む