遊戲服務端架構 - 高效的數據轉發之路由集群

© 內容版權所有,轉載或複製需附源站地址 www.tanjp.com 謝謝合作。

變更記錄

2020-04-28, tanjp, 主要分析和總結路由集群的數據轉發功能。

在之前 分區分服與大規模跨服功能 , 百萬在線的角色服承載能力分析 和 社交服架構設計之幫會系統 的基礎上,再進入服務端架構的數據轉發核心組件,路由集群。


一、進程連接關係

從之前的架構設計圖中,可以看出,在大規模跨服功能的遊戲服務端架構中,會有成百上千個進程一起協作來承載整套遊戲服務端的功能需求。如此多的服務端進程,如何能讓所有進程有序的協作,就成了很關鍵的環節。

我們都知道,服務端的進程一般都是運行在機房內網,進程間的通訊主要是採用 TCP 長連接的方式。TCP 需要 server 端監聽端口,而 client 端主動連接到 server端監聽的地址。

服務端內部的進程數很多,我們首先要確定哪些作為 server端來監聽端口,哪些作為 client端來發起連接。

在 分區分服與大規模跨服功能 中,已經確定好了,存儲服務(DBS)監聽端口,路由服務(route)監聽端口,其他所有的服務端內部進程,都作為客戶端主動連接 DBS 和 route。如下圖:


遊戲服務端架構 - 高效的數據轉發之路由集群

NOTE: 除了存儲進程(DBS),服務端內部所有其他進程都需要主動連接每一個路由進程(route),如果有 2000個進程,那就每個路由進程都維持 2000個TCP長連接。注意,路由進程之間相互獨立,沒有建立連接。


二、轉發數據量預設

先假設每個玩家每秒需要經過路由轉發的數據包大小為 1KB,這個預設值覺得還是偏大。譬如 玩家聊天,如果輸入文字的話,1秒1條聊天記錄已經是極限操作速度,每條聊天一般也會有大小限制,一般也就是幾百字節。再說也不可能每個人每秒都在聊天。其他內部服務之間的交互,主要還是依賴於需求,很難具體分析,所以就以 1KB/人/秒,為分析依據。

現在機房服務器基本上都是千兆網卡,也就是最高有 100MB/秒的數據傳輸率。因為我們架構上的路由集群,不單單只是轉發數據,日後還會負責一些服務治理之類的功能,並且實現上是在應用層的數據轉發,所以我們就設定單個路由數據轉發的效率為 20MB/秒。

我們在這裡主要對路由集群的承載進行分析,先進行數據彙總:

  • 在線1百萬,日活1千萬,總用戶量1億
  • 角色進程數:1000
  • 社交進程數:500 (公會之前預算是 63個,還會有各種社交系統)
  • 房間進程數:100 (是動態分配的,百萬在線也不可能每個人都在房間內)
  • 單個角色需要經過路由轉發的數據量為:1KB/秒
  • 1百萬在線的話,總的路由轉發數據量為:1000000KB/秒,大概 1000MB/秒
  • 單個路由進程數據轉發效率為:20MB/秒
  • 路由集群中路由進程的的總數量:50
  • 單個路由進程的TCP長連接數:1000(角色進程) + 500(社交進程) + 100(房間進程) = 1600


三、數據轉發實現機制

路由進程可以監聽一個或多個地址,每個地址都會等待所有內部其他進程的連接(路由進程之間相互獨立,沒有建立連接)。連接建立後並不是能夠立即轉發數據,要等待邏輯進程上報一個狀態標識【全部就緒】後,路由進程根據網絡協議數據包中的進程PID進行數據轉發。如下圖:


遊戲服務端架構 - 高效的數據轉發之路由集群


路由進程主要是在應用層做TCP數據包的轉發,這就涉及數據包部分數據的提取,如源進程ID(srcid),目標進程ID(dstid)。如果找不到相應的進程連接則把錯誤上報到路由進程的業務層,讓業務層來決定如何處理錯誤。


四、路由轉發策略

上面的數據預設分析得出,1百萬用戶在線的話,需要 50個路由進程來組成一套路由集群。當業務進程連接到 50個路由進程後,它要選擇哪個路由進程來轉發數據呢?這就涉及到路由轉發策略的問題。不能再往高負載的路由進程繼續轉發數據,應該選擇負載更低的路由進程。也就是說,要有一個機制來確定路由進程負載的高低。從上面的分析,每個路由進程最多每秒轉發 20MB數據,也就是說每秒數據轉發量,就可以作為路由進程負載高低的標準。所以,路由進程負載的單位為:MB/秒(每秒數據轉發量)

如果說負載均衡只是從路由整體轉發壓力為方向來分析,要求儘可能讓每個路由進程均衡地接受數據轉發任務。那麼,當多個路由進程的負載都很低的情況下,如何來選擇一個路由進程?很明顯,肯定是選一個更快能夠把數據傳輸完成的路由進程。於是,又引入一個概念【最小轉發延時】,如何來定義這個最小轉發延時呢?

例如, 數據包(大小為1KB)從 PID10的進程轉發到PID41進程,有3個負載都很低的路由進程 R1, R2, R3。從 PID10 至 R1,耗時 14毫秒(ms);從 PID10 至 R2,耗時 20毫秒(ms),具體如下表格:

遊戲服務端架構 - 高效的數據轉發之路由集群

從上圖的總延時,最小的就是 R3,所以從進程PID10的轉發到路由進程R3,再轉發到進程PID41,是最優選擇。

上面分析的最小轉發延時,是假設數據包的大小都是1KB,實際上不可能每個數據包都是一樣大的,所以要處於數據包的大小。更準確描述應該是【每KB最小轉發延時單位為:ms/KB

上面的分析,在大體方向上提供了一個思路,但是在具體實現上,還是有些問題的。具體來說,數據包在沒發出去之前是不知道傳輸延時的,路由進程的負載也不可能是實時監控得到。所以要依據歷史數據進行選擇和分析,當然了,歷史不能完全代表現在,但還是能說明一個大致的趨勢吧。所以,在討論這些路由轉發策略時,都有一個時間窗口,也就是說在過去一段時間內的【每秒數據轉發量】和【每KB最小轉發延時】。

這裡討論都是正常可達的情況,如果是不可達呢?也就是說,由於各種原因發送失敗了,進程掛了?

對於不可達的情況,還是一個時間窗口的問題。如果不可達的時間窗口很小,還沒讓業務進程感知到,那就不能做出正確的判斷,也就是說轉發會失敗。如果不可達的時間窗口已經足夠大,業務進程能夠感知到,自然就能做出正確的選擇。但是即使做出選擇那一瞬間是正確的,也不代表最終會正確送達,因為在數據傳輸途中有可能發生任何事情。

也就是說,通道的數據傳輸是不可能做到 100%成功的,所以業務邏輯層要為失敗的情況負責。要注意啊,有可能連失敗報錯都沒有,只是超時罷了。

梳理一下路由轉發的策略:

  • 優先判斷路由進程負載,歷史每秒數據轉發量,單位 MB/秒。
  • 負載相當(不是相等)時,判斷歷史每KB最小轉發延時,單位 ms/KB。
  • 數據轉發可能失敗或超時,要業務層來處理。


五、數據轉發先後順序問題

如果根據上面所說的路由轉發策略,兩個有先後順序的數據包A和B,兩個數據包的數據轉發選擇了不同的路由進程,就有可能導致接收方收到數據的先後順序與發送方發送數據的先後順序不一致。

對於這種先後順序的不一致,會不會產生問題或者導致BUG?這就依賴於業務層的邏輯實現。

而對於先後順序有要求的業務系統,其實是有很多方法來保證先後順序一致。也就是說,業務層能夠做到保證先後順序一致的邏輯關係。

這裡舉個例子來說明一下:數據包A、B、C,在發送方發送前先進行編號,如A1、B2、C3。在接收方,如果先接收到A1就處理A1的數據,因為順序沒問題。如果先收到B2,那就先不處理,繼續等待A1;如果過一段時間能收到A1,就先處理A1,然後再處理B2,然後等待C3;如果過了挺長時間還是沒能收到A1,直接觸發超時,通知發送方之前發送的數據,我處理到哪?後面的要進行失敗處理。這樣先後順序的問題,就能在業務層解決。

上面這個例子,在業務實現上也不簡單,還是有一點複雜的,下面再說一下更簡單更直接的方法。

NOTE: 先強調一下,同一個源進程(PID10)轉到相同的路由進程(R1),再轉到目標進程(PID41),這種情況下數據包轉發的先後順序是一致的。也就是說,多個數據包採用相同的路徑(PID10=>R1=>PID41),這些數據包在發送方和接收方的先後順序都是一致的。

對於有先後順序依賴的數據邏輯,保證讓它經過同一個路由進程節點進行轉發,即可實現一致的先後順序。

以之前討論的公會系統為例,公會邏輯進程有 60個,路由進程有 50個,建立公會邏輯進程與路由進程,在業務上路由選擇的映射關係,如下圖所示:

遊戲服務端架構 - 高效的數據轉發之路由集群


注意,這裡說的是【業務上路由選擇的映射關係】,不是公會邏輯進程只連一個路由進程。而是,公會邏輯進程會連上所有路由進程,但是在業務上,在路由選擇策略上做一些調整,優先使用上圖的映射關係。當某個路由不可用時,映射關係可以稍微調整,轉到另一個可用的路由進程即可。這樣既能達到更高的可用性,又能保證嚴格的先後順序一致性。


六、總結

路由集群是整套服務端架構非常關鍵的部分,是數據傳輸的中心樞紐,所以必須保證儘可能高的可用性。同時,業務層的數據轉發量在需求確定前是很難預估的,所以儘可能高的數據轉發效率也是一個很重要的目標。

關於路由集群的實現,有很多不同的實現方案,每個人都有自己的思路和側重點。多多交流,聽聽不同的意見和想法,估計還會有很大提升的空間。

關於服務治理方面,也需要路由組件的配合,後面還需進一步深入。


© 內容版權所有,轉載或複製需附源站地址 www.tanjp.com 謝謝合作。


分享到:


相關文章: