ãã®è¨äºã¯ MySQL Casual Advent Calendar 2013 ã® 12 æ¥ç®ã§ãã
ã¿ããªå¤§å¥½ã Nginx + Lua ã§ããããã® Lua ãã MySQL ãå©ããã¨ãªãã¨ãNginx ã ãã§ã¦ã§ãã¢ããªã±ã¼ã·ã§ã³ãæ¸ãã¡ããã¨ãã夢ãåºããã¾ããã
é£ãããã¨ããã¤ã¡ã¼ã¸ãããããããã¾ããããå®ã¯ OpenResty ã使ãã¨ããããªç°å¢ãç°¡åã«ä½ãã¦ãã¾ãã®ã§ãä»æ¥ã¯ãã®æ¹æ³ãç´¹ä»ãã¾ãã
ngx_openresty ã®ã¤ã³ã¹ãã¼ã«
ä»å㯠Ubuntu 12.04 ã§ã®ä¾ã§ãããã»ã¨ãã©åæ§ã®æé 㧠CentOS 6.5 ã§ãåããã¨ã確èªãã¦ãã¾ãã *1
$ sudo apt-get -y install gcc make libpcre3-dev libssl-dev perl5 wget $ sudo apt-get -y install libmysqlclient-dev $ wget http://openresty.org/download/ngx_openresty-1.4.3.3.tar.gz $ cd ngx_openresty-1.4.3.3 $ ./configure --with-luajit && make $ sudo make install
ä¸è¨ã®æé ã§ã /usr/local/openresty/nginx/
以ä¸ã« Nginx ãã¤ã³ã¹ãã¼ã«ããã¾ããããã§ã¤ã³ã¹ãã¼ã«ããã nginx ã«ã¯ããã§ã« Lua ã¢ã¸ã¥ã¼ã«ã lua-resty-mysql ã¢ã¸ã¥ã¼ã«ãå«ã¾ãã¦ããã®ã§ãããã« Nginx + Lua + MySQL ã使ãã¯ããããã¨ãã§ãã¾ãã
ãªãä»åã¯ææã㧠libmysqlclient-dev ããã±ã¼ã¸ã使ã£ã¦ãã¾ãããã«ã¸ã¥ã¢ã«å¢ã®çæ§ã«ãããã¾ãã¦ã¯ç§ä¼ã®ãã«ãããªã³ã¯ãããã¨è¯ãã¨æãã¾ãã
Lua + MySQL ã®ã³ã¼ãä¾
ç°¡åãªã¢ã¯ã»ã¹ã«ã¦ã³ã¿ãä½ã£ã¦ã¿ã¾ãã
/usr/local/openresty/nginx/conf/nginx.conf
ã«ä»¥ä¸ã®ãããªè¨è¿°ã追å ãã¾ãã
location /counter { content_by_lua_file conf/counter.lua; }
/usr/local/openresty/nginx/conf/counter.lua
ã«ä»¥ä¸ã®ãããªã³ã¼ããè¨è¿°ãã¾ãã
-- based on sample code at https://github.com/agentzh/lua-resty-mysql local mysql = require "resty.mysql" local db, err = mysql:new() if not db then ngx.log(ngx.ERR, "failed to instantiate mysql: ", err) return end local ok, err, errno, sqlstate = db:connect{ host = "127.0.0.1", port = 3306, database = "lua", user = "lua", password = "lua", max_packet_size = 1024 * 1024 } if not ok then ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errno, " ", sqlstate) return end res, err, errno, sqlstate = db:query("UPDATE counters SET value = value + 1 WHERE id = 1") if not res then ngx.log(ngx.ERR, "bad result: ", err, ": ", errno, ": ", sqlstate, ".") return end res, err, errno, sqlstate = db:query("SELECT value FROM counters WHERE id = 1") if not res then ngx.log(ngx.ERR, "bad result: ", err, ": ", errno, ": ", sqlstate, ".") return end ngx.say("counter: " .. res[1]["value"]) local ok, err = db:set_keepalive(10000, 100) if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end
MySQL ã®æ¹ã¯ã以ä¸ã®ããã«ã¦ã¼ã¶ã¨ãã¼ãã«ãä½ã£ã¦ããã¾ãããã
GRANT ALL PRIVILEGES ON *.* TO 'lua'@'localhost' IDENTIFIED BY 'lua'; CREATE DATABASE lua; CREATE TABLE lua.counters(id INT PRIMARY KEY AUTO_INCREMENT, value INT NOT NULL); INSERT INTO lua.counters (value) VALUES (0);
Nginx ãèµ·åãã¾ãã
$ sudo /usr/local/openresty/nginx/sbin/nginx
ããã§ã以ä¸ã®ããã« /counter
ã§ã¢ã¯ã»ã¹ã«ã¦ã³ã¿ãåãã¾ãã
$ curl localhost/counter counter: 1 $ curl localhost/counter counter: 2 $ curl localhost/counter counter: 3 $ curl localhost/counter counter: 4
lua-resty-mysql ã® API
ä»åå©ç¨ãã API ãç´¹ä»ãã¾ãããããã¯ã»ãã®ä¸é¨ãªã®ã§ã詳ããã¯ããã¥ã¡ã³ããåç §ãã¦ãã ããã
new
æ°ãã MySQL ã¢ããã¿ãªãã¸ã§ã¯ããçæãã¾ãããã®æç¹ã§ã¯ã¾ã æ¥ç¶ãã¾ããã
local mysql = require "resty.mysql" local db, err = mysql:new()
connect
MySQL ã«æ¥ç¶ãã¾ããå¾è¿°ããã³ãã¯ã·ã§ã³ãã¼ã«ãæ®ã£ã¦ããã°ããã®ã³ãã¯ã·ã§ã³ãåå©ç¨ãããããã§ãã
local ok, err, errno, sqlstate = db:connect{ host = "127.0.0.1", port = 3306, database = "lua", user = "lua", password = "lua", max_packet_size = 1024 * 1024 }
query
SQL ãå®è¡ãã¾ãã
local res, err, errno, sqlstate = db:query("SELECT value FROM counters WHERE id = 1")
Result Set ã¯é åã§è¿ã£ã¦ãã¾ããä¸è¨ã® SELECT ã®çµæããã¯ã以ä¸ã®ããã«ãã¦å¤ãåãåºãã¾ãã
ngx.say("counter: " .. res[1]["value"])
set_keepalive
ã³ãã¯ã·ã§ã³ãã¼ãªã³ã°ã®è¨å®ããã¾ãã
local ok, err = db:set_keepalive(10000, 100)
ãã®ä¾ã§ã¯ã 10,000ms ã§ã¿ã¤ã ã¢ã¦ããåæã« 100 ã³ãã¯ã·ã§ã³ã¾ã§ãã¼ã«ãããã¨ããè¨å®ããã¦ãã¾ãã
ãã¾ã: Docker ã§ãµã³ãã«ãåãã
ä»åã®ãµã³ãã«ããã°ã©ã ãåç¾ã§ãã Dockerfile ãä½ã£ã¦ã¿ã¾ããã以ä¸ã®ãªãã¸ããªã§å ¬éãã¦ãã¾ãã
https://github.com/mirakui/nginx-lua-mysql-example
Docker èªä½ã®ã¤ã³ã¹ãã¼ã«æé ã«ã¤ãã¦ã¯ãå ¬å¼ããã¥ã¡ã³ããåç §ãã¦ãã ããã
Docker ãã¤ã³ã¹ãã¼ã«ããã¦ããã°ã以ä¸ã®ãããªæé ã§ãä»åã®ç°å¢ãåç¾ã§ãã¾ãã
Docker ã¤ã¡ã¼ã¸ã®ä½æ
Dockerfile ããã¤ã¡ã¼ã¸ãä½æãã¾ãã
$ git clone https://github.com/mirakui/nginx-lua-mysql-example.git $ cd nginx-lua-mysql-example $ sudo docker build -t ngx .
Docker ã³ã³ããã®èµ·å
ä½æããã¤ã¡ã¼ã¸ã使ã£ã¦ã³ã³ãããèµ·åãã¾ãã docker ps
ã³ãã³ãã§ã³ã³ããã表示ããã¦ããã°æåã§ãã
$ sudo docker run -d ngx b32680fbc44ee55d309e8377963f9015fcb3e6733f55dc580276c9eff1952ba5 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b32680fbc44e ngx:latest /bin/sh -c /usr/loca 4 seconds ago Up 2 seconds 3306/tcp, 80/tcp angry_heisenberg
ãµã³ãã«ã³ã¼ãã®å®è¡
ç«ã¡ä¸ãã£ã¦ããã³ã³ããã® IP ã¢ãã¬ã¹ã調ã¹ã¦ããããã® IP ã¢ãã¬ã¹ã«å¯¾ã㦠/counter
ãªã¯ã¨ã¹ããçºè¡ãã¦ã¿ãã¨ãã¢ã¯ã»ã¹ã«ã¦ã³ã¿ãåãã¯ãã§ãã
$ sudo docker inspect b32680fbc44e | jq '.[0].NetworkSettings.IPAddress' "172.17.0.17" $ curl 172.17.0.17/counter counter: 1 $ curl 172.17.0.17/counter counter: 2 $ curl 172.17.0.17/counter counter: 3 $ curl 172.17.0.17/counter counter: 4
ãããã«
ãã®ããã« Nginx + Lua + MySQL ã®ç°å¢ã¯ã OpenResty ã使ãã°ã¨ã¦ãç°¡åã«æ§ç¯ã§ãã¾ããä»åã®ãããªæé ãè¦ãã¦ããã°ã isucon ãã isucon çã§å½¹ã«ç«ã¤ããããã¾ããã
ææ¥ 12/13 㯠@meijik ããã§ããã楽ãã¿ã«ã
*1:Mac OSX ã§ã試ããã®ã§ãã pcre ã¾ããã§ã¨ã©ã¼ã«ãªã£ã¦ãã¾ããã¾ã ãã«ãã§ãã¦ãã¾ããâ¦