openresty實踐指導

由於獨立秒殺目前接過來了,但是其核心是利用openresty實現的,本人對此技術棧較爲陌生,特寫下本篇指導,以期快速上手。

一、openresty入門初步

安裝openresty

首先是安裝openresty,macOS的安裝方式

brew tap openresty/brew
brew install openresty

安裝完畢之後,可以得到安裝路徑,配置到系統PATH中並生效:

export PATH=/usr/local/Cellar/openresty/1.21.4.1_2/nginx/sbin:$PATH

之後就可以校驗是否安裝成功了,按照如下命令檢測:

which nginx

結果顯示如下的路徑:/usr/local/Cellar/openresty/1.21.4.1_2/nginx/sbin/nginx,則證明安裝成功;如果沒有任何輸出,則表明未安裝成功,可以檢查安裝路徑是否正確。

初步使用

新建個文件夾,然後利用如下命令新建conf,logs兩個字文件夾:

mkdir conf logs

之後,進行nginx配置文件配置,運行命令如下:

nano conf/nginx.conf

輸入內容如下:

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua_block {
                ngx.say("<p>hello, world</p>")
            }
        }
    }
}

寫完之後,可以測試腳本是否正常:

openresty -p $PWD/ -c conf/nginx.conf -t

之後在當前目錄啓動即可:

openresty -p $PWD/ -c conf/nginx.conf

利用如下命令可以看到啓動的master,worker進程

ps aux|grep nginx|grep -v /tmp/ 

這裏需要注意下,一些常用的openresty命令如下

(1) 啓動 openresty
(2) 重啓 openresty -s reload
(3) 關閉 openresty -s stop

瀏覽器中輸入 http://127.0.0.1:8080就可以看到正常的輸出結果了。

 

二、簡單的lua腳本

創建新的文件夾,名稱分別爲 log,conf, lua,命令如下:

mkdir logs conf lua

nginx.conf文件內容如下:

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua_file /Users/shichaoyang/openresty/hello-module/lua/hello.lua;
        }
    }
}

可以看到,這裏利用content_by_lua_file命令來制定lua腳本文件。其中hello.lua的內容爲 :

ngx.say("hello lua");

之後在當前目錄啓動即可:

openresty -p $PWD/ -c conf/nginx.conf

在瀏覽器訪問,即可以看到正確的輸出結果了。

 

三、lua腳本模塊

同樣創建logs,conf,lua文件夾,其中nginx.conf文件內容如下:

worker_processes 1;
error_log logs/error.log;


events {
    worker_connections 1024;
}


http {
    lua_package_path "/usr/local/Cellar/openresty/1.21.4.1_2/?.lua;;$prefix/lua/?.lua;";


    server {
        listen 8081 reuseport;


        location / {
            default_type text/plain;
            content_by_lua_block {
                local hello = require "mod"
                hello.greet("a lua module");
            }
        }
    }
}

腳本內容如下:


local _M = {}


function _M.greet(name)
    ngx.say("hello from name ",name)
end


return _M

之後在當前目錄啓動即可:

 openresty -p $PWD/ -c conf/nginx.conf

可以看到,腳本模塊的封裝方式。這裏需要說明下,nginx啓動的時候會從lua_package_path指定的路徑中將lua文件加載進來。而content_by_lua_block則可以指定執行的業務邏輯代碼。

這裏也許有人要問,爲什麼把openresty按住根目錄下的lua文件都加載進來呢,主要原因是因爲模塊的執行需要resty.core的支持,如果不加入usr/local/Cellar/openresty/1.21.4.1_2/?.lua;; 報錯:

ginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core); ensure you are using an OpenResty release from https://openresty.org/en/download.html (reason: module 'resty.core' not found:

no field package.preload['resty.core']

所以這裏需要將lua_package_path改成 lua_package_path "$prefix/lua/?.lua;/usr/local/lib/lua/?.lua;;";

參見:https://github.com/openresty/lua-nginx-module/issues/1533

 

四、lua腳本傳參

本指導來源於chatGPT回答:

