低延遲系統的 11 個最佳實踐

英文原文:11 Best Practices for Low Latency Systems

自從Google發佈額外的一個500ms延遲將減小20%的流量以及亞馬遜發現額外的100ms延遲會使銷售量降低1%已經8年了。此後,開發者們一直奮戰在延遲曲線的底部,甚至前端開發者們都在壓縮JavaScriptCSS以及HTML來爭取分毫時間。如下是各類低延遲系統設計時需牢記在心的最佳實踐的一個概覽。大多數這些建議考慮的是邏輯上極端,能夠權衡使用。(感謝在Quora上問這個問題的匿名用戶,這讓我把個人想法寫了下來)。css

選擇正確的語言

腳本語言不要使用,儘管它們愈來愈快,當你處理關鍵事務像拿掉進程的最後幾毫秒時間時,你處理不掉解釋型語言的開銷。此外,你會想要一個強有力的記憶模型來進行無鎖編程,因此你應該看Java、Scala、C++11或Go。 html

把一切放在內存裏

I/O會是延遲主因,因此確保你的全部數據在內存中。這一般意味着管理內存中的數據結構以及維護現有記錄,這樣你在重啓機器或進程後可以重建以前的狀態。維持記錄的選擇包括BitcaskKratiLevelDBBDB-JE。或者你也能夠本地運行一個像redisMongoDB(memory >> data)這樣的內存型數據庫。但須要注意的是,在它們後臺同步數據到硬盤crash時你仍舊可能丟失一些數據。前端

確保數據和處理程序的位置

網絡跳數比磁盤尋道要快,但即便這樣經過網絡也會增長不少開銷。理想狀況下,數據應當徹底在主機的內存中。像AWS雲中幾乎提供了1/4TB的內存,物理服務器提供多個TB如今也很常見。若是你須要運行在多個主機上,你應當確保數據和請求被適當的劃分,使得在服務請求時全部必要的數據都在本地。 html5

保持系統未充分使用java

低延遲老是須要有資源來處理新的請求。不要試圖運行到你的軟硬件資源的極限。總要有一些峯值儲備用於突發狀況。git

保證內容切換最小化github

內容切換是你正在運行的計算工做超過你擁有的資源的一個信號。你須要限制你的線程數使之與你係統的內核數相匹配,確保每一個線程與它的主線程相關聯。web

確保讀操做的連續性redis

各類形式的存儲,無淪是輪轉式的,仍是基於閃存的或內存的,順序使用的時候,它們的性能都會好一些。當進行內存的連續讀操做時,你將會觸發RAM級和CPU緩存級的預讀處理。若是預讀操做順利的完成,那麼下一步所需的數據在使用前都已在L1級的緩存中。促進這一處理的簡便方法是:大量的使用原始數據類型的或結構體數組。不惜一切代價避免使用基於鏈表或者對象數組的隨動指針。 算法

批量處理寫入操做

這個聽起來有背常理,可是你能夠經過批量處理寫操做得到明顯的性能提高。然而,總有一些錯覺:這就意味着在寫入操做前系統須要等待任意的時間。相反地,線程在作輸入/輸出操做時會緊湊地循環。每次寫操做都會在上一次操做完成後對到達的數據批量的處理。這種機制確保了系統快速的響應和良好的適應性。

優化緩存

在各個位置的優化中,內存的快速訪問成了瓶頸。把線程與它們的主線性相關聯有助於下降CPU緩存污染;連續性輸入/輸出處理,一樣有利於緩存中的預加載。除此以外,你可使用基本數據類型來下降內存的佔用量,這樣就能夠有更多的數據加載到高速緩存中。另外你可參閱高速緩存參數無關算法,它經過遞歸的分解數據直到數據與緩存大小匹配,而後進行所需的處理。

儘量多的使用非阻塞模式

使用非阻塞模式並使用不受約束的數據結構和算法。每次你在使用鎖時都要深刻到棧的操做系統層去處理鎖,這是件使人頭痛的事。一般若是你知道本身正在作什麼,你得理解JVM、C++或者Go的內存模型才能夠去應付鎖的相關處理。

儘量多的使用異步

任何處理特別是不須要建立響應輸入/輸出處理應當在關鍵路徑以外處理。

儘量多的並行處理

任何處理特別是能夠並行操做的輸入/輸出處理應當並行的處理。例如你的高可用性策略包括把在磁盤中寫入事務日誌和把事務發送到二級服務器,這些動做都查能夠並行處理的。

參考資料:

全部內容均來自於LMAX的Disruptor項目,您能夠仔細研讀或關注Martin Tompson的分享。

其它的博客:

相關文章
相關標籤/搜索