Post on 28-May-2015
自己紹介✦ 久保 達彦(H.N:bokko)
✦ @cubicdaiya(twitter, github) ✦ Senior Software Engineer@pixiv Inc.
✦ インフラチーム所属
✦ ミドルウェアの開発・運用とかやってます
Goはじめました
普段はnginxのモジュールとか作ってます
✦ mruby_nginx_module ✦ Embed mruby into nginx
✦ ngx_small_light ✦ Dynamic Image Transformation for nginx
✦ ngx_access_token ✦ 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, mruby_require
server rewrite serverコンテキストのrewrite
find config 該当するlocationの探索
rewrite mruby_rewrite_handler locationのrewrite
post rewritepre-access !
access mruby_access_handler !
ファイルへのアクセス
post-accesstry files try_files
content mruby_content_handler bodyの生成
log mruby_log_handler ロギング
その他のディレクティブ
mruby_nginx_moduleのディレクティブ 用途
mruby_cache コードキャッシュのOn/Off(default:On)
mruby_set 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が標準で入っていない
✦ 別途mrbgemが必要(例:iij/mruby-regexp-pcre)
✦ PCREベースのmrbgemはnginxに組み込むのが困難
✦ 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
location /mruby { set $maintainer "bokko"; mruby_content_handler_code ' r = Nginx::Request.new maintainer = r.var.maintainer Nginx.rputs(maintainer + "\n") # => bokko '; }
■nginxの変数にアクセス
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
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 # => UTC Time(2013-11-30 xx:xx:xx) Nginx::Time.local_time # => local time(2013-11-30 xx:xx:xx) !http_time = Nginx::Time.http_time(time) Nginx::Time.parse_http_time(http_time) # => 1377710189
■nginxのtime系APIのラッパー
Nginx::Digest
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…
■MD5, SHA1, HMAC-SHA1, etc
Nginx::Base64
encoded = Nginx::Base64.encode("bokko") # => Ym9ra28= Nginx::Base64.decode(encoded) # => bokko
■Base64 encode/decode
少し発展的な例
(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
✦ 約200行
✦ ngx_access_token by C
✦ 約300行
✦ ngx_access_token by mruby
✦ 約10行
スクリプト言語の力ってすごいですね
今後の課題
✦ 共有メモリAPI(Nginx::Shared)
✦ サブリクエストAPI(Nginx::SubRequest)
✦ ノンブロッキングソケットAPI(Nginx::Socket)
✦ Fiber(コルーチン)導入
✦ etc