OpenResty大會--章亦春演講文字版

轉載:http://mp.weixin.qq.com/s?__biz=MzI2MDAyOTIyNA==&mid=400642479&idx=1&sn=157c008bdb0290286d5b85cdbf0bed3f&scene=2&srcid=1120jdwydiuq6PBssAsVW2ts&from=timeline&isappinstalled=0#wechat_redirect

根據春哥現場視頻整理,如有錯漏,屬於筆者問題,和演講者無關。最後10分鐘沒有整理成文字,請大家期待下週的視頻完整版本。


看了兩天的視頻,一個字一個字打出來的,深感這個演講分量很重,值得大家細細體會。


內容相當多,大家慢慢看...

------------


大家好,我叫章亦春,我喜歡用agentzh這個名字,我很討厭別人把我這個首字母a大寫,我覺得特別醜,所以大家千萬不要大寫,這是雷區。


今天主要想和大家分享下or的過去,現在和未來。如果我在其他的it交流會議上面重點介紹我做了什麼,或者正在做什麼,那麼在or這個我們自己的會上面,我就可以放心大膽的說我們將要做什麼。


其實最初我只是想自己搭一個個人博客,我不想用wordpress,也不想用其他現成的技術,我想自己用一個輕量級的技術做出來。所以最初只是一個非常單純的想法。


我的第一份工作是在yahoo中國的搜索部門,我當時有很多很碎的業務,比如搜索結果的相關推薦,或者垂直搜索,還有下拉列表的自動提示,很多這種很碎的功能在搜索部門。於是我們老大讓我寫一個通用的平臺,可以方便的構造這樣的接口,給前前端來展現。這些接口可能是吐json這種很簡單的API。那個年代,API的概念還是方興未艾,順應這個潮流,做了第一版的or,是由我當時最喜歡的腳本語言perl寫的。花了很大的精力去優化,因爲當時在yahoo使用的生成機器是爬蟲淘汰下來的機器,就是連爬蟲都覺得很慢的機器,拿給我們跑業務跑生產,所以在用Perl做這種訪問量很大的接口時候,很難進行優化。當然我也不斷去把越來越多的or功能用c去實現,但是還是很難達到讓人眼前一亮的性能要求。所以現實是非常殘酷的。


我在yahoo有一個同事,叫chaoslawful,大名叫王曉哲,我很有幸拜他爲師,學了很多系統編程方面的東西,因爲他是一個很了不起的人,也是一個自學成才的工程師。


在09年的時候,就一直有一個想法,把之前用perl的or進行重寫,然後達到一個很高的性能要求。在09年的時候,我和曉哲轉到了淘寶,當時加入了量子統計這個數據平臺部門,做量子統計這個產品,給賣家提供流量統計、銷售統計、廣告效果報表的數據分析產品。現在這個產品已經不存在了,是很多年前淘寶的一個產品。它有很複雜的業務邏輯,對性能也有比較高的要求,同時後臺的數據量是很恐怖的,淘寶大部分商家的數據都會在這裏展現,進行各種維度和搜索的分析。當時,我就想,我既要把or重寫了,得到很高效的框架,同時也要和部門的同事一起,把量子統計在這個平臺上面構建出來。所以很難得有這個機會,同時也是非常大的一個挑戰。我希望在這裏嘗試一些從未嘗試過的、新奇的玩法。所以大家現在看到的or,其實就是在那段時間完成的,09年到2011年,我在淘寶的時間中。同時把量子統計這個web應用進行了非常高效的實現,相比之前PHP實現的老版本,代碼量減少了90%,性能提升了一個數量級,包括延時,包括併發。我們後臺的一個數據庫工程師和我說,之前老闆點擊一個黃鑽賣家的報表,離開工位倒杯水回來,報表還在轉,新版的話,啪一下就出來了。所以效果還是非常明顯的。只用非常少的機器,就能處理非常複雜的數據庫相關的查詢,因爲它數據源很多,所以這裏面有複雜的關係型的融合還有分表的邏輯。


那麼,大家可能會覺得,lua作爲一個非常簡單的語言,來表達很複雜的業務系統,可能會很吃力,事實上,我們在構建這個業務系統的時候,並沒有寫多少lua代碼,但確實是由lua來驅動的。技巧就是我經常鼓吹的一種玩法:設計一種針對業務的小語言,或者說DSL。這個應用背後的數據平臺,就是用我自己設計的一種類似關係型的語言來表達的,然後我自己實現的編譯器,處理這種業務描述,生成高度優化的lua代碼。lua代碼生成之後,你會覺得人類是很難寫出來的,因爲有很多優化,是人很難做對的。對查詢的拆分,對查詢的優化,所以我又在裏面實現了一箇中間件,但代碼很少,所以我等於把lua語言當做虛擬機的機器語言在使用,業務我是用最適合業務模型的一種表達方式來表達的。這塊兒我可以講很多,可以講一天。這塊兒和or配合起來去使用的一個優勢就在於,這個平臺框架很輕,沒有什麼亂七八糟的東西,同時lua語言是一種高度動態的語言,我可以根據需要去做一些魔法般的事情,把它做成我的虛擬機的CPU,來進行代碼生成會非常的方便,同時效率也會非常非常的高。後面我還會講到類似的例子。


我覺得很多時候不用糾結到底使用什麼編程語言,更多的應該考慮用業務語言來表達我們的業務。比如團隊裏面產品經理用犀利的語言把業務描述的很精確,那麼他寫的這個文檔, 已經是這個業務系統本身了。我們寫個編譯機讓它跑起來就行了。大家可以去想一想這個思路。


在2012年的時候,我加入了cloudflare。2011年的時候,我在福州,我不是福州人,很多人認爲我是福州人,回老家,其實不是,我們只是隨便挑選了一個南方城市,去過一種半隱居的生活,有更多的時間專注於開源項目,特別是or。現在大家看到的很多高級功能,都是在那段時間完成的。在2012年,福州田園生活過了一年之後,就加入了美國的cloudflare公司,這是一個cdn公司。所以我之前在搜索行業、在數據分析行業混了幾年,然後到了cdn行業。機緣巧合,這家公司希望用or來構建他們的基礎設置。我覺得去美國過類似的田園生活也不錯。但我沒想到的是or在cdn行業獲取了很大的成功,有很多的公司會去使用。這也是我最初沒有想到的,我最初想的是web應用,對富客戶端或者移動客戶端的API,使用or構建是非常合適的。大家之前看到的web引用,其實也是由這些API驅動的,大量使用了ajax這樣的技術,像模板渲染、用戶交互的控制流邏輯實現都是在瀏覽器裏面完成的,這是一個胖客戶端,當時花了很多精力去搞IE6,所以又寫了很多javascript,還是很辛苦的。


最開始我們考慮把lua嵌入到nginx當中,也是在淘寶的時候,曉哲老師給我建議了這樣一個技術方案,我覺得靠譜。我最早的改寫方案是基於apache去寫c module,但是apache的代碼看得我有些雲裏霧裏,所以在曉哲老師的建議下,開始把工作重心放在nginx上面。這時候可能知道nginx的同學也不是很多。nginx的請求有多個不同的處理階段,在不同的階段,我們可以插入一些lua代碼,插入自己的邏輯,進行一些控制或者事件記錄。當然最常用的就是content_by_lua,這個是用or做完整外圍應用的一種玩法,剛纔很多同學已經演示了,可能對於cdn,對於動態均衡器來說,他就不會用content_by_lua,而是用nginx自己的proxy_pass這樣的反向代理模塊,而且會去使用access_by_lua和rewrite_by_lua這樣一些在更早階段執行的hook去加入自己的一些邏輯。我開始的時候寫了一些resty的lua庫,可以在lua層面做一些代碼的複用。然後社區的熱心用戶貢獻了很多resty庫,特別是今天上午演講的Aapo同學,貢獻了非常多的resty庫,這些都是讓我很振奮的事情。在做這些庫的時候,我有一個願望,就是他們都是相對獨立的,儘量之間不要有相互依賴,這樣可以確保一個清晰的結果,lua的優點就在於他的簡潔明快。