我:openresty多模塊之間傳參,寫一個在兩個網頁中傳參的代碼示例
ChatGPT:
以下是一個在兩個頁面之間傳參的OpenResty代碼示例:
location /page1 { 
  content_by_lua_block {
        local param1 = ngx.var.arg_param1
        local param2 = ngx.var.arg_param2
        ngx.redirect("/page2?param1=" .. param1 .. "& param2=" .. param2)
    }
}


location /page2 { 
   content_by_lua_block { 
      local param1 = ngx.var.arg_param1 
      local param2 = ngx.var.arg_param2
      -- Do something with the two parameters here
    }
}

這裏我們就根據其指導來實現一下。

同樣的,創建logs,conf,lua文件夾,然後nginx.conf內容如下:

worker_processes  1;
error_log logs/error.log;


events {
    worker_connections 1024;
}


http {
    server {
        listen 8080;


        location /p1 {
            default_type text/html;
            content_by_lua_file /Users/shichaoyang/openresty/trans-module/lua/p1.lua;
        }


         location /p2 {
            default_type text/html;
            content_by_lua_file /Users/shichaoyang/openresty/trans-module/lua/p2.lua;
        }
    }
}

lua腳本p1內容如下:

local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2


ngx.redirect("/p2?param1=" .. param1 .. "& param2=" .. param2)

lua腳本p2內容如下:

local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2


ngx.say(param1)
ngx.say(param2)

之後在當前目錄啓動即可:

openresty -p $PWD/ -c conf/nginx.conf

之後訪問:

http://127.0.0.1:8080/p1?param1=1& param2=2

則會自動跳轉到

http://127.0.0.1:8080/p2?param1=1& param2=2

並輸出1 2

更多內容請訪問:https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/

 

五、lua腳本調試

同樣的,創建logs,conf,lua文件夾,然後nginx.conf內容如下:

worker_processes  1;
error_log logs/error.log;


events {
    worker_connections 1024;
}


http {

    lua_package_path "/usr/local/Cellar/openresty/1.21.4.1_2/?.lua;;$prefix/lua/?.lua;";


    server {
        listen 8080;

        location / {
            default_type text/html;
            content_by_lua_file /Users/shichaoyang/openresty/ut-module/lua/ut.lua;
        }


         location /test {
            content_by_lua_file  /Users/shichaoyang/openresty/ut-module/lua/uttest.lua;
        }


    }
}

ut.lua腳本內容如下:

ngx.say("111")

uttest.lua腳本內容如下:



local iresty_test    = require "iresty_test"
local tb = iresty_test.new({unit_name="example"})


function tb:init(  )
    self:log("init complete")
end


function tb:test_00001(  )
    error("invalid input")
end


function tb:atest_00002()
    self:log("never be called")
end


function tb:test_00003(  )
   self:log("ok")
end


-- units test
tb:run()

這裏需要從https://github.com/iresty/lua-resty-test/blob/master/lib/resty/iresty_test.lua將此文件下載,並放到lua文件夾下面

之後在當前目錄啓動即可:

openresty -p $PWD/ -c conf/nginx.conf

訪問:http://127.0.0.1:8080/test 即可得到測試結果:

