您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“nginx怎么集成lua操作mysql”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“nginx怎么集成lua操作mysql”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
直接在nginx做配置黑名單,通過編寫邏輯塊實現(xiàn);
在服務(wù)端(Java)中編寫過濾器,在過濾器中統(tǒng)一攔截;
在服務(wù)端(Java)中編寫攔截器,在攔截器中統(tǒng)一攔截;
這里列舉了3種實現(xiàn)的思路,至于實現(xiàn)方案,可能還有更多,但是我們想想,在nginx中編寫邏輯塊貌似不是很多人擅長的;在代碼層面做不是不可以,而是這樣一來,在涉及到高并發(fā)的業(yè)務(wù)高峰期,這必然會對后端服務(wù)造成較大的壓力,那么還有沒有其他更好的處理辦法呢?
這就是要說的lua,即nginx作為網(wǎng)關(guān)仍然作為代理服務(wù)器,由于nginx可以集成lua,于是使用lua進行配合,來完成上面的業(yè)務(wù)實現(xiàn)的設(shè)計;
ngx_lua模塊由淘寶技術(shù)團隊開發(fā),通過將lua解釋器集成進Nginx;
可采用lua腳本實現(xiàn)業(yè)務(wù)邏輯,由于lua的緊湊、快速以及內(nèi)建協(xié)程,所以在保證高并發(fā)服務(wù)能力的同時極大地降低了業(yè)務(wù)邏輯實現(xiàn)成本;
OpenRestry
OpenResty是一個基于Nginx與 Lua 的高性能 Web 平臺,其內(nèi)部集成了大量精良的 Lua庫、第三方模塊以及大多數(shù)的依賴項;用于方便地搭建能夠處理超高并發(fā)、擴展性極高的動態(tài) Web 應(yīng)用、Web 服務(wù)和動態(tài)網(wǎng)關(guān);
OpenResty內(nèi)部已經(jīng)集成了Nginx和Lua,所以使用起來會更加方便;
簡單來說,直接安裝并使用OpenRestry,就可以達到同時使用Nginx與Lua的效果,同時基于OpenRestry,還可以在內(nèi)部操作其他中間件,比如mysql,redis,kafka等,這樣就使得業(yè)務(wù)架構(gòu)在設(shè)計上具備了更大的靈活性;
wget https://openresty.org/download/openresty-1.15.8.2.tar.gz
tar -zxf openresty-1.15.8.2.tar.gz
這一步有點類似于nginx的源碼安裝,進行相關(guān)的環(huán)境變量的配置,這里直接使用默認的就好;
./configure
進入nginx目錄,可以看到里面的目錄和nginx自身安裝完畢后的配置幾乎一樣
進入conf,找到nginx.conf配置文件,添加如下內(nèi)容:
location /lua { default_type 'text/html'; content_by_lua 'ngx.say(" <h2>hello,openRestry lua</h2>")'; }
進入nginx的sbin目錄下啟動nginx
啟動完成后,瀏覽器訪問下服務(wù)器即可,可以看到nginx本身服務(wù)已啟動
然后訪問上面配置的lua地址,可以看到也能夠正常的訪問到,說明openrestry的模塊已經(jīng)安裝完畢
使用Lua編寫Nginx腳本的基本構(gòu)建塊是指令,指令用于指定何時運行用戶Lua代碼以及如何使用結(jié)果,下面針對一些常用的指令做簡單的說明
1、init_by_lua*
該指令在每次Nginx重新加載配置時執(zhí)行,用來完成一些耗時操作模塊加載,或初始化一些全局配置
2、init_worker_by_lua*
該指令用于啟動一些定時任務(wù),如心跳檢查、定時拉取服務(wù)器配置等
3、set_by_lua*
該指令只要用來給變量賦值,這個指令一次只能返回一個值,并將結(jié)果 值給Nginx中指定變量
4、rewrite_by_lua*
用于執(zhí)行內(nèi)部URL重寫或者外部重定向,典型的如偽靜態(tài)化URL重 寫,本階段在rewrite處理階段的最后默認執(zhí)行(和nginx自身的rewrite功能有類似的地方)
5、access_by_lua*
該指令用于訪問控制,例如,只允許內(nèi)網(wǎng)IP訪問
6、content_by_lua*
該指令是使用最多的指令,大部分任務(wù)是在這個階段完成的,其他過程往往為這個階段準備數(shù)據(jù),正式處理往往都在本階段執(zhí)行
7、header_filter_by_lua*
用于設(shè)置應(yīng)答消息的頭部信息
8、body_filter_by_lua*
該指令對響應(yīng)數(shù)據(jù)進行過濾,如截斷、替換
9、log_by_lua*
該指令用于log請求處理階段,用Lua代碼處理日志,但并不替換原有 log處理
10、balancer_by_lua*
該指令主要作用是用來實現(xiàn)上游服務(wù)器的負載均衡器算法
11、ssl_certificate_by_*
該指令作用在Nginx和下游服務(wù)開始一個SSL握手操作時將允許本配置項的Lua代碼
一個使用指令的需求
接下來針對上面提到的各種指令,來做一個簡單的需求
nginx接收到請求后,根據(jù)參數(shù)中g(shù)ender傳入的值,如果gender傳入的是1 則在頁面上展示 “先生” , 如果gender傳入的是0,則在頁面上展示“女士”
注意:使用指令編寫的基本步驟是,在nginx.conf模塊中,自定義localtion塊中編寫lua的相關(guān)代碼即可
location /getByGender { default_type 'text/html'; set_by_lua $param " local uri_args = ngx.req.get_uri_args() local gender = uri_args['gender'] local name = uri_args['name'] if gender =='1' then return name..':先生' elseif gender=='0' then return name..':女士' else return name end "; charset utf-8; return 200 $param; }
然后啟動nginx做一下測試
1)訪問服務(wù),不攜帶任何參數(shù)
這時候無任何返回信息
2)訪問服務(wù),攜帶name參數(shù)
3)訪問服務(wù),攜帶name和gender參數(shù)
更多的指令可以參照此類方式編寫,但是前提需要掌握一點lua的基本語法
Redis在系統(tǒng)中經(jīng)常作為數(shù)據(jù)緩存、內(nèi)存數(shù)據(jù)庫使用,在各類互聯(lián)網(wǎng)項目中扮演著非常重要的作用;
Lua-resty-redis庫是OpenResty提供的一個操作Redis的接口庫,可根據(jù)自己的業(yè)務(wù)情況做一些邏輯處理,適合做復(fù)雜的業(yè)務(wù)邏輯。所以下面將以Lua-resty-redis來進行說明。
1、提前安裝好redis并啟動服務(wù)
2、測試下redis客戶端
lua-resty-redis提供了訪問Redis的詳細API,包括創(chuàng)建對接、連 接、操作、數(shù)據(jù)處理等。這些API基本上與Redis的操作是對應(yīng)起來的
1、lua中導(dǎo)入redis依賴
redis = require "resty.redis"
2、new,創(chuàng)建一個Redis對象
redis,err = redis:new()
3、創(chuàng)建redis連接
ok:連接成功返回 1,連接失敗返回nil;
err:返回對應(yīng)的錯誤信息;
ok,err=redis:connect(host,port[,options_table])
4、設(shè)置請求操作Redis的超時時間
redis:set_timeout(time)
5、close,關(guān)閉連接
關(guān)閉當前連接,成功返回1;
失敗返回nil和錯誤信息;
ok,err = redis:close()
補充說明:
在lua-resty-redis中,所有的Redis命令都有自己的方法;方法名字和命令名字相同,只是全部為小寫;
具體實現(xiàn)效果展示
在nginx.conf模塊下,添加如下的location內(nèi)容
location /redis { default_type "text/html"; content_by_lua_block { local redis = require "resty.redis" -- 引入 Redis local redisObj = redis:new() --創(chuàng)建Redis對象 redisObj:set_timeout(3000) --設(shè)置超時數(shù)據(jù)為3s local ok,err = redisObj:connect("IP",6379) --設(shè)置redis連接信息 if not ok then --判斷是否連接成功 ngx.say("failed to connection redis",err) return end ok,err = redisObj:set("username","TOM") --存入 數(shù)據(jù) if not ok then --判斷是否存入成功 ngx.say("failed to set username",err) return end local res,err = redisObj:get("username") --從 redis中獲取數(shù)據(jù) ngx.say(res) --將數(shù)據(jù)寫會消息體中 redisObj:close() } }
重啟nginx,進行測試,直接在瀏覽器訪問一下如下地址,可以看到數(shù)據(jù)成功寫入到redis
MySQL是一個使用廣泛的關(guān)系型數(shù)據(jù)庫。在ngx_lua中,MySQL有兩種訪問模式,分別是
用ngx_lua模塊和lua-resty-mysql模塊: 這兩個模塊是安裝OpenResty時默認安裝的;
使用drizzle_nginx_module(HttpDrizzleModule)模塊:需要單獨
安裝,這個庫現(xiàn)不在OpenResty中
lua-resty-mysql
lua-resty-mysql是OpenResty開發(fā)的模塊,使用靈活、功能強大,適合復(fù)雜的業(yè)務(wù)場景,同時支持存儲過程訪問;
lua-resty-mysql實現(xiàn)數(shù)據(jù)庫查詢
1、準備好mysql服務(wù)
2、提前創(chuàng)建一張表
CREATE TABLE `users` ( `id` int(10) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL, `salary` double(10,2) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
并提前準備幾條數(shù)據(jù)
INSERT INTO `mydb`.`users` (`id`, `username`, `birthday`, `salary`) VALUES ('1', 'xiaowang', '1991-03-15', '9000.00'); INSERT INTO `mydb`.`users` (`id`, `username`, `birthday`, `salary`) VALUES ('2', 'xiaoma', '1992-07-15', '8000.00');
1、引入"resty.mysql"模塊
local mysql = require "resty.mysql"
2、創(chuàng)建MySQL連接對象
遇到錯誤時,db為nil,err為錯誤描 述信息
db,err = mysql:new()
3、創(chuàng)建連接對象
ok,err=db:connect(options)
options是一個參數(shù)的 Lua表結(jié)構(gòu),里面包含數(shù)據(jù)庫連接的相關(guān)信息
host:服務(wù)器主機名或IP地址
port:服務(wù)器監(jiān)聽端口,默認為3306
user:登錄的用戶名
password:登錄密碼
database:使用的數(shù)據(jù)庫名
4、設(shè)置子請求的超時時間(ms)
包括connect方法
db:set_timeout(time)
5、關(guān)閉當前MySQL連接并返回狀態(tài)
如果成功,則返回1;如果出現(xiàn)任 何錯誤,則將返回nil和錯誤描述
db:close()
6、異步向遠程MySQL發(fā)送一個查詢
如果成功則返回成功發(fā)送的字節(jié) 數(shù);如果錯誤,則返回nil和錯誤描述
bytes,err=db:send_query(sql)
7、從MySQL服務(wù)器返回結(jié)果中讀取一行數(shù)據(jù)
res返回一個描述OK包 或結(jié)果集包的Lua表
rows指定返回結(jié)果集的最大值,默認為4
如果是查詢,則返回一個容納多行的數(shù)組。每行是一個數(shù)據(jù)列的 key-value對
res, err, errcode, sqlstate = db:read_result() res, err, errcode, sqlstate = db:read_result(rows)
返回結(jié)果類似下面這樣
{ {id=1,username="TOM",birthday="1988-11- 11",salary=10000.0}, {id=2,username="JERRY",birthday="1989-11- 11",salary=20000.0} }
如果是增刪改,則返回類似如下數(shù)據(jù)
{ insert_id = 0, server_status=2, warning_count=1, affected_rows=2, message=nil }
返回值說明:
res:操作的結(jié)果集
err:錯誤信息
errcode:MySQL的錯誤碼,比如1064
sqlstate:返回由5個字符組成的標準SQL錯誤碼,比如 42000
具體操作案例
將下面的內(nèi)容添加到server塊,然后重啟nginx
location /mysql { content_by_lua_block{ default_type "text/html"; local mysql = require "resty.mysql" local db = mysql:new() local ok,err = db:connect{ host="127.0.0.1", port=3306, user="root", password="123456", database="mydb" } db:set_timeout(3000) db:send_query("select * from users where id =1") local res,err,errcode,sqlstate = db:read_result() ngx.say(res[1].id..","..res[1].username..","..res[1]. birthday..","..res[1].salary) db:close() } }
可以看到,通過訪問mysql這個路徑,成功查詢到數(shù)據(jù)庫中ID為1的這條數(shù)據(jù)
使用cjson對查詢結(jié)果進行格式化
從上面的返回結(jié)果來看,這種形式的返回數(shù)據(jù)在解析的時候其實并不是很友好,于是可以使用lua-cjson處理查詢結(jié)果
使用步驟
步驟一:引入cjson
local cjson = require “cjson”
步驟二:調(diào)用cjson的encode方法進行類型轉(zhuǎn)換
cjson.encode(res)
下面對上面程序模塊做簡單的改造
location /mysql-cjson { default_type "text/html"; content_by_lua_block{ local cjson = require "cjson" local mysql = require "resty.mysql" local db = mysql:new() local ok,err = db:connect{ host="127.0.0.1", port=3306, user="root", password="123456", database="mydb" } db:set_timeout(3000) db:send_query("select * from users") local res,err,errcode,sqlstate = db:read_result() ngx.say(cjson.encode(res)) for i,v in ipairs(res) do ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary) end db:close() } }
然后再次進行測試,這時候就以json的格式對數(shù)據(jù)進行了展現(xiàn)
增刪改操作
location /mysql-cjson { default_type "text/html"; content_by_lua_block{ local cjson = require "cjson" local mysql = require "resty.mysql" local db = mysql:new() local ok,err = db:connect{ host="127.0.0.1", port=3306, user="root", password="123456", database="mydb" } db:set_timeout(3000) -- 查詢操作 db:send_query("select * from users where id=1") -- 插入數(shù)據(jù) --local res,err,errcode,sqlstate = db:query("insert into users(id,username,birthday,salary) values(3,'lifei','1995-10-17',3000)") -- 修改數(shù)據(jù) --local res,err,errcode,sqlstate = db:query("update users set username='lisi' where id = 1") -- 刪除數(shù)據(jù) --local res,err,errcode,sqlstate = db:query("delete from users where id = 2") db:close() } }
讀到這里,這篇“nginx怎么集成lua操作mysql”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。