一、背景
項目開始后,先敲定了大體可橫向擴(kuò)展的集群架構(gòu)(這是個美好的期望),然后開始編寫單進(jìn)程的服務(wù)器底層和邏輯,讓前邊幾個迭代周期的邏輯內(nèi)容配合客戶端跑起來了。
接著就是將單進(jìn)程的架構(gòu)擴(kuò)展起來,設(shè)計上細(xì)化下架構(gòu)的擴(kuò)展。已寫在前篇《休閑手游服務(wù)器集群擴(kuò)展思考》里。最近的兩周在將之前單進(jìn)程的服務(wù)器架構(gòu)里部分模塊擴(kuò)展為支持這篇隨筆里提到的集群架構(gòu)。
實(shí)現(xiàn)的過程中碰到的一些需要仔細(xì)設(shè)計的細(xì)節(jié),原則上還是K.I.S.S。
二、全服玩家在線狀態(tài)
邏輯服務(wù)器集群的負(fù)載均衡算法還沒實(shí)現(xiàn)。先只擴(kuò)展玩家間的同服通信為異服通信(通過redis的pub/sub,以下將這個用于通信轉(zhuǎn)發(fā)的redis簡稱為通信redis)。
問題鏈:(“-->>”引出的下個問題被當(dāng)前問題所依賴)
通信發(fā)起方需要知道目標(biāo)方在邏輯集群里的哪個服務(wù)器上 -->>
玩家登陸和退出時往通信redis報告 -->>
登陸時檢查賬號是否注冊到我們的游戲,否就注冊 -->>
(一)登陸和注冊
玩家拿到用戶系統(tǒng)的賬號來登陸我們游戲服務(wù)器。游戲服務(wù)器拿client給的這個code再去用戶系統(tǒng)服務(wù)器做驗證,通過后繼續(xù)。
檢查賬號是否在我們游戲注冊,如果沒有則注冊上,映射出游戲服務(wù)器上的一個local uid。這里需要檢查玩家是否在游戲注冊了,所以需要一個platform uid與local uid的映射表。這個映射之前單進(jìn)程服務(wù)器時與其他角色數(shù)據(jù)放在相同redis上的,現(xiàn)在移到全局類的redis上(以下簡稱全局redis,暫時是將通信redis和全局redis放一起的,等以后看壓測和線上反饋再做演變)。另外用來本地注冊生成local uid的自增長id也移到了全局redis上。
檢查完注冊,得到local uid,先看是否在本服務(wù)器登陸了,否則再向通信redis查看是否登陸在其他服務(wù)器。如果已登陸,則踢掉之前的登陸。之前單進(jìn)程只有同服重復(fù)登陸踢人,現(xiàn)在多個異服重復(fù)登陸的踢人操作。
登陸成功向通信redis報告local uid和所在的這個logic服務(wù)器的server id。另外退出時也向通信redis報告,注銷掉這條記錄。
(二)異服通信
每個邏輯服務(wù)器都與通信redis建立用于pub/sub的鏈接,各邏輯服務(wù)器有自己的頻道。
異服上的玩家通信時,從通信redis拿到目標(biāo)玩家所在server id,讓后向目標(biāo)server所對應(yīng)的專有頻道pub數(shù)據(jù)即可。
三、壓測工具
加了這個集群擴(kuò)展后,底層測試只是單元測試是不夠的。反正要壓力測試工具遲早要寫,就先寫了簡單版的壓測工具,來做異服通信的自動化測試。
壓測工具開始的想法挺多的,后來拋棄了一些短期不好實(shí)現(xiàn)的想法。現(xiàn)在就簡單的,一個client一個Client struct,這個處理client的通信發(fā)送接收。做相同動作的client為一個Group struct。每個動作為一個Rule struct,里邊組合好收到什么包后做什么事情,或者直接發(fā)些什么包。
c++端游壓測的每個Rule動作一般用lua來寫的,比較方便,我們這個壓測工具用go寫,rule暫時也用go寫,也不麻煩。
感慨下,這種并行的應(yīng)用場景,go的編程思維與具體寫法比node.js更適合c/c++出身的程序員。