0.000 [32m[example] [m[32munit test start

[m0.000 [32m[example] [minit complete

0.000 [32m \_[test_00001] [m[33mfail /Users/shichaoyang/openresty/ut-module/lua/uttest.lua:9: invalid input

[m0.000 [32m \_[test_00003] [m鈫搊k

0.000 [32m \_[test_00003] [m[32mPASS

[m0.000 [32m[example] [m[32munit test complete

[m

 

六、openresty配置必知必會

1. proxy_pass, 反向代理,是指以代理服務器接收Internet上的鏈接請求,然後將請求轉發給內部網絡上的服務器,並將從服務器上得到的結果返回給Internet上請求連接的客戶端。

舉個例子,比如我的內部服務器是放在212環境上,那麼開發的接口如下這樣的:

http://192.168.1.212:8136/xxxx 然後端口號是8136,然後直接訪問該接口會返回對應的數據,但是接口一般都是域名訪問的,因此我們需要在nginx上配置一個域名,假如爲 xy.xxx.com, 然後當我們在聯調接口的時候,我們使用 http://xy.xxx.com/xxxx 這樣的接口時,它會反向代理到 http://192.168.1.212:8136/xxxx 上來,這樣它會返回內部服務器的數據給客戶端,客戶端就拿到對應的數據顯示出來了。

2. resolver , DNS解析,一般配製成公共的或者公司內部的都行。

3. allow & denyallow 和 deny 指令在 ngx_http_access_module 模塊中,兩個指令分別表示允許或禁止源 IP 訪問,用於對源 IP 做訪問控制,nginx 是按照自上而下的順序進行匹配,匹配到一個就不往下繼續了。

allow 指令

a、允許哪些 IP 訪問,all 表示允許所有;

b、作用域 http / server / location / limit_except ;

deny 指令

a、禁止哪些 IP 訪問,all 表示禁止所有;

b、作用域 http / server / location / limit_except ;

	location = /request_stat {
                        allow 192.168.0.0/16;
                        deny all;
                        request_status on;
                }

4. stub_status, stub_status模塊參數可以用來查看Nginx的一些狀態信息如連接數、請求數統計等,需要安裝好相應的模塊stub_status才支持配置,安裝時需要指定–with-http_stub_status_module。參考: https://blog.csdn.net/jxlhljh/article/details/126270472

	location = /status {
		allow 192.168.0.0/16;
		deny all;
		stub_status on;
		access_log off;
	}

5. access_log, 日誌文件一般存放在 /var/log/nginx 下,若是docker啓動則可以使用主機掛載位置,直接使用 tail -f命令即可查看access日誌。參考: https://blog.csdn.net/weixin_45698637/article/details/128486012

6. set指令, set 指令是用於定義一個變量,並且賦值。這些變量值可以通過ngx.arg.xxx在lua文件內部使用。

	    #black list redis
		set $risk_control_server "127.0.0.1";
		set $risk_control_port 6380;

7. log_by_lua, log_by_lua*​ 是一個請求經歷的最後階段。由於記日誌跟應答內容無關,Nginx 通常在結束請求之後才更新訪問日誌。由此可見,如果我們有日誌輸出的情況,最好統一到 ​log_by_lua* ​階段。如果我們把記日誌的操作放在 ​content_by_lua*​ 階段,那麼將線性的增加請求處理時間。 api文檔參考: https://www.kancloud.cn/qq13867685/openresty-api-cn/159199

8. localtion @命名location,用@標識,類似於定於goto語句塊。


                location  @item_fail {
                        default_type application/json;
                        content_by_lua_file /export/runtime/WEB-INF/classes/new_lua/item_fail.lua;
                }

                error_page 404 @item_fail;
                error_page 500 502 503 504 @item_fail;

9. limit_req & limit_req_zone, 限流,基於漏桶算法實現的。

limit_req_zone $binary_remote_addr zone=perip_rps:10m rate=5r/s; #單ip每秒限制5個請求
limit_req_zone $server_name zone=perserver_rps:10m rate=3000r/s; #每個server每秒限制處理3000個請求

上面分別是按照ip和server來限流rps,zone=perip_rps:10m是設定這個limit_req_zone的名字爲perid_rps,且在nginx內存裏分配10m的空間來存儲訪問頻次信息,rate=15r/s表示每秒15個請求,30r/m每分鐘30次請求。

一般在http裏配置好了limit_req_zone之後,就可以在server或者location裏邊配置limit_req了,比如:

limit_req zone=perserver_rps burst=2000 nodelay;  #server每秒請求限流
limit_req zone=perip_rps burst=10 nodelay; #每個ip每秒請求如果超過limit_req_zone的配置,最多可以緩衝10個

這裏設置 brust=10,表示在超過限制速率 5r/s 的時候,同時至多允許額外有 10 個請求排隊等候,待平均速率迴歸正常後,隊列前面的請求會優先被處理。

參考: http://events.jianshu.io/p/9db107f579a5

參考: https://www.upyun.com/opentalk/opentalk/417.html

參考: https://www.w3cschool.cn/openresty1/

 

七、openresty腳本必知必會

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章