1. 程式人生 > >資深程序員用Python實現每秒處理 120 萬次 HTTP 請求!什麽概念

資深程序員用Python實現每秒處理 120 萬次 HTTP 請求!什麽概念

更多 PE aws wsgi 語言 對象 虛擬 釋放 功能

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

Python 的微框架(藍色)、NodeJS 和 Go (綠色) 和 Japronto (紫色)

勘誤表:用戶 @heppu 提到,如果謹慎點用 Go 的 stdlib HTTP 服務器可以寫出比上圖的 Go 快 12% 的代碼。另外 fasthttp 也是一個非常棒的 Go 服務器,同樣的測試中它的性能幾乎只比 Japronto 低 18%。真是太棒了!更多細節查可以看 https://github.com/squeaky-pl/japronto/pull/12 和 https://github.com/squeaky-pl/japronto/pull/14

技術分享圖片

我們可以看到其實 Meinheld WSGI 服務器已經和 NodeJS 和 Go 的性能差不多了。盡管它用的是阻塞式設計,但還是要比前面那四個要快的多,前面四個用的是異步的 Python 解決方案。所以,不要輕易相信別人那些關於異步系統總是比同步系統更快的說法,雖然都是並發處理的問題,但事實遠不如想象的那麽簡單。

技術分享圖片

雖然我只是用 “Hello World” 來完成上面這個關於微框架的測試,但它清晰的展現了各種服務器框架的處理能力。

這些測試是在一臺亞馬遜 AWS EC2 的 c4.2xlarge 實例上完成的,它有 8 VCPUs,數據中心選在聖保羅區域,共享主機、HVM 虛擬化、普通磁盤。操作系統是 Ubuntu 16.04.1 LTS (Xenial Xerus),內核為 Linux 4.4.0–53-generic x86_64。操作系統顯示的 CPU 是 Xeon? E5–2666 v3 @ 2.90GHz。Python 我用的版本是 3.6,剛從源碼編譯來的。

公平起見,所有程序,包括 Go,都只運行在單個處理器內核上。測試工具為 wrk,參數是 1 個線程,100 個鏈接和每個鏈接 24 個請求(累計並發 2400 次請求)。

技術分享圖片

技術分享圖片

系統調用,以及在內核空間到用戶空間之間移動數據,相比起在進程內部移動數據,成本要高的多。這就是為什麽不到萬不得已,要盡可能少做系統調用的次數。

當 Japronto 收到數據並成功解析出請求序列時,它會嘗試盡可能快的把這些請求執行完成,並以正確的順序合並所有結果,然後只執行一次系統調用發送數據給客戶端。實際上因為有 scatter/gather IO 這樣的系統調用,合並的工作並不需要自己去完成,只不過 Japronto 暫時還沒有用到這些功能。

然而事情並不總是那麽完美,有時候請求需要耗費很長時間去處理,等待完成的過程增加了不必要的延遲。

當我們做優化時,有必要考慮系統調用的成本和請求的預期完成時間。

技術分享圖片

經過優化 Japronto 拿到了 1,214,440 RPS 的成績

除了利用客戶端流水線請求,和優化調用,還有一些其它可用的技術。

Japronto 幾乎都是用 C 寫的。包含解析器、協議、鏈接管理、路由、請求、應答等對象都是用 C 擴展寫的。

Japronto 力圖做到 Python 的懶加載,比如,協議頭的字典只有在被試圖請求到時才會被創建,另外一系列的對象也只有在第一次使用時才會被創建。

Japronto 使用超牛逼的 picohttpparser C 庫來解析狀態、協議頭以及分片的 HTTP 消息體。Picohttpparser 是直接調用現代 CPU 集成的 SSE4.2 擴展文本處理指令去快速匹配 HTTP 標記的邊界(那些 10 年前的老 x86_64 CPU 都有這玩意兒)。I/O 用到了超棒的 uvloop,它是一個 libuv 的封裝,在最底層,它是調用 epoll 來提供異步讀寫通知。

技術分享圖片

Picohttpparser 依賴 SSE4.2 和 CMPESTRI x86_64 的特性做解析

Python 是有垃圾收集功能的語言,為避免不必要的增加垃圾收集器的壓力,在設計高性能系統時一定要多加註意。Japronto 的內部被設計的嘗試避免循環引用和盡可能少的分配、釋放內存,它會預先申請一塊區域來存放對象各種,同時嘗試在後續請求中重用那些沒有被繼續引用的 Python 的對象,而不是將那些對象直接扔掉。

這些預先申請的內存的大小被固定為 4KB 的倍數。內部結構會非常小心和頻繁的使用這些連續的內存區域,以減少緩存失效的可能性。

Japronto 會盡可能避免不必要的緩存間復制,只在正確的位置執行操作。比如,在處理路由時,先做 URL 解碼再進行路由匹配。

=large開源貢獻者們,我需要你們的幫助

我已經連續不斷的開發 Japronto 超過三個月,不光在每一個工作日,周末也無休。除了每天的工作外,我把所有時間精力都投入到這個項目上了。

我想是時候和社區分享我的勞動果實了。

Japronto 已經可靠的實現了下面這些功能:

技術分享圖片

進群:125240963 即可獲取神秘禮包

資深程序員用Python實現每秒處理 120 萬次 HTTP 請求!什麽概念