背景介紹
在專案開發中,先前經手的一個服務是在redis中存放著產生好的數據,客戶端透過具體的key來獲取redis中的具體數據。在先前的開發中是採用了nginx+wsgi+python的架構方案。透過python也可以快速的實作項目,推送到測試環境也一直在使用當中。
隨著時間過去,慢慢對專案思考,發現其實這種實現方式也有一定的弊端。因為,對於服務來說沒有複雜的邏輯,nginx接受到請求轉發到後台python服務;然後python服務拿到具體請求到redis中取出資料然後返回給客戶端呼叫。整個流程其實比較簡單而且明確,沒有必要在nginx和redis中間再增加一層python的服務,所以在思考這種架構的實作方案是不是可以在優化一點。
nginx與lua
後來經過簡單的搜尋nginx+redis發現一些nginx+lua+openresty相關的關鍵字。接下來就是對openresty開始研究。查看相關文件發現,openresty是一個整合了nginx核心模組與各種第三方模組的一個專案集。如果使用openresty,那麼就避免了額外各種安裝第三方包,它全部都繼承到它的安裝包裡面。這對懶人來說絕對是個不錯的選擇。
lua介紹
lua是一個腳本語言,也有另一個稱呼-膠水語言。它是一個非常小的、可以和其他語言非常容易耦合在一起的語言。透過lua自己的特性,再加上他依附的語言,在一個服務裡利用兩種語言的特性,功能肯定不是一般的強大。看到一些牛B的遊戲中都有在使用lua做一種膠水型的功能型語言。
不過透過簡單使用,發現lua對字串的處理不夠強大,因為它是直接使用C庫,它對字串的處理也只是C庫提供的接口,沒有對接口進行額外的豐富和補充。在很多場景下,需要自己實作一些常用的接口,像是split等。
整合lua與ngxin
因為看到lua是一種膠水類型的語言,那麼lua是否可以直接耦合在nginx中?答案是非常肯定的。 lua可以直接運作在nginx中,做一些邏輯的處理、日誌的控制。那我們就可以考慮使用nginx+lua來開發一個web服務來滿足需求,去完成其他服務端語言不能完成的便利和快速開發。
除了上述說的遍歷性之外,nginx+lua還會帶來什麼優勢:
1.減少一層轉發 ,使用其他服務語言來開發服務,肯定會使用一種協定在nginx和服務端直接進行通訊。如cgi、fcig、wsgi等。如果使用lua,因為lua是直接運行在nginx中,就麼有必要再額外做一次nginx轉送。
2.基於事件的回應,因為lua是直接運作nginx的運行時環境,那麼lua就繼承了nginx的所有特性。在一般情況下,nginx都是基於事件的提供服務,select或epoll。在性能上一定會灰常給力的。
基於以上原因開搞nginx+lua。因為是懶人直接採用了整個安裝openresty的策略,當然也可以單獨安裝nginx,再安裝lua,然後nginx_lua_module。安裝了openresty之後,開始寫簡單的測試,其實在openresty的github上也有相關的例子,可以對著例子直接做一些簡單的測試開發。
做完第一步的安裝和測試範例的編寫,lua+nginx就表示已經整合成功,接下來就是自己業務邏輯的開發。這裡要注意的是因為openresty其實也是整合了nginx,所以在一台機器上跑兩個nginx可能有對應的問題,所以在安裝openresty之後,機器上已有的nginx可能會有一定影響。
升級原服務
開發環境已經配置好,接下來就是直接開發業務邏輯,也就是接受到請求存取redis,讀取資料回傳客戶端請求。因為lua是可以直接寫在nginx的設定檔中的,但這不是一個很好的策略。雖然lua就是和別的語言直接耦合在一起,但耦合的程度也要考慮軟體工程相關問題。例如後期程式碼的可維護性,nginx設定檔的可讀性。
鑑於以上原因也是建議lua的功能實作寫入單獨文件,然後在nginx設定檔中透過聲明的方式,告知nginx進行載入和運行。在實現功能的基礎上,盡量避免耦合的程度和程式碼的可維護性。
在具體的實作中,兩個文件搞定整個服務,當然也是因為服務本身簡單。
-redis.conf #redis的host、port
-init.lua #初始化設定檔
在實作中利用了nginx的共享記憶體的概念。
<code><span>--redis.conf</span> host:<span>127.0</span><span>.0</span><span>.1</span> port:<span>6379</span><span>--init.lua</span> tmp = {} <span>for</span> l <span>in</span> io.<span>lines</span>(<span>"lua/redis.conf"</span>) <span>do</span><span>for</span> i <span>in</span><span>string</span>.gmatch(l, <span>"([^:]+)"</span>) <span>do</span> table.insert(tmp, i) <span><span>end</span></span><span><span>end</span></span> ngx.shared.config:<span>set</span>(tmp[<span>1</span>], tmp[<span>2</span>]) ngx.shared.config:<span>set</span>(tmp[<span>3</span>], tmp[<span>4</span>])</code>
在這裡需要在nginx啟動的時候就進行redis.conf的讀取,所以在nginx中需要加上一句配置告知nginx啟動的時候需要執行init.lua。另外,也要宣告nginx的共享記憶體config,所以nginx的配置如下
<code>lu<span>a_shared</span>_dict config <span>1</span>m<span>;</span> init_by_lu<span>a_file</span> 'lua/init.lua'<span>;</span></code>
第一步已经完成,就是redis相关配置的读取,共享内存的声明和初始化,那接下来就是具体的逻辑实现,几十行代码分分钟搞定。
<code> location /vector{ content_by_lua ' <span>local</span> redis = require <span>"resty.redis"</span><span>local</span> server = redis:new() <span>local</span> conf = ngx.shared.config <span>local</span> ok, err = server:connect(conf:<span>get</span>(<span>"host"</span>), conf:<span>get</span>(<span>"port"</span>)) ngx.header.content_type = <span>"text/plain"</span><span>if</span><span>not</span> ok <span>then</span> ngx.<span>log</span>(ngx.ERR, err) ngx.<span>exit</span>(ngx.HTTP_SERVICE_UNAVAILABLE) <span>end</span><span>local</span> x = ngx.var.arg_x; <span>local</span> y = ngx.var.arg_y; <span>local</span> z = ngx.var.arg_z; <span>if</span> x == nil <span>or</span> y == nil <span>or</span> z == nil <span>then</span> ngx.<span>say</span>(<span>"{\\\"ret\\\": -1}"</span>) ngx.<span>exit</span>(ngx.HTTP_SERVICE_UNAVAILABLE) <span>end</span><span>local</span> key = z..<span>"_"</span>..x..<span>"_"</span>..y <span>local</span> data = server:<span>get</span>(key) '; }</code>
版权声明:本文为博主原创文章,转载请注明来源。
以上就介绍了nginx中集成lua开发web服务,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。