剛纔提到三個應用場景,API Server,還有HTTP Proxy,這個在CDN行業用的比較多。Web Application,這個相對少一些。這個和nginx本身的使用方式有關。有些同學可能沒法接受把nginx本身作爲Web Application的容器或者server,但這是我的初衷。


在發展的過程中,or秉持的是兼容幷包的思想,我們並不排他。出於nginx在整個web stack中位置的特殊性,我們可以很方便的和現有的技術進行融合,比如PHP、Python、go、nodejs,我們在網關這個層面,所以我們可以同時和其他後端應用並存,雖然我還是更傾向於更純淨的方案,但事實上,在or社區裏面,我們的用戶來自各個社區,Ruby、Python甚至java,所以我很高興看到不同語言社區的同學,把他們自己社區的文化,一些看待問題考慮問題的方法,能夠帶到我們社區裏面來,擴展我們的思路。我們也鼓勵各種混合的使用方法,至少對於現存的系統來說,我們的遷移可以一塊一塊的進行,當然用戶認證的這個邏輯需要優先遷移到nginx這個層面。這種玩法也是我最初沒有想到的。我最初用nginx,是看中它http、io事件處理模型這塊的實現,大家最最最爲經典的用法是把nginx最爲前面的網關,後面用fcgi去連API server,或者proxy_pass去做反向代理。那麼在這種結構下,or更有機會去做更多的事情,融合現有更多的業務。


我自己也用過這種技巧,在量子的時候,有一個實時統計的引擎,有很複雜的線路協議,當時我在做業務遷移的時候,因爲很嚴格的上線的時間點,所以沒有時間去完成一個非阻塞性能很高的實時引擎客戶端,所以我簡單的用Perl實現了一個客戶端,雖然我很仔細的實現了,但其實不行,扛不住,成爲整個系統的瓶頸。在上線之後,有了更多時間之後,我寫了一個純c的nginx module,來進行非阻塞通信。剛纔我講用perl,用c,其實並不是我直接用perl,用c去實現,而是用了一個寫程序的程序的技術。這個實時數據庫的維護者,也是我的同事,他維護了一篇非常漂亮的文檔,用來詳細講解線路協議的每一個主要方面。我一看到這個文檔,我靈機一動,這個文檔就是我的客戶端的實現。我寫了一個Perl腳本去自動分析這個文檔,把裏面的數據,裏面的結構,全部抽出來,變成一個數據結構,自動生成Perl實現,自動生成c的實現。事實上,我還讓它自動生成了測試集,測試也可以自動生成。在這個過程中,我發現他文檔中的一些筆誤,因爲畢竟是人寫的,而我的分析器嘗試把它當做程序來運行的時候,就會發現很多細節問題。所以文檔真的很重要,重要到你可以用文檔來生成任何東西,包括實現,包括測試,中文的,英文的,葡萄牙文的各種人類的文檔都可以。這是一種很有意思的思路。這也使得你的業務和具體實現無關,在任何一天,你都可以換掉下面的實現,而不用動上面的實現代碼。像剛纔我舉的那個例子,我可以很愜意的把Perl實現換成c實現,其實我只是寫了一個模板。前段工程師可能很熟悉這種模板的技術,我們一般會使用模板來生成HTML和CSS,但是你有沒有想過,我們可以用模板生成任何東西,包括你的程序本身,爲什麼不呢?所以我使用寫程序的程序的技術的時候,我恰恰是用了那種通常是生成HTML的模板引擎,當然更復雜的代碼生成器,還是需要專門的代碼生成器技術。這個說遠了,我的意思是說,這種兼容幷包的哲學,可以打開我們的思路,我們不必侷限於lua這個語言,nginx這個東西,其實我們只是根據需要,把很多我們需要的塊拼接起來,而並沒有任何的排他或者任何宗教信仰式的極端主義的傾向。


