原 薦 通訊中大量訊息廣播的設計和優化
訊息廣播場在網路通訊應用還是普遍存在,如遊戲中玩家狀態通知,聊天和公共訊息傳送等,但在面對大量業務訊息廣播的情況可能會面臨一些效能上的問題需要處理;畢竟大量業務不僅在訊息序列化上非常損耗CPU,在網路IO讀寫上因過於頻繁也會引起大量的損耗,如果沒有處理好的情況還是非常影響整全服務效能。
訊息廣播場景
一般的設計都是把訊息先寫入會話中,然後會話內部進行訊息轉化成協議資料最終通過 Socket
傳送出去。這種設計不好的地方在於業務訊息比較複雜,廣播的會話數量規模比較大的情況那那整個訊息協議資料轉換就非常損耗效能!為什麼一般這樣設計呢,因為這樣內部轉換協議對 Buffer
的控制相對比較容易可控,只需要關心自己會話的訊息協轉換髮送回收即可。
廣播應用優化
通過把協議轉換前置,然後再把 Buffer
轉到會話再由 Socket
傳送出去,這樣做的好處非常明顯就是在大量廣播訊息的時候效能非常出色,因為無論廣播多少個會話只需要協議轉換一次就可以。不過問題也非常明顯,由於 Buffer
是應用者寫入並共享到不同會話中,這樣就導致 Buffr
不受內部管制,這樣框架總體效能就不好控制。
整合優化
實際服務應用中,兩種情況都會同時存在,不管誰的重權大小在設計只要傾向一邊那框架都很難在效能上發揮著優勢,畢竟你無法控制上層的應用所面對的情況和應用者的行為。為了更好的控制著效能,所以在實現這些基礎功能元件的時候這兩種情況都要有所考慮。
由於轉換協議是一樣的,可以把協議轉換抽象出來,然後在傳送訊息的時候進行一個閥值判斷;當超過閥值的時候就先轉換訊息然後再把 buffer
寫入到會話中,如果沒超過就由會話內部通過轉換器處理 buffer
.這樣在通訊中的 buffer
就可以管控起來,不過對於後者來說由於 buffer
可以進行共享傳送,那在管理上就比較麻煩可以通過傳送完成計數來處理;不過由於網路的不可控制這種控制非常困難(最簡單的方法是記憶體塊複製到單獨的會話 buffer
中後回到池中,對於c#這些來說個人建議直接放棄對這一塊的管理,畢竟在大量廣播下已經降低了很多協議轉換的開銷)。
Socket寫入資料層面的優化
對於C#語言來說Socket的Send方法還是比較損耗效能的,如果每秒要向1000個連線廣播10條訊息,在正常設計的情況那就意味著觸發10000次的Socket的Send操作。雖然這個數量在現有的硬體資源來說並不會存在什麼壓力,但如果10000個連線或傳送的密度更大呢?如果把這方面的損耗壓減下來,留給業務處理那不是一件更好的事情!
在會話內部引用一個訊息佇列,傳送的訊息先寫入佇列,然後通過批量的方式把多個訊息寫入 Buffer
中,在傳送完成後繼續監測佇列;傳送完成和訊息進入會話佇列時會存在一個狀衝突的過程,需要處理好之間的狀態確保佇列訊息轉換的一致性即可(使用定時器方式批量寫入傳送延時不好控制,特別是會話量比較大的情況下,不建議使用)。通過合併傳送在大量小訊息的情況下可以達到更高的頻寬利用率和低IO讀寫量,從而讓整體效能更出色。