在網絡通訊中會經常面對一種情況就是信息廣播轉發,比較常見就是QQ群聊天。群里的人只要發一條信息就會廣播到群里的其他人,不過這種轉發量是非常的少一般情況下直接把通過對應用戶的socket.send方法發送出去即可。但有些情況並不允可你這樣,為什么呢?因為在某些場景下這些信息的轉發量和密集度是非常之高,數量可以達到每少10w,20w,50w,100w或更多,也許你的服務器性能好每秒10w的IO不算什么問題,那面對一100W或更多的消息轉發呢?有人會可能會問那來這么多的轉發量,其實一個同場500的用戶,每個用戶平均每秒有兩次行為改變,那就足以產生50W的轉發量了。
從上面的圖可以看到用戶之間的交互都會壓在服務器上,其信息交互是每秒都會產生這樣的量,以上圖緊緊是6個,如果是500或1000個呢?那是一個怎樣的情況。所以從IO的吞吐數量想把這些信息吃了是件不可能的事情。
針對上面的情況我們需要做的就是控制IO,有朋友可能會問題怎么控制,難不成不Send?其實做控制很簡單,其實只需用固定的資源去做某些事情就行,當工作的損耗超出的額定資源的情況就讓他等一下。
通過線程隊列就可以控制IO處理的數量,當隊列不存在堆壓一般有以下情況:1的線程有足夠的資源完成這些事情,2你需要轉發的消息不多對隊列構不成壓力。其實這些情況都不需要進行合並,因為處理不存IO壓力。
當隊列存在壓力的時說線程沒足夠的資源來處理大量IO,這時候我們就需要做些額外的工作發送數據合並,減低IO壓力。
把當前隊列的所有數據拿出來進行一個合並處理,然后再發送。整個過程都是內存操作其性能遠高於網絡IO處理,如果這個過程的實現比IO還損耗資源,那就認真的檢查一下實現方法,這是不應該的。
以上這種方式實現的延時是非常樂觀的,同時它能根據當前資源的使用情況來決定是否進行合並數據操作。當你服務器資源滿足,但延時上有點高那就可以通過多隊列來處理,把壓力分擔到其他線程上以達到一個短的延時處理。
在實際應用測試中由於網絡帶寬受限,所以只測試了500物體同場景測試,每個物體每秒產生兩次變化,實際廣播信息在50W每秒,發送IO大概1.5w每秒。core e4300的cpu占用大概在25% 左右,內存使用60mb,帶寬80Mbps.,延時大概是60ms左右.
以下是轉發信息結構:
class Po : IMessage { public int ID; public short X; public short Y; public short Type; public void Load(BufferReader reader) { ID = reader.ReadInt32(); X = reader.ReadInt16(); Y = reader.ReadInt16(); Type = reader.ReadInt16(); } public void Save(BufferWriter writer) { writer.Write(ID); writer.Write(X); writer.Write(Y); writer.Write(Type); } }