在設計整個or的過程中,我們還是有幾個比較清晰的目標。第一個目標首先是簡單,simple。這也是我爲什麼不喜歡很多java框架的原因,就是一定要簡單,不需要的東西一定不能存在。然後要小巧,這點我也是很執着的一個事情,我算是半個ops,運維人員的背景出身,所以我希望我在機器上面跑的程序能夠小巧,以至於能夠完全控制整個代碼機,在出問題的時候,可以自己去分析,自己去追蹤,乃至自己去修復,而不管出問題的組件處於軟件系統的哪個位置,所以這個有點偏執,但是這樣可以讓我晚上睡個好覺,因爲我不再懼怕任何詭異問題,因爲本來也就沒有什麼詭異問題。第三個就是要快,這是我在yahoo和淘寶工作的最直接的感觸。後來到了cloudflare也是類似的情況,其實現在的互聯網環境變得如此的擁擠,就是看上去很不起眼的東西,往往就能吸引到很多流量,有很高的性能要求,而給我們的機器,通常不盡如人意,yahoo當時爬蟲淘汰下來的機器是一個極端例子,但也能說明問題,所以要快。如果一個程序跑的還不如我收工幹活來的要快,那麼爲什麼還要寫程序呢?最後一個目標是一定要靈活。這也是我非常看重腳本語言的一個方面,靜態語言有很多優點,但是我希望在做業務的時候,我的手是足夠靈活的,可以做任何我想做的事情,而不會受到很多不必要的束縛。這一點,在座的腳本程序員都會深有體會。有時候,我並不希望實現語言給我太多的限制。


那麼,很重要的一點,就是要實用主義。我們並不追求很花哨的學院派的概念,雖然作爲業務愛好還是很有裨益的,但是對於工程的實踐來說,實用主義應該是放在第一位的。首先要把活幹了,也得得到一個足夠高效、足夠健壯、足夠優美的一個系統。優美是最高境界。那麼or就是實用主義的產物。我希望我們繼續貫徹這個方針,保持實用主義者的稱號。


還有一個很重要的,就是開源工作者很看重的:有趣。我們假設開源是一個編譯器,它有優化選項,-Ofun,我們是針對樂趣進行優化。這一點看上去是和實用主義原則衝突,其實不然。因爲對於一個工程師來說,最有意思的莫過於自己的技術,自己搭建的系統,自己設計的方案,能夠在線上跑的非常好,能夠服務越來越多的用戶,這是非常大的一個樂趣。對開源工作者來講,他也希望自己的代碼能夠跑在儘可能多的公司的服務器上,能夠收到儘可能多的用戶的感謝信。這個你想,在一天干活最痛苦的時候,突然收到一封來自世界另一個角落的用戶的感謝信,字裏行間洋溢着一種感激,一種欣喜,那你這一天立馬就會變得非常美好。所以,要讓樂趣變成我們工作的主旋律,而不要讓工作變成一種負擔。這也是我在做or的時候,希望我自己,以及每一位參與開發或者普通使用的用戶,都能去做到的一件事情。我們會看到在一些社區裏面,很容易產生一種憤怒,比如說有某個用戶問了一個很小白的問題,或者出言不遜,諸如此類的,很容易讓人變得毛躁起來。我希望這種消極情緒能夠儘量的消極乃至沒有,因爲我還是希望世界能多一些美好,多一些正面的積極的情緒,對我們每個人也會更好一些。


那麼我們有一個正在不斷成長的社區,我每天花費你們沒法想象的時間,去處理用戶的郵件和補丁,有新特性,有bugfix。會用各種語言去寫,有時候會忘了正在用什麼語言,可能前半截用的中文,後半截用的英文,有時候也會出現混亂的情況。360的幾位哥們兒,溫銘、院生、艾菲他們也自己開了一個qq羣,我不在那個羣裏面,因爲我很久不用qq了。然後github上面也會有很多issue和pull request,當然一般的討論還是希望能夠在郵件列表裏面,這樣可以方便通過搜索引擎進行檢索。那麼現在我們還有了會議,讓原本只知道web ID的朋友,能夠看到真人,很多朋友只認識他們的github ID,或者email裏面的nick,而不知道他們長什麼樣子。其實很多人和我想像多年的樣子完全不一樣,都是很正常的,還好沒有性別和我想像的不一樣。


