non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

libtrusterdでHTTP/2でphpを動かして分かったこと

こんにちは、7月の3連休はつくばエクスプレスに家族で乗り込み、つくばエキスポセンターへ行ってきました。このところ、飛行機に夢中だった長男がロケットに夢中に成り、次男は、慶応大学の開発したメタリックブルーのタイヤのいっぱいある、電気自動車が大変気に入った様子でした。kjunichiです。

style="display:inline-block;width:300px;height:250px"

data-ad-client="ca-pub-6228424931662217"

data-ad-slot="7183996427">

背景

h2oがFastCGIに対応したことにより、PHPが動かせる旨の記事を読み。この時点ではじめてFastCGIの事を知った。

以前よりTrusterdでCGIっぽいことをやろうとしており、これらがつながった。そうかFastCGIなる規格に対応すれば、TrusterdからPHPPerlも動かせそうだと。

やってみた事

rebuildfmのh3oの回FastCGIのことが話題に出て、バイナリベースのプロトコルであることを知った。同時にそこそここのチャレンジが難しそうだとも感想を持った。

cgi-fcgiを使う

公式ページ?にはSDKやドキュメントが置いてあり、色々読み漁ったり、DLした。その結果、SDK付属のcgi-fcgiを使えば、FastCGIベースのスクリプトを動かせる事がわかった。

SCRIPT_NAME=/test.php SCRIPT_FILENAME=./test.php REQUEST_METHOD=GET ./cgi-fcgi -bind -connect 127.0.0.1:9000

分かった事

コマンドラインで動かせたので、mrubyでもすぐ動かせる。

`SCRIPT_NAME=/test.php SCRIPT_FILENAME=./test.php REQUEST_METHOD=GET ./cgi-fcgi -bind -connect 127.0.0.1:9000`

PHPのハローワールドが動かない

mirbで確認してphpからの応答が帰って来たので、早速、trusterd.conf.rbを書いて動かした。が、動かない、nghttpクライアントでしばらく応答待ちとなりエラーとなる。

<?php

phpinfo();

たったこれだけのシンプルなコードなのに。。。

返却する文字列長に着目した

なんとなく、このphpinfo()が返す文字列が長いなーぁとの感想をもち、wcすると、9万バイトあった。

そこで、rputsする文字列長をだんだん長くして、nghttpクライアントがエラーになるか試して。

境界値は65535

ruby力がないのと算数が苦手なので、trusterd.conf.rbを書き直しまくり、65535を境に動かなくなることを突き止めた。だから、この時にtrusterd.conf.rbは内緒。

pipeで取得したファイルデスクリプタの制限

パイプバッファの最大値以上のサイズのバイト列をwrite出来ない。

OSX,Linuxともに64KB。むかしのLinuxではこのパイプバッファの上限をfcntlで変更できていたが、最近のカーネルではサイズ固定の模様。

なんでpipe使っているの

mruby-http2でrubyスクリプトの処理をpipe関数を使い、ファイルデスクリプタを扱うことで、他の静的コンテンツ(ファイルのファイルデスクリプタ)の処理やリバースプロキシ処理?(ソケットのファイルデスクリプタ)とのコードと統一化している模様。

mruby-http2モジュール側で、pipeを開いて、ライブラリ内の構造体を介してこれらのファイルデスクリプタをmrb_yield_argvで実行されるmrubyスクリプトと共有しており、mrubyスクリプトのrputsで書き込みようのファイルデスクリプタをwriteコールすることで、任意のバイト配列を書き込み、mruby-http2モジュール側で読み込み用のファイルデスクリプタをnghttp2ライブラに渡すことで最終的にHTTP/2応答としてクライアントに返してる。

通常はpipe関数は使用直後にforkして、読み書きを別々のプロセスで行っているため、今回のような事象に遭遇することは可能性が低い。

解決に向けて

ということで、65535の壁を超えるコードは出来つつある。次回に続くかも。。

Link

関連記事