第1页
ngx_lua
Monkey Zhang (timebug)
2016.07 @ Shenzhen ArchSummit
第3页
A Systems Engineer at UPYUN
Email: timebug.info@gmail.com Github: https://github.com/timebug
第4页
$ ./configure --prefix=/opt/nginx \ --add-module=/path/to/lua-nginx-module
http { server { listen 8080;
location /add { set $res '';
rewrite_by_lua ' local a = tonumber(ngx.var.arg_a) or 0 local b = tonumber(ngx.var.arg_b) or 0 ngx.var.res = a + b
';
content_by_lua ' ngx.say(ngx.var.res)
'; } } }
$ curl 'http://localhost:8080/add?a=6&b=7' 13
第5页
LuaJIT
LuaJIT is a Just-In-Time Compiler (JIT) for the Lua programming language.
第6页
How it works
LuaJIT VM embedded into the Nginx
第7页
cosocket API
ngx.socket.* connect send receive
sslhandshake close settimeout etc.
第8页
UPYUN CDN & API is built on top of
NGINX with ngx_lua
第9页
UPYUN API
第10页
Base64 Filter by Lua
http {
lua_package_path “$prefix/app/src/?.lua;;";
server { listen 8080;
location /base64 { set $b64_en ''; set $b64_e0 ''; set $b64_e1 '';
echo_duplicate 1000 hello;
header_filter_by_lua ' ngx.header.content_length = nil -- ((n + 2) / 3 ) * 4 ngx.header.content_type = "text/plain" ngx.header.content_transfer_encoding = "base64"
';
body_filter_by_lua_file app/src/b64_body_filter.lua; } } }
第11页
Base64 Filter by Lua:
local chunk = ngx.arg[1]
local e0 = ngx.var.b64_e0 or '' local e1 = ngx.var.b64_e1 or '' local en = tonumber(ngx.var.b64_en) or 0
if en == 1 then chunk = e0 .. chunk
elseif en == 2 then chunk = e0 .. e1 .. chunk
end
if not ngx.arg[2] then en = #chunk % 3 if en == 1 then e0 = chunk:sub(-1) elseif en == 2 then e1 = chunk:sub(-1) e0 = chunk:sub(-2, -2) end chunk = chunk:sub(1, #chunk - en)
else -- eof en = 0
end
ngx.var.b64_en = en ngx.var.b64_e0 = e0 ngx.var.b64_e1 = e1
ngx.arg[1] = ngx.encode_base64(chunk)
Chunk by Chunk
第12页
location /upload { proxy_request_buffering off; ...
}
第13页
Lua Streaming Upload
ngx.req.init_body() ngx.req.append_body(chunk) ngx.req.finish_body()
第14页
UPYUN CDN
第15页
CDN
5 ~ 10T
第16页
✦ ✦ ✦ ✦
第17页
access_log /path/to/access.log combined buffer=4096 flush=5s;
✦
✦ Logstash / Heka Agent Input File ✦ NGINX 1.7.1+ Logging to syslog
✦
tail -f
第18页
log_by_lua with cosocket
ngx.timer.at
+ Lua Buffer +
tcp:send to nsqd
_M.nsqd = {
config = { topic = "marco_ngx_log", flush_limit = 32768, -- 32KB drop_limit = 2097152, -- 2MB
},
cluster = { { servers = { { host = "127.0.0.1", port = 3900 }, }, },
}, }
第19页
Nginx Internals: HTTP request phase handlers
✦ POST READ PHASE ✦ SERVER REWRITE PHASE ✦ FIND CONFIG PHASE ✦ REWRITE PHASE ✦ POST REWRITE PHASE ✦ PRE ACCESS PHASE ✦ ACCESS PHASE ✦ POST ACCESS PHASE ✦ TRY FILES PHASE ✦ CONTENT PHASE ✦ LOG PHASE
第20页
nsqd --mem-queue-size
✦
✦ NSQ
nsqd
nsq_to_http ,
第21页
✦
✦
ELK
✦
✦
✦
第22页
Lua Custom Logging:
lua-resty-logger-socket
log_format combined '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';
server { access_log /path/to/access.log combined buffer=4096; ...
}
bucket:hbimg = {"enable":true,"ratio":0.1}
redis slaveof
nsqd -> nsq_to_http
logger.log(cjson.encode(log_msg_table) .. "\n")
UPYUN LOG Edge Server
第23页
UPYUN LOG Platform:
HAProxy + Heka + Kafka + Elasticsearch + Kibana
第24页
✦ show ✦ size ✦ retry ✦ abnormal -
50kb/s
Content-Length
第26页
✦ CDN
✦ ✦
✦ TopN
第27页
130+ Edge Nodes
第28页
ngx_lua
Redis ES
第30页
✦ x-request-id: ce4fc776afd2b74175695d239b67e3ed ✦ via: T.2428.H.1, V.mix-gd-can-007, T.2415.R.1, M.cun-ha-cgo-005 ✦ x-source: C/200
第31页
✦ first_byte_time ✦ client_block_time ✦ prematurely_closed
第32页
DNS
DNS
…
timebug@harmless:~$ http http://img.huaban.com/test.mp4
HTTP/1.1 302 Moved Temporarily Connection: keep-alive Content-Length: 161 Content-Type: text/html Location: http://123.150.200.130/img.huaban.com/test.mp4? _up_sum=a738dc&_up_id=0f8b04a82480906a2a09bfda8d864c84&_up_from=112.21.160.135 Server: marco
112.21.160.135 ->
123.150.200.130
✦ correct_dns_to ✦ correct_dns_from
第33页
UPYUN DevOps
conf hash + project version + upyun.cfg
Ansible Playbook
✦ rsync code and binary ✦ conf template instantiate ✦ kill -HUP `cat /var/run/nginx.pid` (*)
第35页
CDN
第36页
nginx.conf
service
server_name *.b0.upaiyun.com
Custom Domain Binding
valid_referers, allow, deny
expires 7d
ssl_certificate* ssl_stapling*
upstream { server 127.0.0.1 }
max_fails=3 fail_timeout=30s
health_check (*)
round-robin, ip_hash, hash (1.7.2+)
Custom Antileech Rules and Redirect:
ip, user-agent, referer, token etc.
Custom Cache Control:
support specific URI rules etc.
Custom SSL
Custom CDN Origin:
support multi-network routing etc.
Custom Health Check Strategy: passive, active
Custom Load Balancing Strategy
rewrite
Custom URL rewrite
……
第37页
nginx.conf as a service
powered by ngx_lua
第38页
http://io.upyun.com/2015/03/09/hello-world/?foo=bar
[scheme] [host] [path] [query]
第39页
tianchaijz:
"$WHEN($MATCH($_URI, '^/foo/.*'))$ADD_REQ_HEADER(X-Foo, bar)"
Marco: I GOT IT !
Edge Server
第40页
Lua Custom URL rewrite:
lua-resty-rewrite | variables
$_METHOD $_SCHEME
$_HOST $_POST_name
$_SYM_sym
$_HOST_n $_HEADER_name
$_COOKIE_name
$_URI
$_GET_name
$_QUERY
$_RANDOM_n $_RANDOM
第41页
Lua Custom URL rewrite:
lua-resty-rewrite | functions
$ENCODE_BASE64(E)
$ALL(E1, E2, ...) $UPPER(E)
$ANY(E1, E2, ...) $DECODE_BASE64(E) $LOWER(E)
$WHEN(E1, E2, ...)
$SUB(E1, from, to) $PCALL(E) $MATCH(E1, E2)
$GT(E1, E2) $GE(E1, E2) $EQ(E1, E2)
$ADD_REQ_HEADER(E1, E2) $DEL_REQ_HEADER(E1) $ADD_RSP_HEADER(E1, E2)
第42页
Join our team
©2012-2014 Trybiane
第43页
Q&A