我很希望去寫一本書,那麼360的溫銘他們的團隊已經開始寫一本叫做《OpenResty最佳實踐》的書,我自己腦袋裏面也會有一些想法,我們可能會合作去合著一本書,這都是可以去討論的。我腦袋裏面那本書叫《programming OpenResty》,希望能夠把我這麼多年來,做or的一些感悟和心得,能夠寫下來。這樣也省的我在郵件裏面,翻來覆去的重複一些很基本的東西,也能讓更多的人受益。


包管理一直是社區裏面呼聲很高的一個功能。我也希望or官方提供包管理這樣的東西,我們可以很方便的上傳、分享、安裝自己或者他人的lua resty模塊,lua庫,或者基於or的應用程序和工具,都可以通過這個統一的工具鏈。大家熟悉的比如說,nodejs的NPM,Perl的CPAN,ptyhon的PIP,  Ruby的gems,有很多現有包管理工具,我們可以去參考。我們設計還沒有定型,我只是給大家看下我腦海裏面很粗糙的想法。這個名字不太好起,我跟溫銘,跟院生他們商量,我覺得目前最好的名字是iresty,但還是稍微有點兒長,像PIP、NPM都是三個字母。iresty.org這個網站,我們可以檢索所有lua resty的庫,或者driver,比如需要ZooKeeper、MongoDB這樣的客戶端庫的時候,就可以先在這個網站上進行搜索。沒有的話,或者沒有合適的話,你可以去着手開發,這樣可以避免重複勞動,也可以鼓勵大家的協同。


命令行工具也會叫iresty,如果大家有更好的想法, 可以在郵件列表或者qq羣,告訴我們。現在是一個雛形的想法。我們可以去 install 一個庫,可以刪除卸載這個模塊。我比較堅持的一點是,模塊名字前面要求加上github ID,這樣可以避免其他社區包管理裏面常見的一種搶坑的問題,就是我這個東西還沒做出來,我先搶這個坑,別人就不能註冊這個名字了。我希望像github一樣,鼓勵大家不在名字空間上面去爭奪,像guthub一樣鼓勵大家去fork,去自己定製,但是還是希望儘量去協作,但我不希望協作是強制的。也可以去search,這些基本功能是需要的。


我還希望有一個命令行的文檔,可以看到標準模塊和安裝模塊的格式化的文檔。這樣省的我們在網上搜索,那也挺費事的。在終端裏面可以看到,這比較符合我們UNIX程序員的習慣。當然不僅能查看庫的文檔,模塊的文檔,還可以查看nginx lua或者nginx裏面某個配置指令的文檔,我也希望能做到這一點,這樣所有的文檔查找都能通過一個命令行工具來進行,甚至你終端支持顏色的話,顯示出來的文檔是彩色的。


resty這個工具已經實現了有一段時間,可能有些同學還不知道。這是一個很簡單的or命令行,你可以用-e選項去執行一行代碼,你可以使用幾乎所有的or裏面暴露的標準API,你也可以指定一個文件,用or實現一些命令行的工具。我們注意到這個工具也可以用於一些在線的分析,比如說同一份業務代碼,即可以作爲服務跑在nginx裏面,同時也可以在命令行裏面,供運維人員去快速檢查一些當前生產數據的狀態,所以這也會非常有用。還有同學會用這個工具做單元測試,因爲本質上這個resty工具,自己啓動了一個沒有腦袋的nginx,這個nginx不會監聽任何東西,只是一股腦的從頭執行到尾,然後退出。


我們剛纔說到irsety包管理工具,會同時支持lua庫和or應用,我希望有更多的or應用可以通過iresty install 就可以裝上,就可以運行。


我們可能會對LuaRocks有限性的兼容支持,而且我個人對LuaRocks不是特別的喜歡。所以我希望or有自己的包管理系統。同時標準Lua世界的庫,由於各種原因,沒有考慮or的阻塞和非阻塞的問題,它沒有使用or提供底層的原語接口,比如說socket接口,所以這些庫通常會阻塞nginx的事件循環,造成併發的嚴重下降。


還會有更多官方的二進制發佈包。比如說我們現在正在做的windows的二進制發佈包,裏面有一個32位的windows版本,剛纔360的同學們也講到,他們維護了一個windows的分支。現在計劃是把他們的優化工作,融合到官方的windows版本中來。我現在這個是非常簡單的,並不適合做生產,只適合在windows上面做開發,有人有這樣的需求,雖然他們最後的生產環境是Linux或者BSD。 我現在的windows版本是用MinGW GCC來編譯的,我希望最終使用微軟的工具鏈來編譯,以獲得最好的性能,和最少的依賴項。還會有主流的Linux發行版本的倉庫,這樣大家升級是apt-get update一下。這些工作都是近期會重點做的事情。我還希望iresty.org網站上傳的lua模塊和應用,能自動生成二進制各個發行版的安裝包,這也是個很cool的feature。


還有一個大家呼聲很高的特性,就是讓nginx成爲一個一般的TCP server,而不僅僅是http server,我們就可以去做更多的事情。那麼nginx最新提供的stream子系統就可以做到這一點。我們會有基於這個子系統的lua模塊和echo模塊。echo模塊已經完成開發,大家可以在github上面去查看,lua模塊也正在開發過程當中,它會擁有和現有的nginx  http modlue相同的lua API,所以你們的很多應用和庫,可以不加修改的運行在一個新的子系統上面。


類似的,我們會有UDP server,其實我很想看到的一點,是基於or的DNS name server,我覺得這是一個很有意思的應用。


下一個,模板。上午Aapo老師介紹過他自己寫的lua-resty-template,我自己也有我的一些想法,就是lua-resty-tt2(jemplate)。作爲一個Perl程序員,我非常熱愛Perl裏面tt2這個模板語言。它其實跟Perl沒有太多關係,Perl社區的一個大神,他寫了一個jemplate這個工具,可以把tt2生成爲獨立的、可以在客戶端運行的JavaScript,這就意味着同一份模板,即可以跑在服務端,也可以跑在客戶端,這是一個非常有趣的想法。這得益於這個模板語言既不是Perl,也不是lua,也不是JavaScript,而是它自己的一種小語言,足夠簡單但有足夠強大。我曾經用一個腳本語言實現了一個比較完整的x86反彙編器,就是通過這個模板。所以這塊也是我想去嘗試的官方模板引擎庫。當然,如果大家有興趣,也可以去移植Python裏面常見的模板語言到or的場景下,那麼Python原有的應用可以更容易的遷移到or,模板文件至少不用動。


大家注意我微博的話,可以看到我很多時間花在Streaming Regex這個正則引擎上面,這是一個從零實現的正則引擎。web世界很難離開正則,因爲總會遇到各種文本處理,對於CDN來說尤爲如此,因爲我們需要對請求進行很複雜的模式匹配,不管是WAF,還是CDN的規則的調度分發,還包括對響應體的一些正則替換,去掉或者刪除一些東西,比如把電子郵件地址替換成它對應的圖片,這些都需要很強大的正則引擎,支持流式處理,可以分塊來進行匹配,這樣的引擎是永遠不會往後回溯的,我處理一塊扔掉一塊,再處理下一塊,用O(1)的內存來處理任意長度的數據流。這個libsregex還在開發當中,我做了一些嘗試和實踐,最新的是基於確定性有窮自動機(DFA)來實現的。我覺得這裏面有一些算法的創新,我也跟PCRE JIT的作者有過溝通,他也很關注這個項目,很早就主動和我聯繫,讓我有些受寵若驚。所以我很高興通過這個項目,吸引了一些正則這個領域舉足輕重的人物的注意和幫助。他們會問需不需要幫助啊,或者說你的這個算法好有意思啊,你教教我好不好,我們一起討論一下。這些互動是非常非常寶貴的,這也會打破公司的邊界甚至國界,這是開源帶給我們的好處和樂趣。我還寫了一個nginx的模塊,用正則在響應體裏面做替換,它現在效率不太好,但是它實現了這個想法,它現在是確定性有窮自動機的算法,所以比較慢,和RE2的一般情況一樣慢,我需要像PCRE JIT一樣性能級別的引擎。最新的libsregex裏面的DFA引擎,在平均情況下可以達到PCRE JIT甚至更高的效率,最壞的情況下,也能和RE2或者比RE2更好。Intel在今年10月份開源了一個做了7年的正則庫,叫HyperScan,也是值得去參考的,只不過它的語義和Perl,和PCRE的差別更大一些。但它的優點是至少可以處理上萬個正則的流式匹配。


