Introduction to openretry, a high performance web platform

Posted by DeeDee2010 on Sat, 19 Feb 2022 23:01:08 +0100

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

Topics: Front-end