mruby_nginx_module
∼

久保 達彦	


cubicdaiya@gmail.com	

pyfes 2013/11/30
自己紹介
✦

久保 達彦(H.N:bokko)	


✦

@cubicdaiya(twitter, github)	


✦

Senior Software Engineer@pixiv Inc.	

✦

インフラチーム所属	


✦

ミドルウェアの開発・運用とかやってます
Goはじめました
普段はnginxのモジュールとか作ってます
✦

mruby_nginx_module	

✦

✦

ngx_small_light	

✦

✦

Dynamic Image Transformation for nginx	


ngx_access_token	

✦

✦

Embed mruby into nginx	


Porting of mod_access_token into nginx	


Nginx本体にも2件ほどパッチ送りました
WEB+DBでもnginxの記事を書きました
WEB+DB PRESS Vol.72	

!

□詳解nginx	

!

設定の柔軟性と	

優れたスケーラビリティ	

!

□共著者	

@harukasan	

@semind
nginx in pixiv
✦

リバースプロキシとかキャッシュとかWebDAVとか
色々な箇所で稼働しています	


✦

Using ngx_lua in pixiv	

✦

http://www.slideshare.net/harukayon/ngx-lua-public	


✦

@harukasan++
とあるpixivを支えるインフラエンジニア談
mruby_nginx_module	

∼Embed mruby into nginx∼
mruby_nginx_module
✦

nginxの拡張モジュール	


✦

nginx.confでmrubyが書ける	


✦

nginxのモジュールがmrubyで書ける	


✦

ngx_mrubyからfork at 2013/07	

✦

✦

それまではPull Request送る形で開発に参加してました	


http://git.io/d3sJtw
ngx_mrubyとの違い
✦

(mod|ngx)_mrubyはWebサーバの拡張記述統一が目的の一つ	

✦

✦

✦

Apacheでもnginxでもできる限り同じように書けるのが重要	

機能は極力mrbgemsで実現する方向	


mruby_nginx_moduleはnginxとの親和性を重視	

✦

機能は極力nginxのAPIで実現する方向
ドキュメント	

http://cubicdaiya.github.io/
mruby_nginx_module/
mruby
✦

軽量Ruby	


✦

組み込み分野向けにまつもとゆきひろ氏が開発	


✦

Cと連携しやすいように設計されてる	


✦

個人的にはリッチなLuaというイメージ
Luaから見たmruby
✦

Cとの連携が非常に楽	

✦

✦

Luaのスタック操作に比べるとかなり直感的	


オブジェクト指向機能のサポート	

✦

Luaでもtableで頑張ることはできるがmrubyに
比べると弱い
ngx_luaとmruby_nginx_module
(あるいはngx_mruby)
ngx_lua
✦

ノンブロッキングアーキテクチャ	

✦

nginxやその他拡張モジュールとの親和性が非常に高い	


✦

関連モジュールが豊富(lua-resty-xxx)	


✦

拡張モジュールというかもはやフレームワークの域	


✦

lua-jitと組み合わせたら鬼に金棒	


✦

OpenRestyの中核モジュール
mruby_nginx_module
✦

まだまだ発展途上	

✦

機能とかライブラリとかいろいろ足りてない	


✦

ノンブロッキングなアーキテクチャにするのが当面の課題	


✦

フック関連のディレクティブ群はほぼ同等レベルまで実装済	

✦

mruby_(rewrite|access|content|log)_handler等
今のところ使える機能
✦

コードキャッシュ	


✦

各種ハンドラへのフック(rewrite,access,content,log)	


✦

ヘッダおよびボディのフィルタリング	


✦

nginxの変数へのアクセス(set & get)	


✦

Nginx::(Request|Context|Time|Base64|Digest|etc)	

✦

✦

by Nginx Core API(not mrbgems)	


Regexp(PCREベース)
nginxの実行フェーズとディレクティブ一覧
nginxの処理フェーズ(実行順) mruby_nginx_moduleのディレクティブ

start-up nginx & modules	

 mruby_init,

server rewrite
find config
rewrite
post rewrite
pre-access
access
post-access
try files
content
log

備考

mruby_require
serverコンテキストのrewrite
該当するlocationの探索

mruby_rewrite_handler

locationのrewrite

!

mruby_access_handler	


ファイルへのアクセス

!
try_files

mruby_content_handler	

mruby_log_handler

bodyの生成
ロギング
その他のディレクティブ
mruby_nginx_moduleのディレクティブ

mruby_cache
mruby_set

用途
コードキャッシュのOn/Off(default:On)

mrubyの実行結果をnginxの変数にsetする

mruby_header_filter

HTTPヘッダの内容をフィルタリング or 上書きする

mruby_body_filter

HTTPボディの内容をフィルタリング or 上書きする
Hello, World!
nginxの変数にset

#=> 55
ファイル指定も可能

・先頭に「/」がある場合は絶対パス	