另外lua-resty-pegex也是我想做的一個庫,我其實並不想把社區可以做的事情都做完,我只是撿一些我特別想做的庫。一旦有了iresty之後,標準庫和非標準庫的邊界已經不是那麼清晰了。pegex是Perl裏面我非常喜歡的用於語法分析的引擎,可以用於構造編譯器,小語言,寫程序的程序,我們需要這種分析機構造器去實現小語言的編譯器,讓計算機認識我們定義的語法,認識我們某個同事寫文檔的格式或者慣用語,那麼讓計算機懂得這個文法,我們就需要另一種小語言,來描述這種小語言的語法,那麼這些工具就可以把描述變成實現,讓計算機能夠理解我們想象的語言的語法。語義分析可能會更復雜一些,因爲沒有這種自動化工具,但實現起來也沒有那麼複雜。編譯原理應該是我計算機專業學習當中,讓我受益最大的一門課。在這裏領域的很多想法,不僅適用於我們常見的gcc、java這樣的全功能的工業級別的編譯器,也適用於小巧的,只有幾百行、幾千行自己實現的小語言的編譯器。


基於這種小語言的思路,我希望or可以提供更多的小語言,讓大家可以去接受、去擺弄這樣的一些想法。我腦海裏面的 Edge 語言就是這樣一個例子,它是爲CDN行業裏面典型的業務模型、業務邏輯來設計的,可以很方便的通過基於規則的語法來表示很複雜的過濾規則、分發規則、WAF的防火牆規則,用一種統一的方式來表達我們的意圖,而不是去表達一種實現。那麼我們的編譯器就有機會在更高的層面上進行業務的語義分析,來寫很了不起的全局優化。比如說,我們有100個規則,都需要對URI進行正則檢查,我們自己實現的優化器,可以把規則裏面對URI的模式,合併成一個自動機,這樣我們只用對URI掃描一遍,而不是100遍。所以這樣就打開了我們優化的可能性。

(這裏舉了一個例子來說明,大家可以看視頻來理解)


我很想看到的一件事情是or有一個官方的WAF平臺,現在開源的一些解決方案,至少我覺得可以做的比它更好。包括cloudflare正在線上使用的WAF,我覺得也可以做的更好。我希望最好的WAF應該是開源的,而且是or裏面的。對於WAF來說,是一個很經典的DSL的例子,我們使用一種小語言,比如剛纔的 Edge 語言,也可以擴展到WAF場景,動作可能是reject、pass、打分,分值達到某個程度之後reject,返回一個403,完成一個capture來進行驗證。


我覺得特別有趣的一種玩法是從DSL生成高度優化的Lua代碼。這樣就可以發揮包括LuaJIT在內的組件的威力,對於JIT編譯器來講,Lua代碼分支越少,越簡單,越有可能生成最高效的機器指令,同時我們因爲使用了編譯的方法,我們抽象本身的開銷可以在編譯期,在上線之前完成。我們最後上線的時候,是生成的非常小巧的lua代碼,沒有什麼運行時開銷,也沒有什麼依賴項。魔法都可以在編譯期完成,這是一種脫去抽象本身開銷的很好的思路。現在很多web框架,是在運行時進行抽象,那麼會導致在線時候,內存和CPU的損耗很大,因爲你引入了很多層次,這些開銷是運行時的開銷。這一點也可能不是上線之前,也可能是在一些特殊的配置端口,比如說CDN的配置界面上面,我們會做編譯,通過一些複製的方式,比如KT,推送到全球各個網絡的各個節點,我們可以推送lua字節碼。在CDN的場景下,等價于于我們爲每一個客戶,高度定製了一個CDN軟件。這樣如果你的CDN配置很簡單,那麼生成的CDN軟件就非常簡單。


