OpenResty ® Is based on Nginx With Lua's high-performance Web platform, it integrates a large number of sophisticated Lua libraries, third-party modules and most dependencies. It is used to easily build dynamic Web applications, Web services and dynamic gateways that can handle ultra-high concurrency and high scalability.
OpenResty ® By bringing together a variety of well-designed Nginx Module (mainly independently developed by OpenResty team), so as to Nginx Effectively become a powerful general Web application platform. In this way, Web developers and system engineers can use Lua scripting language Nginx Support various C and Lua modules to quickly construct a high-performance Web application system capable of 10K or even 1000K single machine concurrent connection.
OpenResty ® The goal is to make your Web service run directly in Nginx Internal service, make full use of Nginx The non blocking I/O model provides consistent high-performance responses not only to HTTP client requests, but also to remote backend such as MySQL, PostgreSQL, Memcached and Redis.
OpenResty simply understands that it is equivalent to encapsulating nginx and integrating Lua scripts. Developers only need to provide modules to realize the relevant logic, instead of writing Lua scripts in nginx and calling them.
install
linux Installation openresty:
1. Add warehouse execution command
yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
2. Perform installation
yum install openresty
3. After successful installation, the default directory will be as follows:
/usr/local/openresty
4. Start openresty
cd /usr/local/openresty/nginx/sbin
./nginx
Entry program
Configure the nginx configuration file conf / nginx conf. Add a server configuration under the http module
server { listen 8080; location / { default_type text/html; content_by_lua_block { ngx.say("<p>hello, world</p>") } } }
Restart openretry
cd /usr/local/openresty/nginx/sbin
./nginx -s reload
Enter the following address to access http://192.168.200.128:8080 Browser output hello, world
Introduction to common Lua API s in openretry
Similar to a general Web Server, we need to receive requests, process and output responses. For requests, we need to obtain information such as request parameters, request header, Body and so on; For processing, you can call the corresponding Lua code; The output response requires response status code, response header and response
Output of content body. Therefore, we can start from the above points
Receive request
Get nginx variable: NGX var
server { listen 8080; location / { #Define nginx variables set $b $host; default_type text/html; content_by_lua_block { local var = ngx.var; -- obtain nginx variable ngx.say("ngx.var.b : ", var.b, "<br/>") ngx.var.b = 2; -- Set variable value ngx.say("ngx.var.b : ", var.b, "<br/>") ngx.say("<br/>") } } }
Get request header: NGX req. get_ headers()
server { listen 8080; location / { #Define nginx variables set $b $host; default_type text/html; content_by_lua_block { local headers = ngx.req.get_headers() ngx.say("headers begin", "<br/>") ngx.say("Host : ", headers["Host"], "<br/>") ngx.say("user-agent : ", headers["user-agent"], "<br/>") ngx.say("user-agent : ", headers.user_agent, "<br/>") ngx.say("=======================================","</br>") for k,v in pairs(headers) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), "<br/>") else ngx.say(k, " : ", v, "<br/>") end end ngx.say("headers end", "<br/>") ngx.say("<br/>") } } }
Get request URI parameter: NGX req. get_ uri_ args()
server { listen 8080; location / { #Define nginx variables set $b $host; default_type text/html; content_by_lua_block { ngx.say("uri args begin", "<br/>") local uri_args = ngx.req.get_uri_args() ngx.say("param:username=",uri_args['username'], "<br/>") ngx.say("param:password=",uri_args['password'], "<br/>") ngx.say("uri args end", "<br/>") ngx.say("<br/>") } } }
Post request parameter: NGX req. get_ post_ args()
server { listen 8080; location / { #Define nginx variables set $b $host; default_type text/html; content_by_lua_block { ngx.say("uri args begin", "<br/>") -- Get the data in the request body ngx.req.read_body() local uri_args = ngx.req.get_post_args() --obtain key-value Formatted data ngx.say("param:username=",uri_args['username'], "<br/>") ngx.say("param:password=",uri_args['password'], "<br/>") ngx.say("uri args end", "<br/>") ngx.say("<br/>") } } }
Other request related methods:
Get the requested HTTP protocol version: NGX req. http_ version()
Get request method: NGX req. get_ method()
Get request header content: NGX req. get_ headers()
Get the requested body content body: NGX req. get_ body_ data()
Output response
server { listen 8080; location / { default_type text/html; content_by_lua_block { --Write response header ngx.header.a = "1" --Multiple response headers can be used table ngx.header.b = {"2", "3"} --Output response ngx.say("a", "b", "<br/>") ngx.print("c", "d", "<br/>") --200 Status code exit return ngx.exit(200) } } } }
Response related methods:
ngx.header.xx = yy: output response header;
ngx.print(): output the response content body;
ngx.say(): same as NGX Print () is the same, but it will output a newline character at the end;
ngx.exit(): specify the status code to exit;
ngx.send_headers(): send the response status code when calling NGX say/ngx. Automatically send the response status code when printing;
ngx. headers_ Send(): judge whether the response status code is sent.
redirect
server { listen 8080; location / { default_type text/html; content_by_lua_block { ngx.redirect("http://jd.com", 302); } } }
Nginx global memory
Friends who have used Java may know such in-process local cache as Ehcache. Nginx is a Master process with multiple Worker processes
Working mode, so we may need to share data in multiple Worker processes, so we can use NGX shared. Dict to achieve full
Office memory sharing.
1. First in nginx The http part of conf defines a global memory and specifies the memory size.
#Shared global variables are shared among all worker s as follows: a global variable named shared is defined_ The global memory of data is 1m in size lua_shared_dict shared_data 1m;
2. Use global memory
server { listen 8080; location / { default_type text/html; content_by_lua_block { --1,Get global shared memory variable local shared_data = ngx.shared.shared_data --2,Get dictionary value local i = shared_data:get("i") if not i then i = 1 --3,Inert assignment shared_data:set("i", i) ngx.say("lazy set i ", i, "<br/>") end --Increasing i = shared_data:incr("i", 1) ngx.say("i=", i, "<br/>") } } }
3. Introduction to common methods of global memory
ngx.shared.DICT
Gets the shared memory dictionary entry object
Syntax: dict = ngx.shared.DICT dict = ngx.shared[name_var] Among them, DICT and name_var For example, in the above example, shared_data = ngx.shared.shared_data namely dict = ngx.shared.DICT The expression of, The same purpose can also be achieved in the following ways: shared_data = ngx.shared['shared_data']
ngx.shared.DICT:get(key)
Get the value corresponding to the key on the shared memory. If the key does not exist or has expired, nil will be returned; If an error occurs, nil and an error message will be returned.
ngx.shared.DICT:get_stale(key)
Similar to the get method, the difference is that this method will also return expired keys. The third return parameter indicates whether the value of the returned key has expired. true indicates that it has expired and false indicates that it has not expired.
ngx.shared.DICT:set(key, value, exptime?, flags?)
Unconditionally insert a key value pair into the shared memory. The "unconditional" here refers to whether the same key already exists on the shared memory to be inserted.
Meaning of three return values:
success: true for successful insertion and false for failure
err: the error message when the operation fails, which may be similar to "no memory"
Mandatory: true indicates that the insertion needs to be realized by forcibly deleting (LRU algorithm) other dictionary items on the shared memory, and false indicates that the dictionary items on the shared memory are not deleted to realize the insertion.
The exptime parameter indicates the validity time of the key. The unit is seconds (s). The default value is 0, indicating that it will never expire;
The flags parameter is a user flag value, which will be obtained when calling the get method
ngx.shared.DICT.safe_set(key, value, exptime?, flags?)**
Similar to the set method, the difference is that the insertion is not realized by forced deletion (LRU algorithm) when the shared memory is used up. If the memory is insufficient, the nil and err information "no memory" will be returned directly
ngx.shared.DICT.add(key, value, exptime?, flags?)**
Similar to the set method, it is different from the set method in that it will not insert duplicate keys (you can simply think that the add method is a sub method of the set method). If the key to be inserted already exists, nil and err = "exists" will be returned
ngx.shared.DICT.safe_add(key, value, exptime?, flags?)**
And safe_ The set method is similar, except that duplicate keys will not be inserted (you can simply think that the safe_add method is a sub method of the safe_set method). If the key to be inserted already exists, nil and err = "exists" will be returned
ngx.shared.DICT.replace(key, value, exptime?, flags?)**
Similar to the set method, the difference is that it only operates on the existing key (you can simply think of the replace method as a sub method of the set method). If the key to be inserted does not exist in the dictionary, nil and the error message "not found" will be returned
ngx.shared.DICT.delete(key)**
Unconditionally delete the specified key value pair, which is equivalent to
ngx.shared.DICT:set(key, nil)
ngx.shared.DICT.incr(key, value)**
Perform incremental operation on the value corresponding to key. The incremental value is value, where the value can be a positive number, 0 or negative number. Value must be a number in Lua type, otherwise nil and "not a number" will be returned; Key must be a key that already exists in shared memory, otherwise nil and "not found" will be returned
ngx.shared.DICT.flush_all()**
Clearing all the fields in the dictionary will not really free up the memory occupied by the fields, but just mark each field as expired.
ngx.shared.DICT.flush_expired(max_count?)**
Clear expired fields on dictionary, max_count indicates the upper limit value. If it is 0 or not given, it indicates that all expired fields need to be cleared. The return value flushed is the number of expired fields actually deleted.
be careful:
And flush_ The difference of the all method is that it will free up the memory occupied by the expired field
ngx.shared.DICT.get_keys(max_count?)**
Get the field list from the dictionary, the number is max_count, if it is 0 or not given, it indicates that the number is not limited. The default value is 1024
be careful:
It is strongly recommended that you specify a max when calling this method_ Count parameter, because when the number of keys is large, if Max is not specified_ The value of count may cause the dictionary to be locked, blocking the worker process trying to access the dictionary.
openresty execution process analysis
The basic building block for scripting by Nginx and Lua is the instruction. Directives are used to specify when to run user Lua code and how to use the results. Instruction interpretation and execution sequence of each stage in openresty (Nginx + Lua Nginx module)
init_by_lua *: initialize nginx and preload Lua (executed when nginx starts and reloads)*
init_worker_by_lua *: each worker_processes is executed when it is created, which is used to start some scheduled tasks, such as heartbeat check, health check of back-end services, regular pull server configuration, etc*
ssl_certificate_by_lua *: the processing of https requests, which will be executed when the SSL handshake of downstream SSL (https) connection is started. Use case: set SSL certificate chain and corresponding private key according to each request, and selectively reject requests according to SSL protocol;
set_by_lua: set nginx variable;
rewrite_by_lua *: Rewrite request (entering from the rewrite phase of native nginx), perform internal URL rewriting or external redirection, typically such as pseudo static URL rewriting*
access_by_lua *: processing the request (the same function as rewrite_by_lua can be realized, entering from the access phase of native nginx)*
content_by_lua *: execute business logic and generate response, similar to servlet in jsp;
balancer_by_lua: load balancing;
header_filter_by_lua *: processing response header;
body_filter_by_lua: processing response body;
log_by_lua: record the access log;
Note: * indicates two options, such as log_by_lua * can represent log_ by_ Log or Lua_ by_ lua_ file
nginx_ Introduction to common modules of lua
json formatting: cjson
server { listen 8080; location / { default_type text/html; content_by_lua_block { -- introduce cjson local cjson = require("cjson") --take lua Object to json character string local obj = { id = 1, name = "zhangsan", age = nil, is_male = false, hobby = {"film", "music", "read"} } local str = cjson.encode(obj) ngx.say("lua Object to string:",str,"</br>") ngx.say("--------------------------------</br>"); --Convert string to lua object str = '{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1,"age":null}' local obj = cjson.decode(str) ngx.say("String to lua object:","</br>") ngx.say("obj.age ",obj.age,"</br>") ngx.say("obj.age == nil ",obj.age == nil,"</br>") ngx.say("obj.age == cjson.null ",obj.age == cjson.null,"</br>") ngx.say("obj.hobby[1] ",obj.hobby[1],"</br>") } } }
Redis client: resty redis
-- introduce resty.redis library local redis = require("resty.redis") -- Define close redis Method of connection local function close_redis(instance) if not instance then return end local ok, error = instance:close() if not ok then ngx.say(error) end end -- establish redis connect local redis_ip = "127.0.0.1" local redis_port = "6379" local redis_instance = redis:new() redis_instance:set_timeout(1000) local ok, error = redis_instance.connect(redis_ip, redis_port) if not ok then ngx.say(error) return close_redis(redis_instance) end -- implement redis command local redis_key = "message" local redis_value = ngx.md5("hello, world") ok, error = redis_instance:set(redis_key, redis_value) if not ok then ngx.say(error) return close_redis(redis_instance) end local message, error = redis_instance:get(redis_key) if not message then ngx.say(error) return close_redis(redis_instance) end if message == ngx.null then message = "" end ngx.say(redis_key, ": ", message) -- close redis connect close_redis(redis_instance)
MySQL client: resty mysql
Configure openresty to connect to mysql
-- introduce resty.mysql library local mysql = require("resty.mysql") -- Define the method of closing the connection local function close_db(instance) if not instance then return end instance:close() end -- establish mysql Instance object local instance, error = mysql:new() if not instance then ngx.say(error) return end instance:set_timeout(1000) local properties = { host = "127.0.0.1", port = 3306, database = "wpsmail", user = "root", password = "123456" } -- connect mysql local result, error, error_no, sql_state = instance:connect(properties) if not result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end
Delete table
local drop_table_sql = "drop table if exists test" local drop_result, error, error_no, sql_state = instance:query(drop_table_sql) if not drop_result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end
Create table
local create_table_sql = "create table test(id int primary key auto_increment, ch varchar(100))" local create_result, error, error_no, sql_state = instance:query(create_table_sql) if not create_result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end
Insert table data
local insert_sql = "insert into test (ch) values('hello')" local insert_result, error, error_no, sql_state = instance:query(insert_sql) if not insert_result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end ngx.say("affected row: ", insert_result.affected_rows, ", insert id: ", insert_result.insert_id)
Update table data
local update_table_sql = "update test set ch = 'hello2' where id =" .. insert_result.insert_id local update_result, error, error_no, sql_state = instance:query(update_table_sql) if not update_result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end ngx.say("affected row: ", insert_result.affected_rows)
Query table data
local select_table_sql = "select id, ch from test" local select_result, error, error_no, sql_state = instance:query(select_table_sql) if not select_result then ngx.say("error: ", error, ", error_no: ", error_no, ", sql_state: ", sql_state) return close_db(instance) end for i, row in ipairs(select_result) do ngx.say(i, ": ", row) end