The article is organized in bilibili Dark horse programmer’s video tutorial

Lua is introduced

What is Lua?

Lua [1] is a small scripting language. It was developed in 1993. It is designed to provide flexible extension and customization capabilities for applications through flexible embedding. Lua is written in standard C and can be compiled and run on almost any operating system and platform. Lua does not provide a powerful library because of its positioning. So Lua is not a good language for developing standalone applications. Lua has a concurrent JIT project that provides just-in-time compilation on a specific platform.

In a nutshell:

Lua is a lightweight scripting language written in standard C and open as source code. It is designed to be embedded in applications to provide flexible extension and customization capabilities.

The characteristics of the lua

  • Support for procedure-oriented programming and functional programming;
  • Automatic memory management; Only provides a general type of table (table), with it can achieve array, hash table, collection, object;
  • Language built-in pattern matching; Closure (closure); A function can also be viewed as a value; Multithreading (collaborative processes, not threads supported by the operating system) support;
  • Closures and tables make it easy to support some of the key mechanisms needed for object-oriented programming, such as data abstraction, virtual functions, inheritance, and overloading.

Application scenarios of Lua

  • The game development
  • Standalone application scripts
  • Web Application Scripts
  • Extensions and database plug-ins such as MySQL Proxy and MySQL WorkBench
  • Security systems, such as intrusion detection systems
  • Nested calls in Redis implement transaction-like functionality
  • The web container applies logic that handles filtering caches and so on, such as Nginx.

The installation of the lua

There e are Linux and MAC versions installed. We use the Linux version of the installation, first we prepare a Linux virtual machine.

To install, run the following command on Linux.

Curl the -r -o http://www.lua.org/ftp/lua-5.3.5.tar.gz tar ZXF lua - 5.3.5. Tar. GzcdLua - 5.3.5 make Linuxtest
Copy the code

Note: The following errors may occur during installation:To install lua dependent libraries, run the following command:

yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
Copy the code

Then run the Lua test to check whether Lua is successfully installed

[root@localhost ~]# luaCopyright (C) 1994-2008 Lua.org, PUC-RioCopy the code

Entry procedures

Create a hello.lua file with the content

Edit the file hello.lua

vi hello.lua
Copy the code

Type in the file:

print("hello");
print("hello lua!");
print("hello world!");
Copy the code

Save and exit.

Execute the command

lua hello.lua
Copy the code

The output is:

hello
hello lua!
hello world!
Copy the code

The effect is as follows:

Basic syntax of LUA

Lua has interactive programming and scripted programming. Interactive programming is simply typing in the syntax and executing it. Scripting requires writing scripts and then executing commands to execute the scripts. Scripting is generally used. (For example, create a hello.lua file, enter the contents of the file, and execute lua hell.lua)

(1) Interactive programming

Lua provides an interactive programming mode. We can type programs on the command line and see the results immediately.

Lua interactive programming mode can be enabled with the command Lua -i or Lua:

lua -i
Copy the code

The diagram below:

(2) Scripted programming

We can save Lua program code to a lua-ending file and execute it. This pattern is called scripted programming, such as writing Lua syntax to a hello. Lua file in the introductory program.

annotation

2. Two minus signs are single-line comments:

--
Copy the code

Multi-line comments:

--[[multiline comment --]]
Copy the code

Define variables

Global variables. By default, defining a variable is a global variable,

To use a local variable, declare it local. For example:

-- Global variable assignment
a=1
-- Local variable assignment
local b=2 
Copy the code

If the variable is not initialized: its value is nil which is different from null in Java.

As shown below:

Data types in Lua

Lua is a dynamically typed language. Variables do not need to be typed, only assigned values. Values can be stored in variables and passed as arguments or returned as a result.

There are eight basic types in Lua: nil, Boolean, number, String, UserData, function, Thread, and table.

The data type describe
nil This is the simplest; only the value nil belongs to this class, representing an invalid value (equivalent to false in conditional expressions).
boolean Contains two values: false and true.
number Represents a real floating-point number of type double precision
string A string is represented by a pair of double or single quotation marks
function A function written by C or Lua
userdata Represents any C data structure stored in a variable
thread Represents a separate line of execution for the execution of the coroutine
table Lua tables are associative Arrays whose indexes can be numeric, string, or table types. In Lua, a table is created using a “construct expression”. The simplest construct expression is {}, which creates an empty table.

Example:

print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
Copy the code

Process control

(1) if statements

A Lua if statement consists of a Boolean expression as a condition, followed by other statements.

Grammar:

if(Boolean expression)then
   --[statement executed when Boolean expression is true --]
end
Copy the code

Example:

(2) the if… Else statements

Lua if statements can be paired with else statements to execute an else statement block if the if conditional expression is false.

Grammar:

if(Boolean expression)then
   --[execute block when Boolean expression is true --]
else
   --[execute block when Boolean expression is false --]
end
Copy the code

Example:

cycle

Students complete

(1)while loop

