1. 程式人生 > >OpenResty的現狀、趨勢、使用及學習方法

OpenResty的現狀、趨勢、使用及學習方法

一.前言

我們都知道Nginx有很多的特性和好處,但是在Nginx上開發成了一個難題,Nginx模組需要用C開發,而且必須符合一系列複雜的規則,最重要的用C開發模組必須要熟悉Nginx的原始碼,使得開發者對其望而生畏。為了開發人員方便,所以接下來我們要介紹一種整合了Nginx和lua的框架,那就是OpenResty,它幫我們實現了可以用lua的規範開發,實現各種業務,並且幫我們弄清楚各個模組的編譯順序。關於OpenResty,我想大家應該不再陌生,隨著系統架構的不斷升級、優化,OpenResty在被廣泛的應用。

二.OpenResty執行原理

Nginx 採用的是 master-worker 模型,一個 master 程序管理多個 worker 程序,基本的事件處理都是放在 woker 中,master 負責一些全域性初始化,以及對 worker 的管理。在OpenResty中,每個 woker 使用一個 LuaVM,當請求被分配到 woker 時,將在這個 LuaVM 裡建立一個 coroutine(協程)。協程之間資料隔離,每個協程具有獨立的全域性變數_G。

ps. 協程和多執行緒下的執行緒類似:有自己的堆疊,自己的區域性變數,有自己的指令指標,但是和其他協程程式共享全域性變數等資訊。執行緒和協程的主要不同在於:多處理器的情況下,概念上來說多執行緒是同時執行多個執行緒,而協程是通過程式碼來完成協程的切換,任何時刻只有一個協程程式在執行。並且這個在執行的協程只有明確被要求掛起時才會被掛起。

原理圖如下:

三.OpenResty的優勢

首先我們選擇使用OpenResty,其是由Nginx核心加很多第三方模組組成,其最大的亮點是預設集成了Lua開發環境,使得Nginx可以作為一個Web Server使用。

藉助於Nginx的事件驅動模型和非阻塞IO,可以實現高效能的Web應用程式。

而且OpenResty提供了大量元件如Mysql、Redis、Memcached等等,使在Nginx上開發Web應用更方便更簡單。目前在京東如實時價格、秒殺、動態服務、單品頁、列表頁等都在使用Nginx+Lua架構,其他公司如淘寶、去哪兒網等。

四.Nginx和lua的簡介

1. Nginx:

(1) Nginx的優點

  • 輕量級同樣起web 服務比apache佔用更少記憶體及資源 

  • 抗併發nginx 處理請求非同步非阻塞而apache 則阻塞型高併發下nginx 能保持低資源低消耗高效能 

  • 高度模組化設計編寫模組相對簡單 

  • 社群活躍各種高效能模組出品迅速啊

(2) Nginx為什麼效能高,佔用記憶體少

眾所周知,nginx效能高,而nginx的高效能與其架構是分不開的。在這裡,我們簡單粗略的介紹一下nginx的架構。

  • 首先,nginx採用的是多多程序模式,好處是什麼呢?首先,對於每個worker程序來說,獨立的程序,不需要加鎖,所以省掉了鎖帶來的開銷,同時在程式設計以及問題查詢時,也會方便很多。其次,採用獨立的程序,可以讓互相之間不會影響,一個程序退出後,其它程序還在工作,服務不會中斷,master程序則很快啟動新的worker程序。當然,worker程序的異常退出,肯定是程式有bug了,異常退出,會導致當前worker上的所有請求失敗,不過不會影響到所有請求,所以降低風險。

  • Nginx是採用非同步非阻塞的方式去處理請求的,什麼是非同步非阻塞呢?其實就是當一個執行緒調用出現等待的io之類的情況時,而不是阻塞在這裡,而是去處理別的事情,等io準備好了,然後再去執行,具體的我就不在這裡和大家描述了。

2. lua:

(1) Lua 是一個小巧的指令碼語言。作者是巴西人。該語言的設計目的是為了嵌入應用程式中,從而為應用程式提供靈活的擴充套件和定製功能

(2) Lua的特點:

  • Lua指令碼可以很容易的被C/C++程式碼呼叫,也可以反過來呼叫C/C++的函式,這使得Lua在應用程式中可以被廣泛應用。不僅僅作為擴充套件指令碼,也可以作為普通的配置檔案,代替XML,Ini等檔案格式,並且更容易理解和維護。

  • Lua由標準C編寫而成,程式碼簡潔優美,幾乎在所有作業系統和平臺上都可以編譯,執行。一個完整的Lua直譯器不過200k,在目前所有指令碼引擎中,Lua的速度是最快的。這一切都決定了Lua是作為嵌入式指令碼的最佳選擇。

五.OpenResty的安裝

上面我門對OpenResty進行了簡單的介紹,執行原理的說明,還有Nginx、Lua優點的介紹,是為了更好的讓大家理解。讓大家知道用這個的好處,接下來我簡單的介紹一下OpenResty的安裝和搭建一個簡單的限流的例子,這是為了讓大家明白,除了上面說的好處,它到底能夠做什麼。

OpenResty的安裝:

(1) 需要事先安裝一下所需的外掛

1

yum install readline-devel pcre-devel openssl-devel

(2) 下載ngx_openresty-1.7.7.2.tar.gz並解壓 

1

wget http://openresty.org/download/ngx_openresty-1.7.7.2.tar.gz

(3) 安裝LuaJIT

1

2

3

cd bundle/LuaJIT-2.1-20150120/

make clean && make && make install

ln -sf luajit-2.1.0-alpha /usr/local/bin/luajit

(4) 下載ngx_cache_purge模組,該模組用於清理nginx快取

1

wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz

(5) 下載nginx_upstream_check_module模組,該模組用於ustream健康檢查

1

wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz

(6) 安裝ngx_openresty

1

2

3

4

5

6

7

8

9

cd /usr/servers/ngx_openresty-1.7.7.2

./configure 

--prefix=/usr/servers 

--with-http_realip_module  

--with-pcre  

--with-luajit 

--add-module=./bundle/ngx_cache_purge-2.3/ 

--add-module=./bundle/nginx_upstream_check_module-0.3.0/ -j2

make && make install

(7) 到/usr/servers目錄下,會發現多出來瞭如下目錄,說明安裝成功

(8) 啟動nginx:/usr/servers/nginx/sbin/nginx(其實我們可以配置好系統的環境變數,配置好後就可以直接資料nginx命令了)

六.防刷(黑白名單)簡單例子的搭建

1. 首先我們先可以在/usr/servers/nginx/conf/ 目錄下建立我們自己的一個簡單的lua檔案,就叫做example.lua好了。

輸入如下命令,我們就可以建立一個example.conf檔案,或者我們可以cp nginx.conf  example.conf 或者mkdir example.conf

2. 接下來我們需要編輯nginx.conf這個啟動配置的檔案了

ok,我們進入到編輯介面,接下來我們需要將我們的example.conf檔案給引入進來,在nginx.conf的http體裡新增一下命令:include example.conf

nginx.conf 的具體內容如下:

其中大家可以看到用紅線框框的是自己專案檔案的引入和lua模組的引入。

3. 接下來我們可以在example.conf檔案中寫我們的邏輯實現了

4. 我們可以看到,在example.conf中的server裡面配置多個location,而location中嵌入了content_by_lua_file  /usr/example/lua/redis_black_limit.lua,從這可以看出在content階段嵌入了lua指令碼,進行了內容的響應,在這裡,我們進去看看相應的程式碼是如何來處理的:

這是一個防刷的demo,從中我們可以看出,我是更具ip,從redis裡面取值,然後通過請求ip的匹配,來做到防刷的功能,除此之外,這裡有一個語句,我們的注意到,那就是require,這就相當於我們的類載入器,class.forname,從而做到載入進來lua的模組。

5. 除此之外,還簡單的做了一個設定黑名單和取消黑名單的功能,用來充當我們以後的管理中心,具體邏輯寫在set_black.lua和cancel.lua中,然後在lua.conf中配置好url,具體如下圖所示:

在lua.conf中server體里加入一下程式碼:

接下來我們需要寫set_black.lua和cancel.lua檔案,檔案內容如下:

1

2

3

4

5

6

7

8

9

10

11

12

v  set_black.lua:

local redis =require "resty.redis"

local cache =redis.new()

cache:set_timeout(6000)

local ok,err=cache.connect(cache,'192.168.150.61',6379)

if not ok then

ngx.say("failed to connect:",err)

return

end

local ip = ngx.var.remote_addr

cache:set("user:"..ip..":block",1)

ngx.say("user:"..ip..":block".."設定黑名單成功")

1

2

3

4

5

6

7

8

9

10

11

12

v  cancel_black.lua:

local redis =require "resty.redis"

local cache =redis.new()

cache:set_timeout(6000)

local ok,err=cache.connect(cache,'192.168.150.61',6379)

if not ok then

ngx.say("failed to connect:",err)

return

end

local ip = ngx.var.remote_addr

cache:expire("user:"..ip..":block",0)

ngx.say("user:"..ip..":block".."移除黑名單")

7. 效果

做好了以上配置,我們可以開始先設定好黑名單,然後訪問請求,返回的結果是被黑名單了,然後再取消黑名單,再訪問請求,顯示訪問成功,具體結果如下圖。

七.總結

上文簡單的介紹一些OpenResty,以及搭建了一個簡單的應用,目的是想讓大家對這個框架有一個大體的瞭解。隨著架構的升級,我們會慢慢的把一些不太複雜的業務可以移到nginx層,從而提高我們的吞吐量,解決一些效能上的瓶頸。例如在nginx這一層做簡單的限流、黑白名單,快取之類的業務複雜性不是太強的工作,從而增加我們的吞吐率,也可以再nginx這一層過濾掉一些垃圾流量,從而讓tomcat層只需要更加專注於業務。(以上是我簡單粗略的一些理解,如果有什麼問題,歡迎大家一起討論)

轉載請並標註: “本文轉載自 linkedkeeper.com (文/曾昌榮)”