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

溫銘,奇虎 360 企業安全服務端架構師,OpenResty 社區諮詢委員會成員。一直在互聯網安全公司從事服務端的開發和架構工作,致力於用互聯網技術幫助企業提高安全防護。曾負責開發過***雲查殺和反釣魚系統。

  1. OpenResty 是什麼,適合什麼場景下使用
    和大部分知名開源軟件誕生在歐美國家不同,OpenResty 自身和依賴的主要組件都是金磚國家的開發者發明的,這點還挺有意思。

Nginx 是俄羅斯人發明的, Lua 是巴西幾個教授發明的,中國人章亦春把 LuaJIT VM 嵌入到 Nginx 中,實現了 OpenResty 這個高性能服務端解決方案。

通過 OpenResty,你可以把 nginx 的各種功能進行自由拼接, 更重要的是,開發門檻並不高,這一切都是用強大輕巧的 Lua 語言來操控。

它主要的使用場景主要是:

在 Lua 中揉和和處理各種不同的 nginx 上游輸出(Proxy,Postgres,Redis,Memcached 等)

在請求真正到達上游服務之前,Lua 可以隨心所欲的做複雜的訪問控制和安全檢測

隨心所欲的操控響應頭裏面的信息

從外部存儲服務(比如 Redis,Memcached,MySQL,Postgres)中獲取後端信息,並用這些信息來實時選擇哪一個後端來完成業務訪問

在內容 handler 中隨意編寫複雜的 Web 應用,使用 同步但依然非阻塞 的方式,訪問後端數據庫和其他存儲

在 rewrite 階段,通過 Lua 完成非常複雜的 URL dispatch

用 Lua 可以爲 nginx 子請求和任意 location,實現高級緩存機制

組織 OpenResty 技術大會之前,我一直認爲自己是一個孤獨的 OpenResty 使用者,覺得自己在使用一個冷門的技術。

雖然大家都聽說過 OpenResty 或者 ngx_lua,但感覺用在生產環境中使用的卻少之又少,除了幾個 CDN 公司外,好像沒有聽說過哪家知名互聯網公司在使用。而 CDN 行業之所以使用,很多是受到 cloudflare 技術棧的影響,OpenResty 的作者也在國外這家 CDN 公司。

但辦完這個大會,我發現使用者真的挺多,奇虎360的所有服務端團隊都在使用,京東、百度、魅族、知乎、優酷、新浪這些互聯網公司都在使用。有用來寫 WAF、有做 CDN 調度、有做廣告系統、消息推送系統,還有像我們部門一樣,用作 API server 的。有些還用在非常關鍵的業務上,比如開濤在高可用架構分享的京東商品詳情頁,是我知道的 ngx_lua 最大規模的應用。

  1. 奇虎企業安全服務端技術選型的標準

先說下 3 年多前做架構選型的時候,我爲什麼會選擇 OpenResty?

其實架構如何設計並不重要,因爲每家公司,每個團隊,他們的公司文化和技術背景各不相同,生搬硬套會適得其反。重要的是當初爲什麼這麼選擇,中途爲什麼調整。

我們的產品要求單機上面,服務端提供高性能的 API 接口, QPS 至少過萬,未來需要支撐到 10 萬。我們並沒有急於去使用 PHP 、 Python 或者其他的語言來實現功能,而是先勾勒出一個理想化的技術模型。

這個模型應該具備:

非阻塞的訪問網絡IO。在連接 MySQL 、Redis 和發起 HTTP 請求時,工作進程不能傻傻的等待網絡IO的返回,而是需要支持事件驅動,用協程的方式讓 CPU 資源更有效的去處理其他請求。很多語言並不具備這樣的能力和周邊庫。

有完備的緩存機制。不僅需要支持 Redis 、Memcached 等外部緩存,也應該在自己的進程內有緩存系統。我們希望大部分的請求都能在一個進程中得到數據並返回,這樣是最高效的方法,一旦有了網絡IO和進程間的交互,性能就會受到很大影響。

同步的寫代碼邏輯,不要讓開發者感知到回調和異步。這個也很重要,程序員也是人,代碼應該更符合人的思維習慣,顯式的回調和異步關鍵字,會打斷思路,也給調試帶來困難。