The Lua programming language while loop repeats the body of the loop if the condition is true. Grammar:

while(condition)
do
   statements
end
Copy the code

Example:

a=10
while( a < 20 )
do
   print("The value of a is:, a)
   a = a+1
end
Copy the code

The effect is as follows:

(2) the for loop

Lua programming language for loop statements can repeatedly execute specified statements, the number of repetitions can be controlled in the for statement.

Syntax: 1->10 1:exp1 10:exp2 2:exp3: incremental number

for var=exp1,exp2,exp3 
do< executor >end  
Copy the code

Var changes from exp1 to exp2. Each change increments var by exp3 and executes the body of execution once. Exp3 is optional. If not specified, it defaults to 1.

Example:

for i=1.9.2
do
   print(i)
end
Copy the code

For I = 1,9,2: I =1 starts the loop at 1, 9 loops the data to 9, and 2 increments by 2 each time

(3) repeat… Until statement [condition satisfied end]

Lua programming language repeat… Until loops differ from for and while loops, where the conditional statements are judged at the beginning of the current loop execution, whereas repeat… The condition statement of the until loop is judged after the end of the current loop.

Grammar:

repeat
   statements
until( condition )
Copy the code

Case study:

function

Functions can also be defined in Lua, similar to methods in Java. Such as:

--[[function returns the maximum value of two values --]]
function max(num1, num2)

   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result; 
end
Call function
print("The maximum value between the two values is.max(10.4))
print("The maximum value between the two values is.max(5.6))
Copy the code

Results after execution:

The maximum value of the comparison is 10 and the maximum value of the comparison is 6Copy the code

… : indicates splicing

table

Table is a Lua data structure that helps us create different data types, such as arrays, dictionaries, etc.

Lua also uses tables for modules, packages, and objects.

Case study:

Initialize the table
mytable = {}

- the specified value
mytable[1] ="Lua"

-- Remove reference
mytable = nil
Copy the code

The module

(1) Module definition

Modules are similar to an encapsulation library. Starting from Lua 5.1, Lua has added a standard module management mechanism, which can put some common code in a file and call it in the form of API interface in other places, which is beneficial to code reuse and reduce code coupling.

Create a file called module.lua and create a separate module in module.lua with the following code:

-- The file name is module.lua
-- Define a module named module
module = {}
 
Define a constant
module.constant = "This is a constant."
 
Define a function
function module.func1(a)
    print("This is a public function")
end
 
local function func2(a)
    print("This is a private function!")
end
 
function module.func3(a)
    func2()
end
 
return module
Copy the code

The structure of a module is the structure of a table, so you can operate on constants or functions in the module as if you were calling elements in the table.

Func2 above is declared as a local variable of the block, representing a private function. Therefore, the private function in the module cannot be accessed externally and must be called through the public function in the module.

(2) the require function

Require is used to introduce other modules, similar to Java classes that reference other classes.

Usage:

require("< module name >")
Copy the code
require "< module name >"
Copy the code

Either way.

We can import the module defined above and create a test_module.lua file as follows:

-- test_module. Lua files
-- module is the module mentioned above in module.lua
require("module")

print(module.constant)

module.func3()
Copy the code

OpenResty introduction

OpenResty(also called ngx_OpenResty) is a scalable Web platform based on NGINx, started by Chinese Zhang Yichun, which provides many high quality third-party modules.

OpenResty is a powerful Web application server that allows Web developers to leverage the various C and Lua modules supported by Nginx using the Lua scripting language, especially in terms of performance. OpenResty can quickly build ultra-high-performance Web applications capable of responding to more than 10K concurrent connections.

360, UPYUN, Aliyun, Sina, Qq.com, Qunar, And Kugou music are all deep users of OpenResty.

OpenResty simply encapsulates Nginx and integrates LUA scripts. Instead of writing LUA scripts in Nginx, developers simply need to provide modules to implement the logic.

Install openresty

Linux installation openresty:

1. Add the warehouse and run the command

 yum install yum-utils
 yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
Copy the code

2. Perform the installation

yum install openresty
Copy the code

3. After the installation, the default directory is as follows:

/usr/local/openresty
Copy the code

Install nginx

Has been installed by default nginx in directory: / usr/local/openresty/nginx.

Modify/usr/local/openresty/nginx/conf/nginx. Conf, sets the configuration file using the root to root, the purpose is to use lua scripts in the future, can be loaded directly under the root of the lua script.

cd /usr/local/openresty/nginx/conf
vi nginx.conf
Copy the code

Modify the code as follows:

Test access

Restart the centos VIRTUAL machine and access the test Nginx

Visit address:http://server IP address /

Lua script instance: page AD cache loading and reading

Demand analysis

Need to display advertising information on the page.

Lua + Nginx configuration

(1) Implementation idea – query data into Redis

Implementation idea:

  • Define request: Used to query data in the database for updates to Redis.
  • A. Connect to mysql, read the advertisement list according to the advertisement category ID, and convert it to a JSON string.
  • B. Connect to Redis and save the AD list JSON string to Redis.

Define the request:

Request: /update_content Parameter: id -- Specifies the ID of the AD category. Returned value: JSONCopy the code

Request address: < http://server IP address /update_content? id=1>

Create directory /root/lua and create update_content.lua ‘: connect to mysql to query data and store it in Redis.



Above code:

ngx.header.content_type="application/json; charset=utf8"
local cjson = require("cjson")
local mysql = require("resty.mysql")
local uri_args = ngx.req.get_uri_args()
local id = uri_args["id"]

local db = mysql:new()
db:set_timeout(1000)
local props = {
    host = "8.131.64.45",
    port = 3306,
    database = "changgou_content",
    user = "root",
    password = "[email protected]"
}

local res = db:connect(props)
local select_sql = "select url,pic from tb_content where status ='1' and category_id="..id.." order by sort_order"
res = db:query(select_sql)
db:close(a)local redis = require("resty.redis")
local red = redis:new()
red:set_timeout(2000)

local ip ="8.131.66.136"
local port = 6379
red:connect(ip,port)
red:auth("csp19990129")
red:select(0)
red:set("content_"..id,cjson.encode(res))
red:close()

ngx.say("{flag:true}")
Copy the code

Modify the/usr/local/openresty/nginx/conf/nginx.confFile: Add header information and location information:

The code is as follows:

server {
    listen       80; server_name localhost; User request /update_content? id=1Location /update_content {content_by_lua_file /root/lua/update_content.lua; }}Copy the code

Define the lua cache namespace, modify nginx.conf, add the following code:



The code is as follows:

# lua cache namespace lua_shared_dict dis_cache128m; 
Copy the code

Browser test execution cache:

http://server IP/update_Content? Id =1

Go to the Redis client to test whether the cache is successful:



As shown, the data is obtained and the cache is successful!

(2) Implementation idea – obtain data from Redis

Implementation idea:

Define a request where the user gets a list of ads based on the ID of the AD category. Get the data directly from Redis using lua scripts.

Define the request:

Request :/read_content Parameter: id Returned value: JSONCopy the code

Create read_content.lua in /root/lua:

-- Sets the response header type
ngx.header.content_type="application/json; charset=utf8"
Gets the ID of the parameter in the request
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
-- Introducing the Redis library
local redis = require("resty.redis");
Create a Redis object
local red = redis:new()
-- Set the timeout period
red:set_timeout(2000)
- the connection
local ok, err = red:connect("Server IP".6379)
Get the value of key
local rescontent=red:get("content_"..id)
Output to the return response
ngx.say(rescontent)
-- Close the connection
red:close(a)Copy the code

in/usr/local/openresty/nginx/conf/nginx.confThe configuration is as follows:

As shown in figure:

Code:

User request /read_content? id=1Location /read_content {content_by_lua_file /root/lua/read_content.lua; }Copy the code

(3) Join openResty local cache

There is no problem in the above way, but if all the requests go to Redis, redis will be under great pressure, so we generally adopt multi-level caching to reduce the service pressure of the downstream system. Refer to the implementation of the basic idea diagram.

  • Query the OpenResty local cache first if not
  • Query data in Redis, if no
  • Mysql > select * from ‘mysql’;

Modify the read_content.lua file as follows:

The complete configuration is as follows:

ngx.header.content_type="application/json; charset=utf8"
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
Get the local cache
local cache_ngx = ngx.shared.dis_cache;
Get local cache data based on ID
local contentCache = cache_ngx:get('content_cache_'..id);

if contentCache == "" or contentCache == nil then
    local redis = require("resty.redis");
    local red = redis:new()
    red:set_timeout(2000)
    red:connect("8.xxx.xx.xx6".6379)
    -- Password and selected bucket
    red:auth("csxxxxx29")
    red:select(0)

    local rescontent=red:get("content_"..id);

    if ngx.null == rescontent then
        local cjson = require("cjson");
        local mysql = require("resty.mysql");
        local db = mysql:new();
        db:set_timeout(2000)
        local props = {
            host = "8.xxx.xx.x5",
            port = 3306,
            database = "changgou_content",
            user = "root",
            password = "CSPxxxxxx.com"
        }
        local res = db:connect(props);
        local select_sql = "select url,pic from tb_content where status ='1' and category_id="..id.." order by sort_order";
        res = db:query(select_sql);
        local responsejson = cjson.encode(res);
        red:set("content_"..id,responsejson);
        ngx.say(responsejson);
        db:close(a)else
        cache_ngx:set('content_cache_'..id, rescontent, 10*60);
        ngx.say(rescontent)
    end
    red:close(a)else
    ngx.say(contentCache)
end
Copy the code

The test address: http://192.168.211.132/update_content? id=1

All ads with category ID=1 will be queried and stored in Redis cache:



Test address:http://server IP/update_Content? Id =1

All ads with category ID=1 will be obtained: