The state of the art of nginx.conf scripting The state of the art of - - PowerPoint PPT Presentation

the state of the art of nginx conf scripting the state of
SMART_READER_LITE
LIVE PREVIEW

The state of the art of nginx.conf scripting The state of the art of - - PowerPoint PPT Presentation

The state of the art of nginx.conf scripting The state of the art of nginx.conf scripting agentzh@gmail.com (agentzh) 2010.10 $ nginx -c /path/to/nginx.conf $ ps aux | grep nginx root 2003 0.0 0.0 25208 412 ? Ss 10:08


slide-1
SLIDE 1

The state of the art of nginx.conf scripting

slide-2
SLIDE 2

The state of the art of nginx.conf scripting ☺agentzh@gmail.com☺

章亦春 (agentzh)

2010.10

slide-3
SLIDE 3

$ nginx -c /path/to/nginx.conf

slide-4
SLIDE 4

$ ps aux | grep nginx root 2003 0.0 0.0 25208 412 ? Ss 10:08 0:00 nginx: master process nginx nobody 2004 0.0 0.0 25608 1044 ? S 10:08 0:00 nginx: worker process nobody 2005 0.0 0.0 25608 1044 ? S 10:08 0:00 nginx: worker process

slide-5
SLIDE 5

# nginx.conf worker_processes 2; events { worker_connections 1024; } http { ... server { listen 80; server_name localhost; ... location / { root /var/www; index index.html index.htm; } } }

slide-6
SLIDE 6

♡ Hello World on the nginx land

slide-7
SLIDE 7

# enable the ngx_echo module in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/echo-nginx-module
slide-8
SLIDE 8

location = '/hello' { echo "hello, world!"; }

slide-9
SLIDE 9

$ curl 'http://localhost/hello' hello, world!

slide-10
SLIDE 10

# enable the ngx_set_misc module and # Marcus Clyne's ngx_devel_kit in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/echo-nginx-module \
  • -add-module=/path/to/ngx_devel_kit \
  • -add-module=/path/to/set-misc-nginx-module
slide-11
SLIDE 11

location = '/hello' { set_unescape_uri $person $arg_person; set_if_empty $person 'anonymous'; echo "hello, $person!"; }

slide-12
SLIDE 12

$ curl 'http://localhost/hello?person=agentzh' hello, agentzh! $ curl 'http://localhost/hello' hello, anonymous!

slide-13
SLIDE 13

♡ Using subrequests to do mashup

slide-14
SLIDE 14

location = '/merge' { echo '['; echo_location_async /moon; echo ','; echo_location_async /earth; echo ']'; } location /moon { echo '"moon"'; } location /earth { echo '"earth"'; }

slide-15
SLIDE 15

$ curl 'http://localhost/merge' [ "moon" , "earth" ]

slide-16
SLIDE 16

# (not quite) REST interface to our memcached server # at 127.0.0.1:11211 location = /memc { set $memc_cmd $arg_cmd; set $memc_key $arg_key; set $memc_value $arg_val; set $memc_exptime $arg_exptime; memc_pass 127.0.0.1:11211; }

slide-17
SLIDE 17

$ curl 'http://localhost/memc?cmd=flush_all'; OK $ curl 'http://localhost/memc?cmd=replace&key=foo&val=FOO'; NOT_STORED

slide-18
SLIDE 18

$ curl 'http://localhost/memc?cmd=add&key=foo&val=Bar&exptime=60'; STORED $ curl 'http://localhost/memc?cmd=replace&key=foo&val=Foo'; STORED $ curl 'http://localhost/memc?cmd=set&key=foo&val=Hello'; STORED

slide-19
SLIDE 19

$ curl 'http://localhost/memc?cmd=get&key=foo'; Hello $ curl 'http://localhost/memc?cmd=delete&key=foo'; DELETED

slide-20
SLIDE 20

♡ Memcached connection pool support

slide-21
SLIDE 21

# enable Maxim Dounin's ngx_http_upstream_keepalive module # in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/echo-nginx-module \
  • -add-module=/path/to/memc-nginx-module \
  • -add-module=/path/to/ngx_http_upstream_keepalive
slide-22
SLIDE 22

