lua-nginx-module ãå°å ¥ãã話 (1) JSON-RPC 2.0 batch requestç·¨
nginxã«luaãçµã¿è¾¼ã openresty/lua-nginx-module · GitHub ã¨ããã®ãé常ã«ä¾¿å©ã§ãåãªãreverse proxyã ã£ãnginxã«ãããããå½¹å²ãæãããããããã«ãªãã¾ãã
nginxã®è¨å®ãåçã«ããããnginxããDBãmecached, redisãªã©ã¸ã®ã¢ã¯ã»ã¹ãå¯è½ã«ãªãã¾ããHTTP requestãçºè¡ãããã¨ããã§ãã¾ãã
ããã«ãããä¾ãã°nginxã®è¨å®ãDBåãããï¼NginxとLuaを用いた動的なリバースプロキシでデプロイを 100 倍速くしたï¼ãã¡ãã£ã¨ããèªè¨¼æ©è½ãå ¥ããããã¢ã¯ã»ã¹ãmemcachedãredisãªã©ã«è¨é²ãã¦æ»æãåçã«å¤å®ãã¦ãããã¯ãããã¨ããnginxã®ã¬ã¤ã¤ã¼ã§è²ããªãã¨ãã§ããããã«ãªãã¾ããï¼ããã¯ã¨ã³ãã®ã¢ããªã±ã¼ã·ã§ã³ã§ãå¿è«åæ§ã®ãã¨ã¯å¯è½ã§ãããå段ã§ãããã¯ã§ããã®ãå¬ããã§ããï¼
ãã¾ãã«ãè²ããªãã¨ãã§ããã®ã§ã極è«ãããã°luaã ãã§ãµã¼ãã¹ã®æ§ç¯ãå¯è½ã§ãããã¯ã¨ã³ãã«ã¢ããªã±ã¼ã·ã§ã³ãç¨æããå¿ è¦ãããªããªãã¾ããèã話ã«ããã¨ãæ§è½ã»é度ãæ±ããããã¢ããã¯ä¼æ¥ã«ã¦ãéããªãã¨ããã ã¨ãæ¬å½ã«nginx+luaã ãã§ãµã¼ãã¹ãæ§ç¯ãã¦ããã¨ãããããããã§ãã(ããããã ã¨ã¯æãã¾ããâ¦)
ãã®è¨äºã§ã¯å¿ç¨ä¾ã®ä¸ã¤ã¨ãã¦ãJSON-RPC 2.0 batch requestã¨ãããã®ãnginx+luaã§å®è£ ã»ã©ã¤ãã©ãªåãã話ããã¾ãã
ç®æ¬¡
- JSON-RPC
- JSON-RPC 2.0 batch request
- batch requestã®ãµã¼ãã¼å®è£
- lua-resty-jsonrpc-batch
- æå¾ã«
JSON-RPC
JSON-RPC ã¯ã¨ã£ã¦ãã·ã³ãã«ãªRPCãããã³ã«ã§ããªã¯ã¨ã¹ããã¬ã¹ãã³ã¹ãå ¨é¨æå®ã®JSONå½¢å¼ã§ããããï¼ã¨ãããã®ã§ããå¤æ°ã®è¨èªã§ãµã¼ãã¼ã»ã¯ã©ã¤ã¢ã³ãå ±ã«å®è£ ãããã¬ã¼ã ã¯ã¼ã¯åãã©ã¤ãã©ãªåããã¦ãã¾ãã
JSON-RPCã§ãããå人çã«ã¯å¤é¨ã«å ¬éããAPIã§ããªãéããURIè¨è¨ãåªçæ§ã¨ãè²ã æ°ã«ããªãã¨ãããªãRestFulãããæ±ãããããªã¼ã¨æã£ã¦ãã¾ãã大æµã®ãã¤ãã£ãã¢ããªã¨ãµã¼ãã¼APIéã®éä¿¡ãªã©ã¯ããã§ååã§ã¯ãªãã§ããããã
以ä¸ããµã³ãã«ã¨ãªãã¾ãã
sample
request
{"jsonrpc": "2.0", "method": "subtract", "params": [5, 2], "id": 1}
response
{"jsonrpc": "2.0", "result": 3, "id": 1}
"subtract"ã¨ããåã®å¼ãç®ããmethodã«2ã¤ãã©ã¡ã¼ã¿ã¼ã渡ãã¦ãã¾ããã¨ã£ã¦ãã·ã³ãã«ã§ããã key "id" ã®æå³ã¯å¾è¿°ãã¾ãã
request
{"jsonrpc": "2.0", "method": "getUser", "params": { "user_id": 1 }, "id": 1}
response
{"jsonrpc": "2.0", "result": {"name": "mosa", "email": "[email protected]"}, "id": 1}
ã¦ã¼ã¶ã¼æ å ±ãåå¾ããAPIã®ä¾ã§ãã
ã©ã¡ããç¹å®ã®methodã«ãã©ã¡ã¼ã¿ã¤ãã§1ã¤ã®åç´ãªãªã¯ã¨ã¹ããéã£ã¦ã1ã¤ã®ã¬ã¹ãã³ã¹ãããã£ã¦ãã¾ãã
ï¼å¾è¿°ã®batch requestã¨åºå¥ãã¦ãããã便å®ä¸ãsingle requestãã¨å¼ã¶ãã¨ã«ãã¾ã)
JSON-RPC 2.0 batch request
JSON-RPC 2.0 ã«ã¯batch requestã¨ããä»æ§ãããã¾ããç°¡åã«ããã¨ãè¤æ°ã®ãªã¯ã¨ã¹ããä¸æ°ã«éã£ã¦ãä¸æ°ã«ã¬ã¹ãã³ã¹ããããããã¨ãããã®ã§ãã以ä¸ããµã³ãã«ã§ãã
request
[ {"jsonrpc": "2.0", "method": "subtract", "params": [5, 2], "id": 1}, {"jsonrpc": "2.0", "method": "getUser", "params": { "user_id": 1 }, "id": 2} ]
response
[ {"jsonrpc": "2.0", "result": 3, "id": 1}, {"jsonrpc": "2.0", "result": {"name": "mosa", "email": "[email protected]"}, "id": 2} ]
JSON Arrayã§éã£ã¦JSON Arrayã§è¿ããã¨ã¦ãã·ã³ãã«ãªãããã³ã«ã§ãã ãã ãä»æ§ä¸ãéã£ãArrayã®é çªéãã«ã¬ã¹ãã³ã¹ã並ã¶ãã¨ã¯ä¿è¨¼ããã¾ããããªã®ã§èå¥åã¨ã㦠"id"ã®keyãclientã¯è¦ãªãã¨ããã¾ããã
batch requestã®ã¡ãªãã
batch requestã¯ã¨ã¦ã便å©ã§ãã è¤æ°ã®APIã®ã¬ã¹ãã³ã¹ããã¨ã«ã¯ã©ã¤ã¢ã³ãã®ç»é¢ãæç»ããããã¨ã¯è¯ãããããã®ébatch requestã§ã¾ã¨ãã¦ãã¾ããã¨ã§ãªã¯ã¨ã¹ãæ°ãæ¸ãããã¨ãã§ãã¾ããï¼ã¾ãã§CSS spriteã®ããã§ããï¼ ã¾ããã¯ã©ã¤ã¢ã³ãã§ã®ã2ã¤ã®APIã®çµæãå¾ ããªãã¨æç»ãã¦ã¯ãããªãããã©ããã®APIããããå ´åã¯å ¨ä½ãã¨ã©ã¼ã«ããªãã¨ãããªãããªã©ã®ãéåæã§ã¯é¢åã ã£ããã³ããªã³ã°ãã·ã³ãã«ã«ãªãã±ã¼ã¹ãããã¾ãã
batch requestå°å ¥åã¯ããªã¯ã¨ã¹ãæ°ãæ¸ããããã«ã1ç»é¢ã«å¿ è¦ãªæ å ±ã¯ã ããã1ã¤ã®APIã§è¿ãããããªè¨è¨ã«ãã¦ãããã¨ãããã¾ããããããAPIã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ãã¯ã©ã¤ã¢ã³ãã®UIå¤æ´ã«å¼ããããã¦å¤æ´ãä½åãªãããããã¨ãè¨è¨çã«é常ã«æ°æã¡æªããã¨ã«ãªã£ã¦ãã¾ãããbatch requestå°å ¥å¾ã¯ãã¯ã©ã¤ã¢ã³ãã§ã©ãæç»ãããããã¯ãã¾ãæ°ã«ãããã¨ãªãããªã½ã¼ã¹åä½ã§APIã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ã決ãããã¨ãã§ããããã«ãªãã¾ããã
batch requestã®ãã¡ãªãã
éãå¦çã«å¼ããããã¦ãã¾ãã¾ããã¤ã¾ããå¦çã«10ç§ããããªã¯ã¨ã¹ãAã¨ã1ç§ããããªã¯ã¨ã¹ãBã®2ã¤ãbatch requestã«ããå ´åãA, Bã®ã¬ã¹ãã³ã¹ããããããã«æä½10ç§ããããã¨ã«ãªãã¾ãã(â»ãµã¼ãã¼ã®å®è£ 次第ã§ã¯11ç§ã§ã)
ã§ãã®ã§ãéãmethodãå©ãå ´åã¯æ³¨æããå¿ è¦ãããã¾ãã
batch requestã®ãµã¼ãã¼å®è£
ããã ã便å©ãªbatch requestãã©ãå®è£ ããã®ãè¯ãã§ããããã 以ä¸ãJSON-RPC APIããµã¼ãã¼ã«ç«ã¦ãnginxãéãã¦HTTPéä¿¡ã§å©ç¨ãããã¨ãèãã¾ãã
å®è£ 1. ãã¬ã¼ã ã¯ã¼ã¯å´ã§è¡ã
æ¢åã®JSON-RPC 2.0ã®ãµã¼ãã¼ãã¬ã¼ã ã¯ã¼ã¯å®è£ ãã¿ãã¨ã対å¿ãã¦ããªããã®ãå¤ãã対å¿ãã¦ãã¦ã以ä¸ã®ãããªåç´ãªå®è£ ãè¦ããã¾ããã
- ãªã¯ã¨ã¹ãã§æ¥ãJSONãdecodeãã
- Arrayã§ã¯ãªãã£ããé常ã®ãªã¯ã¨ã¹ãã¨ãã¦å¦çãã
- Arrayã®å ´å(batch request)ãfor loop ã§ããããé çªã«å¦çããå ¨ã¦çµãã£ããã¾ã¨ãã¦ã¬ã¹ãã³ã¹ãçæãã
ãã®å ´åãã¨ã¦ãã·ã³ãã«ã§ã¯ããã¾ããã10ååã®batch requestãæãããå¦çã«10åæéãããããã¨ã«ãªãã¾ããããã¾ãã¤ã±ã¦ãã¨ã¯ããã¾ããã並åã«ããããã®ããã»ã¹ï¼ã¹ã¬ããï¼ãå¦çãã¦ãããã®ãçæ³ã§ãã for loopã§ã¯ãªã並åã§å¦çããã°è¯ãã®ã§ãããè¨èªã«ãã£ã¦ã¯è¤éãªå®è£ ã«ãªãã§ãããã
å®è£ 2. proxy serverããã¦ã
ä¸è¨ã®1-3ã®å¦çãããã ãã®proxy ã³ã³ãã¼ãã³ããç«ã¦ãã®ã¯ãå¦çã並ååããæ¹æ³ã®1ã¤ã§ãããã batch requestã¯ã¾ãproxyãå¦çãããã¨ã«ããproxyãJSON Arrayã®ããããã«å¯¾ããéåæã§ä¸¦åã«ããã¯ã¨ã³ãã®JSON-RPCãµã¼ãã¼ã«ãªã¯ã¨ã¹ããæããå ¨ã¦è¿ã£ã¦ããã1ã¤ã«ã¾ã¨ãã¦ã¬ã¹ãã³ã¹ãçæããå½¢ã§ãã nodeãªã©ã§æ¸ãã°ããããã·ã³ãã«ãªå®è£ ã«ãªãã§ãããã
ããã管çã³ã³ãã¼ãã³ããå¢ãããã¨ã«ãªããä¸æããã client => nginx1 => proxy => nginx2 => app ã®çµè·¯ã辿ããã¨ã«ãªããéç¨ã®è¤éãã¯å¢ãã§ããããç°å¸¸ãèµ·ããå ´åãã©ã®çµè·¯ã§æ»ãã ã®ãå¤æ°ã®ãã°ãæ¼ããã¨ã«ãªãã¾ããproxy serverã®å°æ°ç®¡çãèããªãã¨ããã¾ããã
ï¼ãªãéã«nginx2ãå¿ è¦ãã¯ãè¤éã§ãã以ä¸ã®çç±ã«ããã¾ããã¾ããsingle requestã®å ´åã¯proxyãæã¾ãªã client => nginx2 => app ã®çµè·¯ã«ããã¨ãã¾ãããã®ã¨ãbatch request㧠proxy => app ã®çµè·¯ã«ãã¦ãã¾ãã¨ãappã¸ã®reverse proxyè¨å®ãnginx2ã¨proxyã§äºé管çãããã¨ã«ãªãã¾ããproxy => nginx2 => app ã¨ããã°äºé管çãé²ããã¨ãã§ãã¾ãï¼
å®è£ 3. nginxã§è¡ã
ã¨ãã訳ã§ä»åææ¡ãããã®ããnginx-lua-moduleãç¨ãã¦nginxã§å¦çãããå½¢ã§ãã nginx => app ã®çµè·¯ã¯ãã®ã¾ã¾ã§ãnginxã®ã¬ã¤ã¤ã¼ã§batch requestã¯ãã©ãã¡ããããã¨ãããã®ã§ããåé ã®proxy server ã®å½¹å²ãluaãæ å½ãããã¨ã«ãªãã¾ãã
backendã®JSON-RPC APIã¯single requestããæããã°è¯ãããµã¼ãã¼è¨èªã«ä¾ãããã®æ§æãåããã¨ãã§ãã管çã³ã³ãã¼ãã³ããå¢ããªãã®ãã¡ãªããã§ãã
ã¤ãã³ãããªãã³ãªnginxã®æ§è³ªãæ´»ããããã³ããããã³ã°ï¼ï¼backendã®å¦çãå¾ ããªãã¦ãã)ã§ä¸¦åãªbatch requestãç°¡åã«å®è£ ãããã¨ãã§ããã®ããã¤ã³ãã§ãã
nginx-lua-moduleã«ã¯localtion.capture
ã¨ããæ©è½ããããnginxå
ã§ãã³ããããã³ã°ãªå
é¨ãªã¯ã¨ã¹ã(subrequest)ãçºè¡ãããã¨ãç°¡åã«ã§ãã¾ããã¾ããlocation.capture_multi
ã§ã¯è¤æ°ã®subrequestã並åã§æãããã¾ãããããç¨ãã¦ãsingle requestãæããlocationã¸ä¸¦åã«subrequestãçºè¡ãããã¨ã§ãç°¡åã«batch requestãå®è£
ãããã¨ãã§ãã¾ãã
ï¼ã¾ããå
é¨ãªã¯ã¨ã¹ããªã®ã§ãsingle requestã®reverse proxyè¨å®ã¯ãã®ã¾ã¾æµç¨ãããã¨ãã§ããåè¿°ããäºé管çåé¡ãããã¾ããï¼
ããããããã¨ãæ¸ãã¾ããããä»åbatch requestã«å¿ è¦ãªæ©è½ãluaã®ã©ã¤ãã©ãªåããããããããç¨ããã ãã§ç°¡åã«ä½¿ããã¨ãã§ãã¾ãã
lua-resty-jsonrpc-batch
ã¨ãã訳ã§ä»¥ä¸ã¯ã©ã¤ãã©ãªã®ç´¹ä»ã§ãã
使ãæ¹
以ä¸ã®ãããªè¨å®ãnginxã«æ¸ãã ãã§ãbatch requestã並åã«ããã³ããããã³ã°ã«å®è£ ã§ãã¾ãã
server { location /jsonrpc { # jsonrpc single request endpoint } location /jsonrpc/batch { lua_need_request_body on; content_by_lua ' local jsonrpc_batch = require "resty.jsonrpc.batch" client = jsonrpc_batch:new() local res, err = client:batch_request({ path = "/jsonrpc", request = ngx.var.request_body, }) if err then ngx.exit(500) end ngx.say(res) '; } }
/jsonrpc
ã¯jsonrpcã®single requestãå¦çã§ããendpointã¨ãã¾ãã
/jsonrpc/batch
ã®ã¨ã³ããã¤ã³ãã¯ãrequest bodyã«JSON Arrayãæ¥ãå ´åã¯ããã©ãã¦ä¸¦åã« /jsonrpc
ã®ã¨ã³ããã¤ã³ãã«subrequestãæãã¾ãã
ã·ã³ãã«ã§ããï¼
以ä¸ã¯ããå°ãåã£ã使ãæ¹ãããã人ã®ããã®ä¾ã§ãã
http { init_by_lua ' local jsonrpc_batch = require "resty.jsonrpc.batch" client = jsonrpc_batch.new({ -- ããããªã¯ã¨ã¹ãã®Array sizeã®å¶é max_batch_array_size = 10, -- ããã¯ã¨ã³ãã®å¦çæéããã®ã³ã°ããããã«nginxå¤æ°ã«å ¥ãã before_subrequest = function(self, ctx, req) ctx.start_at = ngx.now() end, after_subrequest = function(self, ctx, resps, req) ngx.var.jsonrpc_upstream_response_time = ngx.now() - ctx.start_at end, }) '; server { set $jsonrpc_upstream_response_time -; location ~ /jsonrpc/method/.* { # jsonrpc endpoint } location /jsonrpc/batch { lua_need_request_body on; content_by_lua ' local res, err = client:batch_request({ -- ãªã¯ã¨ã¹ããã¨ã«endpointãåçã«é¸æã§ãã path = function(self, ctx, req) return "/jsonrpc/method/" .. req.method end, request = ngx.var.request_body, }); if err then ngx.log(ngx.CRIT, err); ngx.exit(500); end ngx.say(res); '; } } }
ãã®ä¾ã¯ä»¥ä¸ã®ãããªæ©è½ãå®è£ ãã¦ãã¾ãã
- lua-resty-jsonrpc-batch ãªãã¸ã§ã¯ãããªã¯ã¨ã¹ãã®ãã³ã«ä½ãã®ã¯é¦¬é¹¿ãããã®ã§ãnginxã®initæã«ä½ãããã«ãã¦ãã
- ã§ããArrayãæ¥ãã¨æ»æã«ãªãã®ã§ãæ大ãµã¤ãºã10ã¨ãã¦ãã
- subrequestã®å¦çæéãnginx access logã«å
¥ããããã«ãnginxå¤æ°ã«å¤ãå
¥ãã¦ãã
- before_subrequest, after_subrequestã®ããã¯ãã¤ã³ããå©ç¨ãã¦ãã
- ãjsonrpc "substract" methodã¯
/jsonrpc/method/substract
ã®ãã¹ã§åãããããªã©ãåçãªlocationã«å¯¾å¿ãã¦ãã
ãã®ä¾ã§ãããããã«ãlua-resty-jsonrpc-batchã«ã¯ããã®ã³ã°ãããããããã®ããã¯ãã¤ã³ããããã¤ãç¨æãã¦ãã¾ãã ã¨ã¯ããæ¬è³ªã¯nginxã®subrequestãå©ç¨ãã¦ããã ããªã®ã§é常ã«ã·ã³ãã«ã§ãã 詳ããã¯mosasiru/lua-resty-jsonrpc-batch · GitHubãã覧ãã ããã
ã¤ã³ã¹ãã¼ã«æ¹æ³
ã¾ãã¯nginx-lua-moduleãnginxã«å ¥ããªãã¨ããã¾ããã ã¤ã³ã¹ãã¼ã«æ¹æ³ã¯Lua | NGINX ã«ããã¾ãããæ¸ãã¦ããéãopenresty (luaããè²ã ã¯ãã£ãæ¡å¼µçnginx)ã使ããã¨ãå¼·ãæ¨å¥¨ããã¦ãã¾ãã
macãªãã°brewã§ç°¡åã«è©¦ããã¨ãã§ãã¾ãã
brew install ngx_openresty
èªåã§ãã«ãããå ´åã¯ä»¥ä¸ã§ãã
curl -O http://openresty.org/download/ngx_openresty-1.9.3.1.tar.gz tar xzvf ngx_openresty-1.9.3.1.tar.gz cd ngx_openresty-1.9.3.1/ ./configure make make install
lua-resty-jsonrpc-batchã®ã¤ã³ã¹ãã¼ã«æ¹æ³ã¯ã以ä¸ã®2éãã§ãã
(1) lua-rocksã§å ¥ãã
luarocks --local install lua-resty-jsonrpc-batch
(2)ãã¡ã¤ã«ãèªã¿è¾¼ã
ãããã¯lua-resty-jsonrpc-batchãcloneãã¦ãlibãã£ã¬ã¯ããªãé©å½ãªã¨ããã«ããã以ä¸ã®ããã«lua_package_pathãæå®ãããã¨ã§ã©ã¤ãã©ãªãèªã¿è¾¼ããã¨ãã§ãã¾ãã
http { lua_package_path '/hogehoge/lua-resty-jsonrpc-batch/lib/?.lua;;';
æå¾ã«
é·ã ã¨ç´¹ä»ãã¦ãã¾ããããã¾ã¨ããã¨ã以ä¸ã®3ç¹ã«ãªãã¾ãã
- jsonrpc 便å©ï¼ batch requestã便å©ï¼
- batch requestã«ã¯è²ããªãµã¼ãã¼å®è£ ãèãããããã©ãnginx + luaã§ããã¨è¯ãããï¼
- lua-resty-jsonrpc-batch ã£ã¦ããã©ã¤ãã©ãªä½ã£ããã使ã£ã¦ã
ã§ãã
lua-resty-jsonrpc-batchã¯ã¾ã è²ã ãããä½å°ãããã¨æãã®ã§ãã©ãã©ãå©ç¨ãã¦ããã ããã¨ãããããã§ãã
æå¾ã«ãnginx + luaã«ã¯æ¬å½ã«ãã¡ãªããã¯ãªãã®ã§ããããï¼å®éç¨ã«èããããã¢ã¸ã¥ã¼ã«ãªã®ã§ããããï¼ããã©ã¼ãã³ã¹ã¯ï¼ãªã©ã®çåãæ®ãã¾ãã ãããã¯ãå®éã«æè¡èª¿æ»ãããéç¨ãã¦å°é·ãè¸ãã çµæãã¾ã¨ãã¦ã次åã®è¨äºã«ãããã¨æãã¾ãã å ã«çµè«ã ãããã¨ãå°ãæ°ãã¤ããã¨ããã¯ãããã©æ®éã«ä½¿ãããï¼ï¼ã§ãï¼