mruby_nginx_module at pyfes 2013.11

Post on 28-May-2015

1.219 views 8 download

Transcript of mruby_nginx_module at pyfes 2013.11

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 ✦ 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