最好是站在巨人肩上,基於成熟的技術上搭建。採用一門全新誕生的語言和技術,需要經歷語言自身發展期頻繁調整的陣痛,還可能站錯隊。

不僅支持 Linux 平臺,還需要支持 Windows 平臺,這個是我們產品很特別的需求,很多中小企業用戶還是習慣 Windows 的操作,不具備 Linux 的維護能力。

基於以上幾點的考慮,考察了當時的一些方案,選擇了 OpenResty 。

首先,它最大的特點就是用同步的代碼邏輯實現非阻塞的調用,其次它有單進程內的 LRU cache 和進程間的 share DICT cache,而且它是揉合 nginx 和 LuaJIT 而產生的。而且 nginx 有 Windows 版本,雖然有非常多的限制,但這些限制都是可以解決的, nginx 官方 Windows 版本中不支持的特性,我們開源出來的版本都解決了。

第一次看到這樣的方案,我覺得它肯定會顛覆高性能服務端的開發。爲什麼呢?在我之前的公司裏,每天會有近百億次的查詢請求,而服務器只用了十臺。

我們採用了 nginx C 模塊 + 內置在 nginx 中的 K-V 數據庫(自己開發的),來實現所有的業務邏輯,達到這個目標。聽上去很簡單,但是過程非常艱辛,兩三個十幾年工作經驗的大牛做了一年多才穩定下來。絕大部分開發能力不足,只能望塵莫及。而且後續的調試和維護,也會花費不少精力。

但是 OpenResty 的出現改變了這一切, OpenResty 非常的 pythonic ,適合人類的正常思維。新手經過一兩個月的學習,做出來的 API, 就可以達到 nginx C 模塊的性能,而且代碼量大大減少,也方便調試。

  1. 以奇虎和新浪爲例,如何在項目中引入新技術

技術選型只是第一步,如何才能在一個產品或者項目中引入 OpenResty 這個新的技術呢?我拿奇虎企業安全和新浪移動這兩家公司真實發生的案例給大家看看。我和新浪移動的周晶,都是在一個有成熟產品的部門,用一兩個人的力量,把一個新技術,替換掉了原有的技術架構。但由於企業產品和個人產品的不同,方法有很大的不一樣。

先說我所在奇虎企業安全。我在 2012 年初加入這個部門,當時產品主打免費,目標用戶是小企業。所以架構設計上面,只考慮了幾十點、幾百點的終端請求,使用了非常強綁定的 Windows 平臺技術,而且傾向於不用開源軟件,自己新做一個更適合自己的框架。包括自己用 C++ 開發的 Web server,自己寫的 PHP 路由和框架,數據存儲在 sqlite 裏面。

我幫忙修改了兩個月 PHP 的 bug,看明白了技術架構的思路之後,就去新開的一個產品線了。這是一個實驗性的產品,主要面對央企和專用網,一個網絡中有上百萬的終端。

剛開始沒有什麼人關注,我就直接採用了 Linux + OpenResty + Redis + Postgres 的開源組件,性能測試甩之前的N條街。後面這個實驗性的產品,和之前的產品,合併爲一個產品,技術上面就割裂爲兩套架構。老功能用老架構,新功能用新架構。

隨着越來越多大用戶的增加,原有的技術架構開始捉襟見肘,技術債務越積壓越多。隨着用戶的抱怨,sqlite 被拋棄,全面換成 Postgres。但對於自己開發的框架還是有些敝帚自珍。

期間通過對比測試、OpenResty 培訓還有多次用戶性能問題排查,讓開發同學們都知道這門技術的優勢。快被加班壓垮的開發同學,逐漸開始選擇使用 OpenResty 而不是自研的框架,來進行新功能的開發,以及舊功能的遷移,來避免加班。

在產品重構的時候,之前自研的服務端框架被完全拋棄,服務端開發的同學從 8 、9 個人減少到 3 個人。在新技術的引入過程中,我們沒有采用強制的舉措,因爲企業產品需要穩定,用戶處部署的版本更新很慢。

而新浪移動周晶的實踐,對大家更有參考意義。新浪移動最開始是基於 Apache,用 PHP 來處理用戶請求。Apache 是同步多進程模型,在併發請求不多的情況下沒有問題。

