1. 程式人生 > >我們能用 lua 做什麼

我們能用 lua 做什麼

640?wx_fmt=gif&wxfrom=5&wx_lazy=1

女主宣言

lua 是一個巴西人設計的小巧的指令碼語言,它的設計目的是為了能夠嵌入到應用程式中,從而為應用程式提供靈活的擴充套件和定製功能。今天我們邀請到 360 高階開發工程師李鋼帶我們快速入門 lue。本文最先發佈於 opsdev,轉載已獲取作者授權。 

PS:豐富的一線技術、多元化的表現形式,盡在“HULK一線技術雜談”,點關注哦!

前言

作為web開發工程師,我們平時主要使用的開發語言是php。這個語言提供了對html模版的強大的處理能力,也提供了十分豐富的函式庫及擴充套件,非常的適合web開發使用。那麼lua是如何進入到我們的視線中的呢?在這裡我先說下我在開發一個web產品時,會優先考慮的幾個問題:

  1. 如何保證服務的穩定性,即如何防止白屏、50x錯誤的發生。

  2. 如何提高頁面的響應速度,即讓使用者感覺頁面開啟足夠快。

  3. 那麼在用php解決這幾個問題時,是否夠用呢?

答案在我看來是否定的,為什麼這麼說呢?請聽我分別道來:

1

php在處理服務穩定性時的不足

先簡單說下由php導致的服務異常原因:

  1. php語法錯誤、執行時的異常都會導致500錯誤,這在使用者端瀏覽器就會顯示出白屏。

  2. 在使用nginx + php-cgi這種組合提供動態web服務時,當後臺cgi程序掛掉或數量不夠用時,即會產生502錯誤;當php執行時遭遇阻塞(如連db時,db壓力過大),而在nginx中配置的超時時間到達後,通常會產生504錯誤。

這幾種異常本身都是由於php導致的,當然不能靠php去解決。

webserver如nginx提供瞭如error_page這種用於處理當服務產生異常時的後續處理機制,為了不讓使用者看到白屏或錯誤頁面,我們可以定時對正常服務時的頁面做一個快照,當遇到服務異常時,就給使用者這個歷史快照看。

但這樣做也有個侷限性:當你提供服務的頁面很多時,又或是需要根據請求的引數做一些邏輯上的處理時,顯然就很難做到了。

你也許會說,我可以寫nginx配置,讓它分析請求引數,再做相應的邏輯處理。但是這樣做的話,想想看你的nginx配置會有多麼的複雜,多麼的難以維護,而且就算你這樣做,也不能解決所有的問題。比如說我有個介面要輸出json字串,或是其它別的格式,你總不能說我再去寫個nginx擴充套件讓它支援json吧。

所以,在提高服務的穩定性方面,我們的需求是:

  1. 能用到webserver提供的錯誤處理機制。

  2. 能方便的處理請求引數,做需要的邏輯處理。

2

php在提高使用者響應速度方面的不足

php是一個阻塞式順序執行的指令碼語言,雖然支援多程序執行,但這種模式並不適合使用在併發量很高的web服務中。

想像如果一個請求的處理過程中,你需要呼叫到多處外部資源或服務(db、rest介面),那麼你的處理速度就要依賴於這些外部服務,而且是一個一個順序處理的,它們越多,處理就越慢。

php的multi_curl可以用來併發請求這些外部的rest服務,但這樣做的話,依舊需要等全部的請求都處理完成,才能返回給使用者。換句話說,如果某個外部服務很慢,那麼使用者看到頁面開啟依舊會很慢。

也可以選擇把頁面分塊,讓慢的部分用js非同步請求載入。但這樣做的話,會增加伺服器的訪問量,每增加一塊,訪問量會增大一倍。

所以,在提高頁面的響應速度方面,我們的需求是:

  1. 耗時慢的服務能夠做到非同步載入,服務端每完成一部分的計算,就讓頁面展示這部分。

  2. 不能過大的增加伺服器的壓力。

3

nginx-lua模組

最終,我們找到了nginx-lua?模組。這個模組會在每個nginx的worker_process中啟動一個lua直譯器,在nginx處理http請求的11個階段中,你可以在其中的多個階段用lua程式碼處理請求。

這二者的結合,給我們的web開發帶來了新的思路。下面我就來說下導航目前是如何使用它來解決問題的。

4

解決服務穩定性

這裡的思路很簡單,我們會在error_page指令被執行後,用lua程式碼來接受引數,處理邏輯部分,最終會返回前端和用php處理看起來一致的內容。部分程式碼如下:

nginx_conf:

640?wx_fmt=jpeg

這裡大家看到,當請求出現50x錯誤時,會跳到location jump_to_error_page_api中,在這裡面,content_by_lua_file指令會在content處理階段啟動指定好的lua指令碼(這裡是error_page_api.lua)來處理請求。我們再看下lua指令碼中都做了什麼:

lua example:

640?wx_fmt=jpeg

這裡大家可以看到,我們可以在lua指令碼中接受請求引數,做和php一樣的邏輯,最終輸出前端需要的正確的內容。

目前這套機制我們已經用在我們這邊的一個重要使用者頁面上,目前都沒有收到使用者反饋說頁面打不開,出現錯誤頁這種,效果很是明顯。

5

提高使用者頁面的響應速度

上面提到的解決響應速度的幾個需求,我們的思路是引入bigpipe的處理機制。關於bigpipe本文不做講解,大家可以自行google。這個專案目前尚處於實驗階段,但我們已經實現了一個簡單的demo:

nginx_conf:

640?wx_fmt=jpeg

這裡指定請求index.php會用bigpipe_index.lua處理。

lua example:

640?wx_fmt=jpeg

這裡在處理請求時,大致邏輯如下:

  1. 首先會先吐出首屏html部分及部分html框架程式碼。

  2. 接下來會啟動3個lua協程,在nginx-lua這個模組的排程下以非同步非阻塞的模式併發的來處理3個外部請求。

  3. 這3個外部請求各自的延時不同,但是任何一部分處理完成,都會直接返回給前端用於展示。

通過這種方式,使用者的頁面響應速度得到了明顯的提高,體驗更好。

6

結束語

正如lua官方給出的定義所說,lua很小巧,非常的適合嵌入已有的應用程式中,從而補足現有系統的一些缺憾,並擴展出新的功能。對nginx-lua模組的使用,筆者也還在研究中,但我相信更好的使用它,能為我們現有的web開發開啟一扇新的窗戶,理解更深層次的知識。

參考資料:

[1] https://www.lua.org/

[2] https://github.com/openresty/lua-nginx-module

HULK一線技術雜談

由360雲平臺團隊打造的技術分享公眾號,內容涉及雲端計算資料庫大資料監控泛前端自動化測試等眾多技術領域,通過夯實的技術積累和豐富的一線實戰經驗,為你帶來最有料的技術分享

640?wx_fmt=gif