我們社區常常會吸引到其他社區,包括redis社區的郵件,比如redis社區的一個哥們兒就發郵件和我討論stateful這個概念,這個我也是從他那裏聽說的。所以有一些很有趣的協議和方法,當然每一種協議都有自己的折中和自己的應用場景。我希望後面or能在這方面多做一些嘗試,各個or之間形成更加默契配合的關係。同時能給請求引入狀態,這個狀態可以在同一機房的不同節點傳遞,甚至是跨機房,在全球節點之間傳遞。這些都是可以玩的一些東西,也會有它們各自的應用場景。


semaphore是一個很重要的特性,它可以用於ngx_lua輕量級線程之間的同步,其實就是線程同步裏面的信號量。酷狗音樂的同學一直在開發這個功能,已經有一些很不錯的成品了。我還在review過程當中,希望能儘快融合進主幹,這個可以避免使用sleep的方法進行同步,損耗可以下降非常多。這個朱德江同學的分享裏面也會提到。


酷狗音樂的朱德江同學還實現了基於list的共享內存的類型支持,可以用redis風格的接口對共享內存進行隊列操作,這個也會有非常有趣的應用場景。


我自己也很想拿Shm-based databases來練手,在or裏面來實現一個內存數據庫,沒有持久化,或者有限持久化支持的數據庫。關係類型的,或者其他類型的,時間序列類型的。


init_by_lua一直不支持cosockets,我希望這個能增加支持。在nginx啓動的時候,在外部的tcp或者udp服務裏面拿一些數據,這個還是非常有用的。那目前需要在每個worker裏面做一些比較噁心的初始化同步工作。


我們需要有更好的cosockets。cosockets仍然像經典的socket同步的使用,但它是非阻塞的,不會阻塞任何操作系統線程。我們有一些內存是分配在nginx的內存池裏面,我希望可以避免這種分配,更適用於推送的場景,很多下游長連接保持非常長時間的場景。


UDP或者gram socket需要一個bind()方法,這樣我們可以進行雙向的服務發現,服務推送之類的東西。


cosockets連接池,我希望能夠基於它做一些後端的併發控制,當超過這個連接池容量的時候,可以對connect請求進行排隊,而確保後端不會因爲併發數太多而損失吞吐量,即使是redis,如果給他併發太高的話,吞吐量也會直線下降。


ngx.connection 這是一個比較新的東西,和cosockets平行。我希望能夠提供一個fd,也就是文件描述符,這個fd可能是其他c庫實現的,我們可以把fd註冊到nginx的事件循環裏面,然後可以去同步非阻塞的等待nginx事件循環裏面的事件,比如說read、write。這種模式的好處在於我們可以結合luajit的ffi,很方便的整合現有的第三方的支持非阻塞IO的c庫,比如postgres的libpq,而不用lua的cosockets去重寫這樣的庫。這個也是能夠改變or生態系統的一個特性。幸運的是,這個特性實現起來很簡單。而且github上面已經有了一個pull request,叫做wait for fd,有興趣的同學可以一起參與討論,一起研究。


balancer_by_lua這個剛剛開源,你可以用lua來定義自己的負載均衡器,可以在每個請求的級別上去定義,當前訪問的後端的節點地址、端口,還可以定製很細力度的訪問失敗之後的重試策略。如果我是重試還是不重試,重試失敗後去重試哪個節點,都可以在每個請求的力度上進行lua編程。這對於很多反向代理風格的業務來講,是一個很重要的特性。


(這裏又是一個例子,建議大家看視頻)


SSL現在也很熱門,大家爲了安全起見,都往HTTPS遷移。 ssl_certificate_by_lua 可以讓你通過lua嚴格去控制下游的ssl握手的過程。比如使用什麼ssl,使用什麼證書,讓不讓它握手,都可以在這個環節插入自己的代碼來完成。比如cloudflare的ssl網關就是利用這個特性來實現的。


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