・それ以外の場合は相対パス(conf_prefixがroot)
ヘッダ書き換え

# 本来はtext/html
レスポンスボディも(ry
各処理フェーズでデータ共有
Builtin-Regexp based PCRE
nginxとmrubyとPCRE
✦

nginxは正規表現処理にPCREを利用している	


✦

mrubyには今のところRegexpが標準で入っていない	

✦

✦

PCREベースのmrbgemはnginxに組み込むのが困難	

✦

✦

別途mrbgemが必要(例:iij/mruby-regexp-pcre)	


nginxがpcre_(malloc|free)を上書きしてる	


でもPCREは使いたい
なので、
✦

iij/mruby-regexp-pcreのコードを直接取り込み & 改変	


✦

pcre_(malloc|free)をさらに上書き	

✦

✦

ngx_luaも似たようなことをやってる	


http://bokko.hatenablog.com/entry/2013/10/13/142154
Nginx::Request
■処理中のリクエスト情報にアクセス
location = /mruby {	

mruby_content_handler_code '	

r = Nginx::Request.new	

Nginx.rputs(r.uri
+ "n") # => /mruby	

Nginx.rputs(r.method + "n") # => GET, POST, etc	

Nginx.rputs(r.protocol + "n") # => HTTP/1.x	

';	

}
Nginx::Request
■nginxの変数にアクセス
location /mruby {	

set $maintainer "bokko";	

mruby_content_handler_code '	

r = Nginx::Request.new	

maintainer = r.var.maintainer	

Nginx.rputs(maintainer + "n") # => bokko	

';	

}
Nginx::Headers_in
■リクエストヘッダへのアクセス
hin = Nginx::Headers_in.new	

host = hin["Host"]
# Host header	

agent = hin["User-Agent"] # User-Agent header	

table = hin.headers_in_hash # all headers with hash table
Nginx::Headers_out
■レスポンスヘッダへのアクセス
time = Nginx::Time.time()	

http_time = Nginx::Time.http_time(time + 60 * 60 * 24)	

!

# Expiresヘッダを設定	

hout = Nginx::Headers_out.new	

hout["Expires"] = http_time.to_s
Nginx::Time
■nginxのtime系APIのラッパー
time = Nginx::Time.time # => epoch value	

!

time = 1377710189	

Nginx::Time.http_time(time) # => Wed, 28 Aug 2013 17:16:29 GMT	

Nginx::Time.cookie_time(time) # => Wed, 28-Aug-13 17:16:29 GMT	

!

Nginx::Time.utc_time
Nginx::Time.local_time

# => UTC Time(2013-11-30 xx:xx:xx)	

# => local time(2013-11-30 xx:xx:xx)	


!

http_time = Nginx::Time.http_time(time)	

Nginx::Time.parse_http_time(http_time) # => 1377710189
Nginx::Digest
■MD5, SHA1, HMAC-SHA1, etc
md5 = Nginx::Digest.md5("bokko")	

Nginx::Digest.hexdigest(md5) # => fe9749…	

!

sha1 = Nginx::Digest.sha1("bokko")	

Nginx::Digest.hexdigest(sha1) # => cea3d1…	

!

hmac_sha1 = Nginx::Digest.hmac_sha1("data", "key")	

Nginx::Digest.hexdigest(hmac_sha1) # => 10415…
Nginx::Base64
■Base64 encode/decode
encoded = Nginx::Base64.encode("bokko") # => Ym9ra28=	


Nginx::Base64.decode(encoded)

# => bokko
少し発展的な例
(mod|ngx)_access_token
っぽいアクセス認証
(mod|ngx)_access_token
✦

S3のクエリ文字列認証っぽい機能を提供	

✦

✦

✦

特定のアクセストークンに基づいた認証	

リソースの有効期限設定	


mod_access_token	

✦

✦

livedoor(現LINE)が開発	


ngx_access_token	

✦

@cubicdaiyaが開発
xxx_access_tokenの認証方式
以下のパラメータをリクエストURLに付加する	

!

・AccessKey -> 公開
・Expires

文字列	


-> 有効期限(エポック値)	


・Signature -> シグネチャ	

!

Text = Method + Uri + Expires + AccessKey	

Signature = Base64(HMAC_SHA1(Text, (※) SecretKey))	

!

(※)秘密

文字列(サーバ側で設定)
ngx_access_token
by mruby_nginx_module
(mod|ngx)_access_tokenと比べて、
✦

mod_access_token by C	

✦

✦

ngx_access_token by C	

✦

✦

約200行	


約300行	


ngx_access_token by mruby	

✦

約10行	


スクリプト言語の力ってすごいですね
今後の課題
✦

共有メモリAPI(Nginx::Shared)	


✦

サブリクエストAPI(Nginx::SubRequest)	


✦

ノンブロッキングソケットAPI(Nginx::Socket)	


✦

Fiber(コルーチン)導入	


✦

etc

mruby_nginx_module at pyfes 2013.11