但是總是會有突發新聞,比如馬航失聯、文章×××等,突發的高流量把後臺壓垮了幾次。而且可以預見世界盃的流量也會很大,所以周晶花幾個月時間,用 nginx 替換了 Apache,使用 nginx 的 fast_cgi_cache,QPS 提升了一個數量級。

新浪移動後臺的接口都是使用 PHP 來實現的,在高併發下有些力不從心。而 nginx 簡單的緩存雖然能滿足性能,但不能滿足業務精細化和數據一致性的要求,需要找 PHP 之外的解決方案,前提是讓 PHP 的開發能夠舒適的使用。 node.js 的回調地獄、Go 的調試不方便,都是一個阻礙。

他們最後選擇了 OpenResty,而且基於 OpenResty 開源了一個 Web 框架 Vanilla(香草),模仿了 Yaf 的使用習慣,讓 PHP 的開發更容易接受和上手。 Vanilla 已經在新浪移動開始使用,一些核心業務,比如高清圖和體育直播,正在向這個框架遷移中。

  1. 入門痛點,以及學習的正確方法

我和周晶的入門,都是自己摸着石頭過河。當時除了 Python 社區「大媽」的那篇使用文章外,找不到其他的資料。

奇虎和新浪都用 OpenResty 成功替換了之前的技術,但問題還是挺明顯,就是大家都認爲自己是孤獨的使用者,同事中基本沒有人認同。在關鍵和支撐業務上,使用 OpenResty 有些不放心,都會在邊緣業務上先做嘗試和驗證。

雖然 OpenResty 的性能做的很棒,比肩或者超過其他所有的高性能解決方案,但是擔心沒有學習資料、擔心招不到人、擔心沒人交流,可能還擔心作者章亦春哪天撂挑子不幹了,這個項目就黃了。

高可用架構羣裏的各位都是架構師,是技術決策者,在引入一門新技術的時候,肯定會考慮到這些風險。比如小米科技馬利超在高可用架構的分享,他們在搶購系統中曾經使用過 ngx_lua,雖然性能滿足需求,但是團隊裏面熟悉的人少,最後還是改成了 Go 語言實現。

如何解決這些擔憂? 社區是有過思考和討論的,我們放在分享最後講。先從一個嘗試使用這門技術的開發者的角度看,OpenResty 不少基礎工作沒有完善,友好程度不夠:

只能從源碼安裝,沒有 apt-get、brew 等軟件倉庫安裝方法;安裝第三方庫沒有 PIP、NPM 之類的包管理工具,需要去先谷歌,然後拷貝代碼文件到指定的目錄下,才能 require 使用。

代碼編寫需要修改 nginx.conf 和對應的 lua 代碼,即使是 hello world 也是如此。當然你可以把代碼寫在 nginx 的配置文件裏面,但是生產環境肯定是要分離的。這種編寫代碼的方式,不像是一個編程語言,和常規的編程方式不同。

有獨特的執行階段概念,因爲 OpenResty 是基於 nginx 的,所以也繼承它的這種概念。你的代碼邏輯,可能需要放在不同的階段裏面運行,才能獲取你想要的預期。而這些階段間信息如何傳遞,以及哪些 API 不能在某些階段使用,就會經常攔住新手。

遇到問題只有郵件列表這一種方式來溝通,而郵件列表是被牆的。文檔也只有英文版本,導致很多新手的問題無法被解決。

沒有系統學習 OpenResty 的手段,大都是業務需要實現什麼功能,就去文檔和 API 裏面去找。至於方式對不對,能不能優化,就不知道了。

而 Lua 語言自身也有一些特別的地方:

下標從 1 開始,這個是和其他編程語言很大的不同。

不區分 array 和 dict ,會導致處理 json 的時候,無法區分 array 和 object。

默認全局變量,需要在所有變量前加 local,忘記的話,可能導致各種難查的 bug。

自帶的字符串正則匹配規則和通常的 PCRE 不同,使用的話,學習成本較高。

Lua 標準庫和周邊庫,都是阻塞的,需要自己甄別哪些可以和 OpenResty 搭配使用。新手很容易使用了阻塞的庫,而導致性能急劇下降。

有沒有好的入門方法?

