1. 程式人生 > >Socket伺服器整體架構概述【轉】

Socket伺服器整體架構概述【轉】

http://gad.qq.com/article/detail/33606

Socket伺服器主要用於提供高效、穩定的資料處理、訊息轉發等服務,它直接決定了前臺應用程式的效能。我們先從整體上認識一下Socket伺服器,Socket伺服器從架構上一般分為:網路層、業務邏輯層、會話層、資料訪問層,如圖:

 

一、網路層

 

網路層主要用於偵聽socket連線、建立socket、接受訊息、傳送訊息、關閉連線。作為socket通訊伺服器,網路層的效能相當重要,所以我們在設計網路層時,要著重在以下幾方面獲得突破:最大連線數、最大併發數、秒處理訊息數。如何突破呢?下面我為大家介紹幾種網路層常用到的一些技術和技巧(具體實現,我將在博文中逐一具體闡述):

 

1.Buffer管理

每一個SocketAsyncEventArgs物件(以下簡稱SAEA)在記憶體中都有其對應的快取空間,如果不對這些快取空間進行同一管理,當SAEA物件逐漸增多時,這些SAEA物件的快取空間會越來越大,它們在系統記憶體中不是連續的,造成很多記憶體碎片,而且這些快取不能重複利用,當建立、銷燬SAEA物件時,造成CPU很多額外消耗,影響伺服器效能。面對這問題如何解決呢?用Buffer池管理!

 

2.雙工通訊

Socket伺服器提高通訊效率是一個永恆的話題,提高通訊效率有很多種方法,雙工通訊就是其中之一。一個SAEA物件在同一時刻只能用來接收資料或傳送資料,有人想,如果一個SAEA物件在同一時刻既能傳送資料又能接受資料,那肯定會提高socket通訊效率。恩,很有想法!可是你能讓你的頭在同一時刻既往左轉又往右轉嗎?答案是不行的,那如何實現雙工通訊呢?既然一個SAEA物件在同一時刻只能做一件事,那我自定義DuplexSAEA物件,在該物件中封裝兩個SAEA,一個用於接受,一個用於傳送,問題不就解決了嗎。

 

3.poolOfAcceptEventArgs

poolOfAcceptEventArgs是個什麼東西?它不是個東西,是一個容器,一個容納AcceptSAEA物件的容器。給你兩個socket伺服器,你能很快判別兩個伺服器效能的優異嗎?很簡單,你瞬間向一臺伺服器打入5、6萬的連線,看看會不會都連上,如果都連上,說明這臺socket伺服器的併發處理連線的能力還是不錯的。那如何提高socket伺服器的併發連線能力呢?答案:poolOfAcceptEventArgs!

 

4.訊息佇列排程器

訊息佇列排程器主要分為兩種:接受訊息佇列、傳送訊息佇列。為什麼要用訊息佇列呢?主要是提高socket伺服器的吞吐量。首先我們定義一個佇列Queue,然後編寫N個排程器,不斷從佇列中排程訊息,接受佇列排程器用於將訊息拋至業務邏輯層處理,傳送佇列排程器用於呼叫網路層傳送訊息介面,向指定埠傳送資料。

 

5.心跳掃描

有一個困惑:客戶端連線socket伺服器,連線沒有斷開,但客戶端掛了,這樣這條連線在socket伺服器中就成了釘子戶,落地生根不走了!一個釘子戶還可以忍受,千千萬萬個呢?那就崩潰了!怎樣解決這個問題呢?定時掃描每條連線,如果該條連線在超時時間內沒有IO響應,則關閉它。

 

6.粘包

伺服器在接受訊息包時,如果兩個資料包同時被你伺服器收了怎麼辦?你會把他當成一個數據包嗎?如果一個數據包斷了,分成兩次被你伺服器收了,你會把他們拼接起來嗎?這些就是粘包了,怎麼解決?正則表示式掃描!

 

7.多執行緒程式設計

Socket伺服器的程式設計就是多執行緒程式設計,面對多執行緒,執行緒間怎樣同步、怎樣避免死鎖?多執行緒訪問公共資源如何處理,在下面的博文中,我將會為大傢俱體闡述。

 

二、業務邏輯層

 

網路層將解包後的訊息包拋至業務邏輯層,業務邏輯層收到訊息包後,解析訊息型別,然後轉入相應的處理流程處理。

 

網路層應提供傳送訊息的介面供業務邏輯層呼叫,因為網路層不會主動傳送訊息,傳送訊息的操作是由業務邏輯層來控制的,所以業務邏輯層應根據具體的業務應用,封裝不同功能的傳送訊息的方法。

 

三、會話層

 

會話層主要用於記錄線上使用者資訊,該層隸屬於業務邏輯層。既然隸屬於業務邏輯層,那為什麼還要獨立出來呢?這主要為以後分散式開發拓展用,試想,一臺伺服器最大能支援多少人同時線上?中國有多少人?如果1億人同時線上,你一臺伺服器能支援得了嗎?答案肯定是否定的,所以要分散式開發。分散式開發涉及到使用者資訊同步的問題,所以會話層就要獨立出來了。

 

四、資料訪問層

 

資料庫執行效率是整個socket伺服器的瓶頸?為什麼呢?舉個例子:假設我們的socket伺服器的秒處理訊息的條數為3000,每處理一條訊息都會儲存歷史記錄,那麼,如果資料訪問層不想拖網路層的後腿,那麼他的執行sql語句的效率也必須達到每秒3000!如果socket伺服器和資料庫伺服器部署在同一網段上,這個速度是沒有問題的,但如果資料庫伺服器部署在外網呢?你的sql語句的執行效率能達到那麼高嗎?很困難!

 

再思考一個問題:如果網路層執行執行緒和資料庫執行執行緒是同一個執行緒,那麼網路層的處理必須等待資料庫執行完畢後,才能進行!如果資料庫執行效率比較慢,那對整個socket伺服器將是一個毀滅性的打擊。

 

那麼怎樣將資料訪問層與網路層分離,讓他們互不影響?如何提高資料庫執行效率,讓網路層的處理速度和資料訪問層的處理速度達到一個平衡?答案:連線池+sql排程器+主從資料庫。

 

Socket伺服器的整體架構就為大家介紹到這裡,下面我將會為大傢俱體闡述各個技術的實現。