http { ... upstream my_memc_backend { server 127.0.0.1:11211; # a connection pool that can cache # up to 1024 connections keepalive 1024 single; } ... }

slide-23
SLIDE 23

location = /memc { ... memc_pass my_memc_backend; }

slide-24
SLIDE 24

♡ Memcached server hashing based on user keys (Hey, memcached cluster!)

slide-25
SLIDE 25

# enable the ngx_set_misc module and Marcus Clyne's # ngx_devel_kit again in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/memc-nginx-module \
  • -add-module=/path/to/ngx_devel_kit \
  • -add-module=/path/to/set-misc-nginx-module
slide-26
SLIDE 26

http { upstream A { server 10.32.110.5:11211; } upstream B { server 10.32.110.16:11211; } upstream C { server 10.32.110.27:11211; } upstream_list my_cluster A B C; ... }

slide-27
SLIDE 27

location = /memc { set $memc_cmd $arg_cmd; set $memc_key $arg_key; set $memc_value $arg_val; set $memc_exptime $arg_exptime; # hashing the $arg_key to an upstream backend # in the my_cluster upstream list, and set $backend: set_hashed_upstream $backend my_cluster $arg_key; # pass $backend to memc_pass: memc_pass $backend; }

slide-28
SLIDE 28

♡ Some non-blocking MySQL love

slide-29
SLIDE 29

# install libdrizzle first and then # enable the ngx_drizzle and ngx_rds_json # modules in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/drizzle-nginx-module \
  • -add-module=/path/to/rds-json-nginx-module
slide-30
SLIDE 30

http { upstream my_mysql_backend { drizzle_server 127.0.0.1:3306 dbname=test password=some_pass user=monty protocol=mysql; } ... }

slide-31
SLIDE 31

location = /cats { drizzle_query 'select * from cats'; drizzle_pass my_mysql_backend; rds_json on; }

slide-32
SLIDE 32

$ curl 'http://localhost/cats' [{"name":"Jerry","age":1},{"name":"Tom","age":3}]

slide-33
SLIDE 33

♡ mysql connection pool support

slide-34
SLIDE 34

http { upstream my_mysql_backend { drizzle_server 127.0.0.1:3306 dbname=test password=some_pass user=monty protocol=mysql; # a connection pool that can cache up to # 200 mysql TCP connections drizzle_keepalive max=200 overflow=reject; } ... }

slide-35
SLIDE 35

♡ Mysql cluster hashing love

slide-36
SLIDE 36

# re-enable the ngx_set_misc module and Marcus Clyne's # ngx_devel_kit in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/drizzle-nginx-module \
  • -add-module=/path/to/rds-json-nginx-module \
  • -add-module=/path/to/ngx_devel_kit \
  • -add-module=/path/to/set-misc-nginx-module
slide-37
SLIDE 37

http { upstream A { drizzle_server ...; } upstream B { drizzle_server ...; } upstream C { drizzle_server ...; } upstream_list my_cluster A B C; ... }

slide-38
SLIDE 38

location ~ '^/cat/(.*)' { set $name $1; set_quote_sql_str $quoted_name $name; drizzle_query "select * from cats where name=$quoted_name"; set_hashed_upstream $backend my_cluster $name; drizzle_pass $backend; rds_json on; }

slide-39
SLIDE 39

♡ ngx_postgres has already landed. Thanks Piotr Sikora! http://github.com/FRiCKLE/ngx_postgres

slide-40
SLIDE 40

# configure the PostgreSQL upstream backend upstream my_pg_backend { postgres_server 10.62.136.3:5432 dbname=test user=someone password=123456; }

slide-41
SLIDE 41

location /cats { postgres_query 'select * from cats'; postgres_pass my_pg_backend; rds_json on; }

slide-42
SLIDE 42

$ curl 'localhost/cats' [{"name":"Marry","age":32},{"name":"Bob","age":12}]

slide-43
SLIDE 43

♡ Everything is also non-blocking as ngx_drizzle. Thanks to libpq's nonblocking API!

slide-44
SLIDE 44

♡ Construct fully RESTful queries in a single location

slide-45
SLIDE 45

location ~ '^/cat/(\d+)' { set $id $1; set_form_input $name; set_quote_sql_str $quoted_name $name; postgres_query GET "select * from cats where id=$id"; postgres_query DELETE "delete from cats where id=$id"; postgres_query POST "insert into cats (id, name) values($id, $quoted_name)"; postgres_pass my_pg_backend; }

slide-46
SLIDE 46

♡ Qunar.com is running ngx_postgres + ngx_rds_json in production. Thanks Liseen Wan's promotion!

slide-47
SLIDE 47
slide-48
SLIDE 48
slide-49
SLIDE 49

♡ Caching database responses using memcached via ngx_srcache and ngx_memc. http://github.com/agentzh/srcache-nginx-module

slide-50
SLIDE 50

# enable the ngx_srcache and other # modules in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/srcache-nginx-module \
  • -add-module=/path/to/rds-json-nginx-module \
  • -add-module=/path/to/memc-nginx-module \
  • -add-module=/path/to/drizzle-nginx-module
slide-51
SLIDE 51

♡ It's very important to put ngx_srcache before ngx_rds_json during nginx configure so that we cache the final JSON rather than RDS.

slide-52
SLIDE 52

# configure the mysql upstream backend upstream mysql_backend { drizzle_server 127.0.0.1:3306 dbname=test password=some_pass user=monty protocol=mysql; }

slide-53
SLIDE 53

# configure the cache storage location location /memc { internal; set $memc_key $query_string; set $memc_exptime 300; memc_pass 127.0.0.1:11211; }

slide-54
SLIDE 54

location /cats { srcache_fetch GET /memc $uri; srcache_store PUT /memc $uri; default_type application/json; drizzle_pass mysql_backend; drizzle_query 'select * from cats'; rds_json on; }

slide-55
SLIDE 55

$ curl 'localhost/cats' [{"name":"Marry","age":32},{"name":"Bob","age":12}]

slide-56
SLIDE 56

# if it is a cache miss $ memcached -vvv -p 11211 ... <10 new client connection <10 get /cats > NOT FOUND /cats >10 END <10 connection closed. <10 new client connection <10 set /cats 0 300 44 > NOT FOUND /cats >10 STORED <10 connection closed.

slide-57
SLIDE 57

# if it is a cache hit $ memcached -vvv -p 11211 ... <10 new client connection <10 get /cats > FOUND KEY /cats >10 sending key /cats >10 END <10 connection closed.

slide-58
SLIDE 58

♡ ngx_lua is quite usable now! http://github.com/chaoslawful/lua-nginx-module

slide-59
SLIDE 59

♡ chaoslawful is crazy!

slide-60
SLIDE 60

# first install lua (or even luajit) into your system... # enable the ngx_lua module in your nginx build $ ./configure --prefix=/opt/nginx \

  • -add-module=/path/to/ngx_devel_kit \
  • -add-module=/path/to/echo-nginx-module \
  • -add-module=/path/to/lua-nginx-module
slide-61
SLIDE 61

location = /adder { set_by_lua $res "local a = tonumber(ngx.arg[1]) local b = tonumber(ngx.arg[2]) return a + b" $arg_a $arg_b; echo $res; }

slide-62
SLIDE 62

$ curl 'localhost/adder?a=25&b=75' 100

slide-63
SLIDE 63

location = /fib { set_by_lua $res " function fib(n) if n > 2 then return fib(n-1) + fib(n-2) else return 1 end end local num = tonumber(ngx.arg[1]) return fib(num) " $arg_n; echo $res; }

slide-64
SLIDE 64

$ curl 'localhost/fib?n=10' 55

slide-65
SLIDE 65

♡ or use external Lua script file...

slide-66
SLIDE 66

location = /fib { set_by_lua_file $res "conf/fib.lua" $arg_n; echo $res; }

slide-67
SLIDE 67
  • - conf/fib.lua file

function fib(n) if n > 2 then return fib(n-1) + fib(n-2) else return 1 end end local num = tonumber(ngx.arg[1]) return fib(num)

slide-68
SLIDE 68

$ Complex database cluster hashing can also be done in Lua

slide-69
SLIDE 69

http { upstream A { drizzle_server ...; } upstream B { drizzle_server ...; } upstream C { drizzle_server ...; } ... }

slide-70
SLIDE 70

location ~ '^/user/(\d+)' { set $uid $1; set_by_lua_file $backend "conf/hash.lua" $uid; if ($backend = '') { return 400; break; } drizzle_query "select * from users where uid=$uid"; drizzle_pass $backend; rds_json on; }

slide-71
SLIDE 71
  • - hash.lua

function hash(uid) if uid > 0 and uid <= 1200 then return 'A' end if uid > 1200 and uid <= 5300 then return 'B' end if uid > 5300 and uid <= 7100 then return 'C' end return '' end return hash(tonumber(ngx.arg[1]))

slide-72
SLIDE 72

♡ Use Lua to code up nginx content handler directly

slide-73
SLIDE 73

location = /lua { content_by_lua 'ngx.say("Hello, Lua!")'; }

slide-74
SLIDE 74

$ curl 'localhost/lua' Hello, Lua!

slide-75
SLIDE 75

♡ ...and we can read arbitrary nginx variables from within our Lua content handler!

slide-76
SLIDE 76

location = /hello { content_by_lua 'local who = ngx.var.arg_who ngx.say("Hello, ", who, "!")'; }

slide-77
SLIDE 77

$ curl 'localhost/hello?who=agentzh' Hello, agentzh!

slide-78
SLIDE 78

♡ We can also put Lua code into external .lua file to eliminate escaping nightmare.

slide-79
SLIDE 79

location /foo { ... content_by_lua_file /path/to/your/lua-file.lua; }

slide-80
SLIDE 80

♡ We can also issue nginx subrequests diredctly from within Lua content handler now!

slide-81
SLIDE 81

location /other { echo "hello, world"; } # transparent non-blocking I/O in Lua location /lua { content_by_lua ' local res = ngx.location.capture("/other") if res.status == 200 then ngx.print(res.body) end'; }

slide-82
SLIDE 82

$ curl 'localhost/lua' hello, world

slide-83
SLIDE 83

♡ We'd call this whole set of nginx modules ngx_openresty and our work is heavily funded by Taobao.com.

slide-84
SLIDE 84

♡ It is already powering lz.taobao.com.

slide-85
SLIDE 85
slide-86
SLIDE 86
slide-87
SLIDE 87
slide-88
SLIDE 88
slide-89
SLIDE 89

♡ Generate nginx.conf from Perl TT2 templates

slide-90
SLIDE 90
  • - META-conf.lua

apiproxy = { enable = true, enable_lightface = true, enable_admin = false, -- MUST disable in production enable_devel = false, -- MUST disable in production host = 'api.linezing.com', port = 80, log_path = '/opt/apiproxy/logs', conf_path = '/opt/apiproxy/conf', }, nginx = { ...

slide-91
SLIDE 91

♡ Generate nginx.conf from Perl TT2 templates

slide-92
SLIDE 92
  • - nginx.conf.tt

... http { default_type text/plain; keepalive_timeout [% nginx.keepalive_timeout %]; access_log [% nginx.enable_access_log ? apiproxy.log_path _ '/access.log' : 'off' %]; gzip [% nginx.enable_gzip ? 'on' : 'off' %]; gzip_min_length 1000; gzip_types application/x-javascript text/css application/json; gzip_disable "msie6"; ...

slide-93
SLIDE 93

♡ Generate Lua code by our LZSQL compiler

slide-94
SLIDE 94

$ lzsql-compile -c -O2 -n src/*.lzsql $ lzsql-link -m lightface.core -o lightface/core.lua src/*.oul

slide-95
SLIDE 95
  • -/=/view/itemdailyflow/type/trend

int $uid; text $begin, $end, $today, $url_index; symbol $db; location $lz_report; @hist := select ... from LZDB.dpunit_purl_result($db, $begin, $end, $uid) as a ... at $lz_report; @rt := select name, count(name) from LZRTI.getPurl($end as day, $uid) group by name ... return select ... from @hist union all @rt ...

slide-96
SLIDE 96

♡ Join us at the OpenResty Google Group http://groups.google.com/group/OpenResty and the nginx-devel mailing list http://nginx.org/mailman/listinfo/nginx-devel

slide-97
SLIDE 97

♡ or just catch us on IRC: irc.freenode.net #nginx #openresty

slide-98
SLIDE 98

☺ Any questions? ☺

slide-99
SLIDE 99