pdf
|<<
<
>
>>|
/
NGINX, Lua, and beyond ☺{{#author|agentzh@gmail.com}}☺ {{#author|Yichun Zhang (@agentzh)}} {{img src="images/cloudflare2.gif" width="141" height="71"}} {{#date|2014.02.25}} ---- ngx_echo ---- {{#kw|echo}} \"hello world\"; {{#kw|echo_after_body}} \"some footer...\"; {{#kw|echo_duplicate}} 1024 \"a\"; {{#kw|echo_sleep}} 1.5; {{#kw|echo_exec}} /foo; {{#kw|echo_location}} /baz; {{#kw|echo_subrequest_async}} DELETE /bar {{#v|$echo_request_method}} ---- ngx_headers_more ---- {{#kw|more_clear_headers}} Server X-Powered-By; {{#kw|more_set_headers}} 'Foo: bar'; {{#kw|more_set_input_headers}} 'User-Agent: curl'; ---- ngx_set_misc ---- {{#kw|set_unescape_uri}} {{#v|$name}} {{#v|$arg_name}}; {{#kw|set_if_empty}} {{#v|$name}} \"anonymous\"; {{#kw|set_random}} {{#v|$rand}} 1 10; {{#kw|set_formatted_local_time}} {{#v|$timestr}} \"%a %b %e %H:%M:%S %Y %Z\"; ---- {{img src="images/nginx-memcached-new.jpg" width="977" height="297"}} ---- {{#kw|location}} = /memc-set { {{#kw|set}} {{#v|$memc_cmd}} set; {{#kw|set}} {{#v|$memc_key}} foo; {{#kw|set}} {{#v|$memc_value}} blah; {{#kw|set}} {{#v|$memc_exptime}} 60; # 60 sec {{#kw|memc_pass}} 127.0.0.1:11211; } ---- Ragel ---- ngx_redis2 ---- {{#kw|location}} = /redis-test { {{#kw|redis2_query}} del key1; {{#kw|redis2_query}} lpush key1 A; {{#kw|redis2_query}} lpush key1 B; {{#kw|redis2_pass}} 127.0.0.1:6379; } ---- {{img src="images/nginx-mysql-new.jpg" width="977" height="421"}} ---- {{#kw|upstream}} mysql_backend { {{#kw|drizzle_server}} 127.0.0.1:3306 dbname=test password=some_pass user=monty protocol={{#c|mysql}}; } {{#kw|server}} { {{#kw|location}} = /mysql { {{#kw|set}} {{#v|$query}} {{#c|'select * from cats'}}; {{#kw|drizzle_query}} {{#v|$query}}; {{#kw|drizzle_pass}} mysql_backend; {{#kw|rds_json}} on; {{#cm|# or rds_csv on}} } ---- libdrizzle ---- {{img src="images/nginx-postgres-new.jpg" width="978" height="310"}} ---- libpq ---- Oracle? OCI? ---- ngx_srcache ---- location /foo { {{#kw|set}} {{#v|$key}} {{#v|$uri$args}}; {{#kw|srcache_fetch}} GET /memc {{#v|$key}}; {{#kw|srcache_store}} PUT /memc {{#v|$key}}; {{#kw|srcache_store_statuses}} 200 301 302; {{#cm|# proxy_pass/fastcgi_pass/drizzle_pass/echo/etc}} } ---- ngx_replace_filter ---- {{#kw|location}} ~ '\.cpp$' { {{#kw|# proxy_pass/fastcgi_pass/root/...}} {{#kw|replace_filter_types}} text/plain; {{#cm|# skip C/C++ string literals:}} {{#kw|replace_filter}} \"'(?:\\\\[^\n]|[^'\n])*'\" {{#v|$&}} g; {{#kw|replace_filter}} '\"(?:\\\\[^\n]|[^\"\n])*\"' {{#v|$&}} g; {{#cm|# remove all those ugly C/C++ comments:}} {{#kw|replace_filter}} '/\*.*?\*/|//[^\n]*' '' g; } ---- {{img src="images/data-chunks-new.jpg" width="976" height="355"}} ---- {{img src="images/fixed-size-buffer.png" width="704" height="256"}} ---- libsregex ---- nginx.conf {{#i|scripting}} ---- ngx_lua ---- {{#kw|init_by_lua}} {{#kw|init_worker_by_lua}} {{#kw|set_by_lua}} {{#kw|rewrite_by_lua}} {{#kw|access_by_lua}} {{#kw|content_by_lua}} {{#kw|header_filter_by_lua}} {{#kw|body_filter_by_lua}} {{#kw|log_by_lua}} ---- \"Light threads\" based on Lua {{#i|coroutines}} ---- {{img src="images/schedule-coroutines-new.jpg" width="977" height="523"}} ---- ngx.location.capture(\"/foo\") ngx.location.capture_multi{ {\"/foo\"}, \"/bar\"} } ---- {{#kw|local}} sock = ngx.socket.tcp() {{#kw|local}} ok, err = sock:connect(\"127.0.0.1\", 1234) {{#kw|local}} bytes, err = sock:send(\"hello\") {{#kw|local}} data, err = sock:receive(\"*l\") ---- {{#kw|local}} sock = ngx.socket.udp() {{#kw|local}} ok, err = sock:setpeer(\"127.0.0.1\", 5432) {{#kw|local}} bytes, err = sock:send(\"my query\") {{#kw|local}} dgram, err = sock:receive() ---- {{#kw|local}} req_body_sock = ngx.req.socket() {{#kw|local}} raw_sock = ngx.req.socket({{#kw|true}}) ---- {{#kw|local}} t = ngx.thread.spawn(func) {{#kw|local}} ok, res = ngx.thread.wait(t) ---- {{#kw|local}} dogs = ngx.shared.dogs dogs:add(\"Tom\", 5) dogs:set(\"Tom\", 7) dogs:incr(\"Tom\", 1) dogs:delete(\"Tom\", 1) ---- {{#kw|local function}} do_job() ... {{#kw|end}} {{#kw|local}} ok, err = ngx.timer.at(1.5, do_job) ---- {{img src="images/nonbuffered-new.jpg" width="977" height="539"}} ---- {{#kw|while true do}} {{#kw|local}} chunk, err = read_data_chunk_from_backend() {{#kw|if not}} chunk {{#kw|then}} {{#cm|-- error and eof handling}} {{#kw|end}} {{#kw|local}} ok, err = ngx.print(chunk) {{#cm|-- handle errors here if any}} {{#kw|local}} ok, err = ngx.flush({{#kw|true}}) {{#cm|-- handle errors here if any}} {{#kw|end}} ---- lua-resty-memcached lua-resty-redis lua-resty-mysql lua-resty-dns lua-resty-upload lua-resty-websocket lua-resty-lock lua-resty-upstream-healthcheck ---- LuaJIT ---- OpenResty ---- CloudFlare Lua {{#x|CDN}} {{img src="images/cloudflare2.gif" width="141" height="71"}} ---- CloudFlare Lua {{#x|WAF}} {{img src="images/cloudflare2.gif" width="141" height="71"}} ---- Testing ---- No-pool patch for NGINX ---- {{img src="images/no-pool-new.jpg" width="977" height="526"}} ---- mockeagain ---- {{img src="images/mockeagain-read-new.jpg" width="711" height="722"}} ---- {{#kw|export}} MOCKEAGAIN={{#c|r}} {{#kw|export}} LD_PRELOAD=/path/to/mockeagain.so {{#cm|# edit nginx.conf to add "env" directives}} {{#cm|# start nginx and test}} ---- {{#cm|# nginx.conf}} {{#kw|env}} MOCKEAGAIN; {{#kw|env}} LD_PRELOAD; ---- Better than the TCP proxy approach ---- {{img src="images/mockeagain-write-new.jpg" width="977" height="359"}} ---- {{#kw|export}} MOCKEAGAIN={{#c|w}} ---- Mocking socket write timeout ---- {{#kw|export}} MOCKEAGAIN={{#c|w}} {{#kw|export}} MOCKEAGAIN_WRITE_TIMEOUT_PATTERN={{#c|'hello world'}} ---- Test::Nginx ---- {{#kw|=== TEST 1: echo hello world}} {{#kw|--- config}} location = /t { echo \"hello world\"; } {{#kw|--- request}} GET /t {{#kw|--- response_body}} hello world ---- {{#kw|--- more_headers}} User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.7.4; U; en) {{#kw|--- stap}} F(ngx_http_core_content_phase) { printf(\"content: opera: %d\n\", $r->headers_in->opera) } {{#kw|--- stap_out}} content: opera: 0 ---- LeakTest: k=10.5 Up-Edges: 52 Stable point: N/A RSS Samples (in KB): 3596 3860 3604 3608 3612 3616 3620 3624 3628 3628 3632 3636 3904 3648 3652 3656 3660 3668 3672 3676 3680 3684 3688 3692 3696 3700 4096 3844 4104 3848 3852 4116 4120 4388 4128 4132 3876 3880 3884 3888 4156 4160 3904 4168 3912 4176 3920 3928 4192 4192 4196 4200 3944 4208 4212 4216 4220 3964 3968 3972 4496 3980 4508 4512 3992 4520 4524 4528 4532 4536 4016 4020 4024 4028 4032 4560 4044 4568 4312 4056 4060 4320 5116 4068 4072 4076 4604 4084 4088 4620 4356 4884 4628 4892 4900 4900 4384 4648 4916 ---- {{img src="images/leak-chart.png" width="900" height="300"}} ---- Test Cluster on Amazon EC2 ---- opsboy ---- {{#v|$}} ./dispatcher -r -t 170 -a 'linux x86_64' {{#x|ngx_lua}} Requires at least {{#c|5}} machines. bucket 1: tl-ngx_lua force=1 (242 min) bucket 2: twv-ngx_lua tw-ngx_lua to-ngx_lua force=1 (160 min) bucket 3: trv-ngx_lua tr-ngx_lua force=1 (125 min) bucket 4: tv-ngx_lua t-ngx_lua force=1 (118 min) bucket 5: thv-ngx_lua th-ngx_lua force=1 (74 min) ---- qa.openresty.org ---- {{img src="images/test-report-new.png" width="978" height="445"}} ---- Online debugging and profiling ---- systemtap ---- {{img src="images/software-stack.jpg" width="704" height="512"}} ---- {{img src="images/how-systemtap-works-new.jpg" width="976" height="488"}} ---- nginx-systemtap-toolkit stapxx (stap++) ---- {{#v|$}} ./ngx-req-distr -c -m `cat /opt/nginx/logs/nginx.pid` Tracing 4394 4395 4396 4397 (/opt/nginx/sbin/nginx)... Hit Ctrl-C to end. ^C worker 4394: 0 reqs, 0 conns worker 4395: 2100 reqs, 21 conns worker 4396: 501 reqs, 6 conns worker 4397: 2100 reqs, 21 conns ---- {{#cm|# show the details of the shm zone named "dogs" }} {{#v|$}} ./ngx-shm -p 15218 -n dogs Tracing 15218 (/opt/nginx/sbin/nginx)... shm zone \"dogs\" owner: ngx_http_lua_shdict total size: 100 KB free pages: 88 KB (22 pages, 1 blocks) 22 microseconds elapsed in the probe. ---- {{#v|$}} ngx-rps.sxx -x 19647 WARNING: Tracing process 19647. Hit Ctrl-C to end. [1376939543] 300 req/sec [1376939544] 235 req/sec [1376939545] 235 req/sec [1376939546] 166 req/sec ---- {{#v|$}} epoll-loop-blocking-distr.sxx -x 19647 --arg time=60 Start tracing 19647... Please wait for 60 seconds. Distribution of epoll loop blocking latencies (in milliseconds) max/avg/min: 1097/0/0 value |-------------------------------------------------- count 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 18471 1 |@@@@@@@@ 3273 2 |@ 473 4 | 119 8 | 67 16 | 51 32 | 35 64 | 20 128 | 23 256 | 9 512 | 2 1024 | 2 2048 | 0 ---- Flame Graphs ---- {{img src="images/my-day-flame-graph2.png" width="806" height="403"}} ---- {{img src="images/perl-vm-test-nginx2.png" width="804" height="280"}} ---- on-CPU Flame Graphs ---- {{img src="images/nginx-waf-on-cpu-new.jpg" width="978" height="523"}} ---- {{img src="images/luajit-fnew.png" width="563" height="369"}} ---- {{img src="images/pcre_compile2.png" width="432" height="358"}} ---- {{img src="images/lua-yield.png" width="259" height="386"}} ---- {{img src="images/kt-on-cpu-new.jpg" width="976" height="314"}} ---- {{img src="images/ktserver-on-cpu-new.jpg" width="976" height="340"}} ---- off-CPU Flame Graphs ---- {{img src="images/nginx-open-off-cpu-new.jpg" width="978" height="536"}} ---- {{img src="images/open-file-cache-off-cpu-new.jpg" width="978" height="536"}} ---- {{img src="images/preempted-nginx-off-cpu-new.jpg" width="977" height="614"}} ---- Memory Leak Flame Graphs ---- {{img src="images/nginx-leaks-new.jpg" width="976" height="314"}} ---- File IO Flame Graphs ---- {{img src="images/vfs-latency-flames-new.jpg" width="976" height="405"}} ---- DWARF debug info format ---- {{img src="images/dwarf-guide-new.jpg" width="899" height="721"}} ---- {{img src="images/light-in-darkness-new.jpg" width="978" height="438"}} ---- nginx-gdb-utils ---- {{#v|(gdb)}} source luajit21.py {{#v|(gdb)}} lvmst current VM state: C code from intperpreted Lua {{#v|(gdb)}} lbt builtin#166 builtin#195 builtin#187 @/home/agentzh/git/lua-resty-core/lib/resty/core/regex.lua:588 content_by_lua:10 ---- {{#v|(gdb)}} source ngx-raw-req.py {{#v|(gdb)}} ngx-raw-req r GET /foo HTTP/1.0 Host: bar.com User-Agent: curl Accept-Encoding: gzip ---- Spider binary data structures in the process space ---- {{img src="images/spider-data-structures-new.jpg" width="977" height="587"}} ---- We are hiring :) ---- ☺ {{#ci|Any questions}}? ☺