我們團隊正在做這方面的努力,儘量在現有的基礎上,降低學習的門檻。 對於新手,可以看 StuQ 上面 OpenResty 的系列視頻教程 (http://www.stuq.org/course/detail/1015),我們計劃有 4 季,分別是入門、進階、實戰和源碼分析。現在第一季已經上線,第二季正在後期製作。看完前兩季,基本上就可以在項目裏面用了。

對於已經使用了 OpenResty 的開發者,我們把這兩三年遇到的坑,都記錄在 GitHub 的《OpenResty最佳實踐》上面(https://github.com/moonbingbing/openresty-best-practices),大家可以當做 cookbook 來使用。

  1. nginScript 這樣的嘗試會替代 OpenResty 嗎?

nginScript 是今年 nginx 大會上,Nginx 官方推出的一個新的配置語言。它是模仿了 OpenResty 的做法,把 JavaScript VM 嵌入到 nginx 中,提供簡單的 nginx 配置功能。

我們看下它的 hello world:

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

再對比下 OpenResty 的 hello world:
OpenResty的現狀、趨勢、使用及學習方法

看上去差不多,只是 OpenResty 簡潔一些。根據 nginx 官方的說明,nginScript 只是想提供一種更方便配置 nginx 的方法,並不想取代 ngx_lua。

考慮到 JavaScript 本身的流行和開發社區的強大,如果未來兩三年它從一個簡單的 nginx 配置語言,逐漸演變成類似 ngx_lua 這樣功能非常完備的開發語言,甚至替代 OpenResty 也是有可能的。

當然,這個前提是 OpenResty 停滯不前。現在 OpenResty 已經有的功能,和計劃開發的功能,傾向於覆蓋 nginx Plus 的功能。所以 nginx 和 OpenResty 之間,有一個良性的競爭關係,這是大家都樂意看到的。

6 未來重點解決的問題和新增特性

短期內的目標,是想降低入門的難度:

提供官方二進制發佈包。類似於 docker 的安裝方法,一行命令,下載一個sh腳本,增加一個源地址,不用手工解決依賴,不用源碼編譯,直接就可以試用。
而且會發布 Windows 的二進制包,方便這個平臺的開發者本機做一些測試。

增加包管理。命令行工具叫 iresty,可以從 iresty.org 上面搜索、安裝需要的 lua resty 庫,避免找錯庫或者放錯目錄。

寫一本書《 OpenResty 編程》,這本書會成爲官方的入門書籍,框架和關鍵內容由作者春哥直接操刀,我和社區的其他同學幫助一起完成。

做完上面3點,OpenResty 的入門難度會降低到和其他編程語言一樣。

在功能上面,會增加很多激動人心的新特性:

支持 TCP 和 UDP 。Nginx 最新的 stream 子系統已經支持了 TCP,OpenResty 的 ngx_stream_lua 模塊正在開發中,會擁有和現有的 nginx http modlue 相同的 lua API,所以很多應用和庫,可以不加修改的運行在一個新的子系統上面。

更好的支持推送場景。增加 shared list 共享內存的隊列,可以用於 worker 間的通訊;增加 semaphore 特性,用於 ngx_lua 輕量級線程間的通訊。酷狗音樂的推送服務就是基於這些實現的,這些改動點會在這個月併入 master。可以邀請酷狗音樂的同學,來給大家詳細分享下里面的細節。

建立一個開源的 WAF 平臺。現在阿里雲和 cloudflare 的 WAF 做的都很棒,經受住了很多實際的考驗。但是都沒有開源,我們希望最好的 WAF 是開源的,而且是基於 OpenResty 的。

在 OpenResty 中增加內存數據庫。可以有持久化,或者就是全內存的,支持 SQL 的查詢。這個也是出於極致性能的考慮,有時候我們還是需要使用 SQL 來做一些複雜的查詢,但有不想使用那麼重的關係型數據庫,而且數據是可以丟失的。那麼這個就可以排上用場。

實現 PHP、Python 等方言,讓 PHP、Python 等程序員可以用自己喜歡的語言寫 OpenResty 的代碼,底層轉換爲 LuaJIT 的字節碼。

春哥在 OpenResty 技術大會上面說了非常多的新特性,包括 streaming RegEx 正則引擎等等,非常高端,我挑了幾個我覺得有意思的做介紹。

  1. 開源社區建設
    OpenResty 誕生於 2011 年,大多數時間都是春哥主力在維護這個項目,當然也有很多開發者提交 feature 和 bugfix ,但基本上算單打獨鬥。

社區有 github 和郵件列表,大部分還是提問的。春哥每天會花費很多的時間,來詳細的回答各種基礎問題。

今年新增了 QQ 羣和微信羣, QQ 羣的質量很高,每天都會有很多提問,非技術問題是被禁止的。而且還有了自己的技術大會,能給大家面對面交流的機會。

我們翻譯了 ngx_lua 的英文文檔,能讓大家更方便的查找資料;我們搭建了一個不用×××就能訪問的論壇: bbs.iresty.com,用作提問和知識積累的地方。後面會把谷歌郵件列表的內容同步過來。

只有上面這些是不夠的,在 OpenResty 技術大會的第二天,我們召集了一個很小規模的閉門會議,決定成立 OpenResty 諮詢委員會。

這個委員會,是以個人名字參加的,成員來自奇虎 360、新浪、又拍雲、酷狗音樂等公司和社區的開發者,希望把國內社區的核心使用者和開發者團結在一起,促進 OpenResty 的發展。

同時,OpenResty 軟件基金會也開始籌備工作,我們希望走規範的非盈利組織的模式,來保證 OpenResty 長期穩定發展。給開發者和使用者信心,敢於在關鍵業務上面使用 OpenResty。

Q & A

1、請問 OpenResty 的定位是什麼,從分享來看似乎全棧了?

定位主要是高性能,所有的新功能和優化,都是針對性能的。 但是也有人拿來做頁面,比如京東;也有人拿來替代 PHP 做 Web server,比如新浪。 我覺得它越來越像一個獨立的開發語言。

2、請問 Lua 是不是可以實現動態配置 location?比如動態切流量?
balancer_by_lua 可能是你需要的,你可以用 Lua 來定義自己的負載均衡器,可以在每個請求的級別上去定義,當前訪問的後端的節點地址、端口,還可以定製很細力度的訪問失敗之後的重試策略。

3、OpenResty 是可以拿到 nginx 請求裏面的所有信息?那是不是可以做一些更復雜的轉發操作?能介紹一下 OpenResty 在 cdn 裏面的應用場景嗎?

可以看下 iresty.com 的分享,又拍的張聰非常詳細的介紹了 OpenResty 在又拍 CDN 的使用。

4、OpenResty 是否修改了 nginx 的源碼,還是和 nginx 完全可剝離開的?Nginx 版本升級,OpenResty 也跟着升級嗎?例如 nginx 修復漏洞 bug 等情況。

OpenResty 不修改 nginx 的源碼,可以跟隨 nginx 無痛升級。 如果你覺得 OpenResty 升級慢了, 你可以只拿 ngx_lua 出來,當做 nginx 的一個模塊來編譯。實際上,OpenResty 在測試過程中,發現了很多 nginx 自身的 bug 。

5、軟 WAF nginx + Lua 是主流和未來方向麼?

我覺得 WAF 應該基於 nginx,不管是性能還是流行程度。而 OpenResty 具有更靈活操控 nginx 的能力,所以我覺得 OpenResty 在 WAF 領域非常合適。cloudflare 的 WAF 就是基於 OpenResty。

6、看樣子未來可能有各種 ngx_xx,最有可能的是 js,不知道這方面有什麼前沿的動向?
我們組在嘗試把 PHP 嵌入到 nginx 中,當然性能肯定不如 LuaJIT,但是會方便很多 PHP 同學,有進展的話,我們會開源出來 :)

7、OpenResty 目前看似乎是一個 proxy 的配置框架(糅合了 nginx + Lua),但以後的發展是什麼樣子?會不會以後更進一步,比如做一個 API gateway 之類的。
OpenResty其實是希望大家忽略 nginx 的存在,直接使用 ngx_lua 提供的 API 實現自己的業務邏輯。更像一門獨立的開發語言,只不過底層使用 nginx 的網絡庫而已。你可以按照你的想法搭建任何好玩的服務端應用出來。

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