這是我在 2016 OpenResty 全球技術大會上面的分享,起了一個驚悚的標題,內容是我自己工作多年的總結。這篇文章是現場分享的文字版本,歡迎大家評論。

說到高性能服務端,沒有真正接觸的工程師都覺得有些神祕,高不可攀的樣子。而事實是什麼呢?這裡我結合自己接觸到的一些講講。

大部分性能測試都是錯的

這是第一個驚人真相。性能測試對於服務端是肯定需要做的,但真相是 90% 以上的性能測試都是錯的,我自己接觸到的性能測試基本沒有做對的。為什麼會這樣?

第一點是性能測試方案沒有業務處理鏈和大局觀,很多都是拍腦袋得出來的。在做測試之前,參與測試的工程師是否對整個業務系統瞭然於胸?是否熟悉系統架構以及設計的原因?測試數據應該隨機生成,還是需要從線上系統拷貝流量回來放大重放?可能出現性能的子系統和 API 是什麼?

很多時候,都是開發列出幾個 API,QA 找兩臺機器就開始隨機發包了。美其名曰快速迭代。沒有一個精心設計的測試方案,後面的都是無用功。

第二點是系統環境沒有調優。我不止一次在郵件列表裡面看到工程師的提問,為什麼 OpenResty 的 hello world 性能測試數據這麼低?其實只需要調整幾個系統參數就可以解決。在一個 ulimit 還是 1024 的系統,不管什麼語言開發的 web server,QPS 都很低。

第三點是沒有檢查系統和應用的錯誤日誌。在做性能測試之前,你應該保證冒煙測試是通過的,而不是被 SELinux 攔截、連不上資料庫等磕絆,讓性能測試變成錯誤日誌刷新測試。

第四點是沒有用工具打滿負載。如果 A 系統和 B 系統的 QPS 一樣,但是前者 CPU 佔用 30%,後者佔用 90%,那麼這個結果是沒有意義的。

所以我們應該用能夠產生足夠大壓力的測試工具,比如 wrk,來保證 A 系統和 B 系統測試時都被狠狠的打滿 CPU。當然有些代碼很差勁的系統,會使用阻塞 IO,無論如何 CPU 都很空閑,那時候需要拿起 off-cpu 火焰圖分析工具照一照。

第五點是沒有 APM 或者火焰圖這樣的分析工具。測試到性能問題,然後就沒有然後了。只能丟給開發查問題,然後再測試新版本。這樣的壓力測試是沒有意義的。我們應該使用科學的分析工具,讓數據替代猜測,很多性能點是完全猜測不出來的。

人類和動物最大的區別是,人類會創造和使用工具。

第六點是沒有業務增長的預判。現在的系統性能可以支撐多少用戶量,我們是否需要進行性能優化,甚至系統重構來應對未來的業務增長?其實做性能測試的工程師很多時候是不關心這個問題的。

上面提到的工具類和系統優化類的,這裡有一個例子給大家參考:iresty/Mio。

高大上系統的 QPS 並不高

現在參加技術會議,有一個感覺,大家產品的日訪問量都是百億起步,日誌量都到了萬億,伺服器集羣幾千幾萬的。聽得時候心情澎湃,看看自家的產品實在是自慚形穢。

但是他們好像從來也不提這些高大上系統的單機 QPS 是多少?

讓我們算一筆帳。某個產品,?活 2000 萬,每個?戶每天 500 個請求,那麼每天就是 100 億的訪問量。你也可以當做日活 5000 萬, 200 個請求,也是 100 億。其實日活幾千萬的產品並不多,那些後臺沒事亂搞的 app 不算。

每天按照十小時計算,這樣系統的 QPS 是:每天100億訪問量 / 每天10?時 / 3600秒 = 27.78 萬,就按照 30 萬算吧。那麼單機 QPS 就是 30 萬除以伺服器數。那麼問題來了,對於日活好幾千萬的高大上系統,如果單機 QPS 達到 3 萬,只需要 10 臺機器,如果 QPS 是 3千,就需要 100 臺機器。

日誌量的話,每天 100 億,堅持一年就是 3.65 萬億,只要你的儲存空間足夠。真正的問題是儲存萬億級別的日誌,和存儲百億級別的日誌,對於業務是否有質的改變?

很多人可能會說,我們的業務邏輯很複雜,所以 QPS 並沒有預期的那麼高。其實,機器比人便宜,多買 100 臺機器,就幾百萬,用好幾年,比招幾個大牛要划算。這算是一個很痛的領悟。

系統性能和語言性能無關

有些架構師做系統技術選型時,主要精力放在開發語言的對比和糾結上,這是一個誤區。對於高性能服務端來說,整個系統的性能瓶頸並不在語言,而在網路和資料庫。

更重要的是,主流開發語言已經同質化。比如JIT、協程逐漸成為標配,雖然有些開發語言官方版本沒有接受,但第三方版本已經很成熟。連 await/async 這些關鍵字在 C#、python、ES7 裡面都是一樣的,雖然有些語言的實現只是語法糖。在這個背景下,幾千的 QPS 已經不成問題,如果你有 100 臺機器,一樣可以支撐日訪問量 100 億次的系統。

更重要的是,選擇的這個開發語言,要開發、維護和替換成本低。這個如人飲水,冷暖自知,不要為了追時髦而使用某個新技術。

存在銀彈

銀彈,是三十年前提出的一個理論:在十年後不會出現讓軟體過程提高十倍的技術。現在軟體過程上面都沒有銀彈。那麼在高性能服務端開發上面有沒有銀彈呢?

我覺得是有的。在揭曉這個銀彈之前,讓我們先完成極致性能這個小目標。對於服務端的工程師來說,幾千的 QPS 完全不能昭顯技術的優勢,對於性能的追求是沒有極限的。

我們先看下經典的服務端架構,http request 到服務端的 web server,再轉給業務邏輯,然後是緩存和資料庫。這個過程會經過多個進程,也可能跨過多個伺服器和機房。那麼又沒有一個技術方案,可以把這個過程簡化到一步呢?就是在一臺伺服器,一個進程內,處理完所有之前(web server + 業務邏輯 + cache + db)的事情呢?沒有進程的通信,沒有網路和磁碟的IO。

這看上去是一個不可能的事情。而實際上,早在 2010 年就已經實現了。[github.com/ecug/con-201] 這是 2012 年的一個幻燈片,我當年部門的老大做的分享。我們當時的系統每天有接近 100 億次用戶請求,而伺服器只有 10 臺,分佈在 2 個機房。所以我剛才提到的 QPS 計算,其實是一個真實的高性能服務端案例,是在資源有限的情況下,被倒逼實現的一個技術方案。由於高度優化,所以和業務綁定很死,沒有開源出來。但是思路是可以借鑒的。

再回到銀彈的話題,這枚銀彈除了自帶極致性能,還應該可以用 DSL 解耦開發和業務。春哥經常提到一個他在淘寶的親身經歷,在開發看來就是桃花源。就是產品同學有需求變更的時候,只用更新一個語法嚴謹的文檔,編譯器自動生成邏輯代碼。

在這個桃花源裏,不用不停的更新流程圖,也不用為產品需求和技術實現不同而撕逼。工程師的重心是理解業務,設計好符合業務的 DSL,並進行針對性優化。

而業務小語言正是 OpenResty 2017 年的開發重點,春哥的分享會重點講這個事情。我很期待在未來兩三年的時間內,OpenResty 可以成為我所說的這枚銀彈!這需要 OpenResty 社區的努力,也需要各位的貢獻,多謝。


推薦閱讀:
相關文章