在很多程式設計論壇裡經常會看到有人討論如何開發高效能伺服器的問題,但是初學者往往會把精力糾結到api的使用上,錯誤的認為使用了一些高階的api就意味著高效能,屬於只見樹木不見森林。以下是我認為高效能伺服器設計應該遵循的一些基本原則:
在不同應用場合中的伺服器對效能的需求是不一樣的,有些需要處理大量的併發連線,有些追求高實時性(低延遲),有些則追求高吞吐量,有些要求大量的io操作而有些則需要大量的cpu計算。所謂的高效能伺服器設計就在於針對具體的效能要求給出專門的設計方案,而通用的適用於普遍場合的伺服器設計那就不叫高效能了,因此在設計你的伺服器之前搞清楚你的效能設計目標是非常重要的,這將指導你做出正確的選擇。
伺服器的資源包括:網路頻寬、包吞吐量、cpu資源、記憶體資源等等。在任何時候伺服器的資源都是有限的,制約效能的唯一因素就在於資源的瓶頸,而要把效能最大的發揮出來就需要找出資源的瓶頸,並進行合理的分配和優化。這裡舉乙個簡單的例子:對於tcp連線來說,雖然它是抽象為資料流協議的,但是在底層實現上是依賴於ip資料報協議,因此在估算伺服器能處理的最大位元組吞吐量的時候就不能簡單的以網路頻寬資料來估算,而是要根據ip包吞吐量 * 每tcp包大小來進行估算,在實際中還涉及到rtt(平均延遲時間)及tcp滑動視窗大小,nagle演算法的採用等等因素,如果你每次tcp包的傳送大小只有幾十位元組的話,那麼是遠遠達不到實際的理論頻寬的,如果你的伺服器是以位元組吞吐量為設計目標的話,那麼就需要想辦法增加每個tcp包的傳送大小。
所謂高效能是節省出來的,這是一句真理。幾乎所有的程式設計師都是理性的,沒有人會去刻意或者毫無道理的浪費系統資源。但往往我們會在不知不覺中浪費系統資源,這主要源於我們的無知。由於程式語言、介面、庫及框架將底層的細節抽象了,所以當我們只停留在這些抽象層次上,就很難認識到抽象背後隱藏的東西,在不知不覺中浪費了系統資源。具體來說,每乙個系統api的呼叫在程式上看只是一句函式呼叫而已,但是每個api背後的開銷則是大不相同的,先來看乙個簡單的例子:
在乙個tcp資料報的構造中通常我們需要先傳送乙個頭(裡面可能只是簡單的標識一下這個包的長度),然後再傳送實際的內容,見**:
send(socket, &packet_size, 4);
send(socket, packet, packet_size);
這樣看上去雖然只是2個簡單的不起眼的api呼叫,但實際上卻會造成很大的開銷,send本身是乙個昂貴的系統級呼叫,需要占用大量的cpu時間(send的呼叫需要幾到幾十個us),同時第一send可能會導致底層構造並傳送乙個只帶有4位元組內容的tcp包,而乙個tcp頭就需要40位元組,這嚴重的降低了網路利用率。所以,如果我們把這兩段資料拷貝到乙個資料緩衝區並呼叫一次send傳送的話,效能就會大大提公升,這個例子同時暗示我們:如果有機會可以合併更多小資料報並一次性呼叫send操作的話,那麼效能將會有很大的提公升。
其他方面的例子也很多,例如執行緒切換的開銷,cache missing的開銷,cache一致性的開銷,鎖的開銷等等。避免浪費聽上去是一句簡單的廢話,但實際上告訴我們的是需要深入的了解抽象背後的細節。
「穩定壓倒一切」,對於伺服器來說是一句至理名言。伺服器的資源是有限的,所能承載的最大負載必然是有限的。正如前段時間杯具的12306鐵路網路售票系統,想必很多人都深有體會(可惜我從來沒有體會過春運)。在伺服器超負荷執行中最杯具的就是稱之為"雪崩效應"的一類問題,當負載達到乙個臨界點後伺服器效能急轉直下,使得正常的服務也無法進行甚至直接宕機。因此,作為乙個有職業素養的伺服器端程式設計師(非臨時工和無證程式設計師),在設計中必須對各種最壞情況要有預計,並通過前期設計及後期的壓力測試來確定伺服器所能達到的滿負載指標,對超負載情況要有保護措施(拒絕服務新的連線以保證伺服器的安全),當然在實際的運營中還需要為伺服器保留一定的安全邊界以防止各種顛簸釀成杯具。
高效能伺服器設計
原文 http blog.chinaunix.net u 5251 showart 236329.html 先後檢視了 haproxy l7sw 和lighttpd 的相關原始碼,無一例外,他們一致認為多路復用是效能最好的伺服器架構 事實也確實應該如此,程序的出現一方面就是為了儲存任務的執行上下文從...
高效能伺服器設計
先後檢視了haproxy l7sw 和lighttpd 的相關原始碼,無一例外,他們一致認為多路復用是效能最好的伺服器架構。事實也確實應該如此,程序的出現一方面就是為了儲存任務的執行上下文從而簡化應用程式設計,如果程式的邏輯結構不是很複雜,那麼用整個程序控制塊來儲存執行上下文未免有些大材小用,加上程...
高效能伺服器設計
原文 先後檢視了 haproxy l7sw 和lighttpd 的相關原始碼,無一例外,他們一致認為多路復用是效能最好的伺服器架構 事實也確實應該如此,程序的出現一方面就是為了儲存任務的執行上下文從而簡化應用程式設計,如果程式的邏輯結構不是很複雜,那麼用整個程序控制塊來儲存執 行上下文未免有些大材小...