棋牌游戲服務(wù)器架構(gòu)設(shè)計(jì)

一、棋牌類服務(wù)器的特點(diǎn)
1、棋牌類不分區(qū)不分服
? 一般來說,棋牌游戲都是不分區(qū)不分服的。所以棋牌類服務(wù)器要滿足隨著用戶量的增加而擴(kuò)展的需要。
2、房間模式
? 即在同一局游戲中就是在同一個(gè)房間中,同一個(gè)房間中的人可以接收到其他人的消息。
3、每個(gè)房間的操作必須是順序性
?? 這個(gè)特性類似與一般游戲的回合制,每個(gè)玩家的操作都是有順序性的。

二、需要解決的技術(shù)點(diǎn)
1、數(shù)據(jù)共享
?? 因?yàn)槠迮祁愑螒虿环謪^(qū)不分服,我們?cè)谠O(shè)計(jì)服務(wù)器的時(shí)候,是按世界服的思想去設(shè)計(jì),即服務(wù)器是一個(gè)n多臺(tái)物理機(jī)的集群。當(dāng)用戶登陸服務(wù)器,創(chuàng)建房間時(shí),可能根據(jù)負(fù)載均衡算法,它可以在任何一臺(tái)服務(wù)器上面。所以,不管用戶登陸到哪一臺(tái)服務(wù)器上面了,都可以獲得自己的數(shù)據(jù)。我們可以使用redis來做數(shù)據(jù)共享。
2、如何進(jìn)入房間
?? 在同一局游戲中,我們要求所有人都在同一個(gè)房間中,我們可以規(guī)定在同一個(gè)房間中的用戶,必須登陸到同一臺(tái)物理服務(wù)器上面。在創(chuàng)建房間完成之后,其他人根據(jù)房間號(hào)查找房間的時(shí)候,可以根據(jù)房間號(hào),獲取這個(gè)房間所在的服務(wù)器ip和端口,判斷一個(gè)當(dāng)前用戶登陸的服務(wù)器ip與房間所在的服務(wù)器ip是否相同,如果相同,就不做切換,如果不一樣,客戶端就使用ip和端口,連接到房間所在的服務(wù)器上面。
3、保證房間操作的順序性
? 創(chuàng)建房間成功之后,接下來的操作都要保證它的順序性,所以房間需要有一個(gè)它自己的消息個(gè)隊(duì)列。我們可以把每個(gè)房間到達(dá)服務(wù)器的消息封裝為一個(gè)任務(wù),把這個(gè)任務(wù)放到消息隊(duì)列中,然后有一個(gè)任務(wù)執(zhí)行者去按順序執(zhí)行這些任務(wù)。

三、系統(tǒng)架構(gòu)
1、功能設(shè)計(jì)
a、登陸
? 一般都是需要接第三方登陸,登陸這一塊是http操作,我們統(tǒng)一提供一個(gè)web服務(wù),用來做登陸驗(yàn)證。因?yàn)樵诘顷憰r(shí),調(diào)用第三方的http服務(wù),這個(gè)過程可能很慢,如果放在邏輯服務(wù)器的話,可能會(huì)卡業(yè)務(wù)邏輯任務(wù)。因?yàn)榭赡懿煌耐婕覙I(yè)務(wù)請(qǐng)求可能同在一個(gè)線程中,如果有任務(wù)卡了,那么這個(gè)任務(wù)以后新來的請(qǐng)求請(qǐng)會(huì)卡住,導(dǎo)致消息延遲。
b、獲取游戲公告,也放在web服務(wù)中。公告一般是游戲登陸的時(shí)候向服務(wù)器獲取一次。把它放在web服務(wù)器中,與業(yè)務(wù)邏輯分離的好處是,當(dāng)業(yè)務(wù)邏輯服務(wù)器維護(hù)或更新的時(shí)候,不影響用戶的登陸,和獲取公告,這樣用戶體驗(yàn)會(huì)好一些。
c、創(chuàng)建用戶唯一的id,因?yàn)槠迮祁愑螒蚍?wù)器是世界服,無分區(qū),所以用戶的id必須是全局唯一的??梢岳胷edis的incr方法,原子的遞增,如果不想被別人根據(jù)userid的遞增推算出有多少注冊(cè)用戶,遞增的梯度可以隨機(jī),比如每次遞增的值從1到1024中隨機(jī)一個(gè)。
d、創(chuàng)建房間,當(dāng)房間主創(chuàng)建房間時(shí),房間的id需要在任何臺(tái)服務(wù)器上可以查詢到,所以創(chuàng)建房間成功后,房間id要存儲(chǔ)在共享內(nèi)存redis中,每個(gè)房間id對(duì)應(yīng)一個(gè)房間所在的ip地址或服務(wù)器id.這樣,當(dāng)有用戶要進(jìn)入房間,在查詢房間id時(shí),可能判斷這個(gè)房間是否和自己登陸的游戲服務(wù)器相同。
e、查找加入房間,根據(jù)房間id查詢房間,查找到房間后,獲取房間所在的ip地址或服務(wù)器id,如果發(fā)現(xiàn)和自己所登陸的服務(wù)器一樣,直接可以加入房間。如果不一樣,把這個(gè)房間所在的ip和端口返回給客戶端,讓客戶端重新與房間所在的服務(wù)器建立連接,使用登陸時(shí)的token驗(yàn)證用戶。
f、游戲腳本調(diào)用,在驗(yàn)證游戲是否合法時(shí),客戶端與服務(wù)器都要驗(yàn)證,驗(yàn)證的算法是一樣的,所以可以使用腳本來寫,寫一份腳本,在服務(wù)器與客戶端中同時(shí)使用??梢允褂胠ua。同一個(gè)算法使用同一個(gè)腳本 ,這樣在開發(fā)新的同類型棋牌游戲時(shí),只需要替換一下這個(gè)腳本就行了,不用再重復(fù)開發(fā)。
2、后臺(tái)管理系統(tǒng)
? 這個(gè)一般是根據(jù)運(yùn)營(yíng)需求開發(fā)的,每個(gè)公司不一樣。不過有一點(diǎn),后臺(tái)管理系統(tǒng)可能要和游戲服務(wù)器通信,這種通信方式最好是采用redis的訂閱/發(fā)布機(jī)制。這樣可以把某個(gè)消息事件同時(shí)發(fā)送到所有的業(yè)務(wù)服務(wù)器上面。根據(jù)用戶所在的服務(wù)器進(jìn)行處理。
3、玩家同屏
? 玩家同屏是棋牌游戲中的一個(gè)重點(diǎn),對(duì)于做過那些大型的arpg,或mmo游戲的程序員來說,這并不是什么難事。因?yàn)橥辆褪欠?wù)器對(duì)客戶端的消息進(jìn)行轉(zhuǎn)發(fā)。一個(gè)房間四個(gè)人,一個(gè)人出的牌或操作能被其他三個(gè)人同時(shí)看到
4、數(shù)據(jù)同步和持久化
? 由于棋牌類的業(yè)務(wù)少,數(shù)據(jù)更新少,所以查詢可以有redis緩存,減少數(shù)據(jù)庫查詢的壓力,而更新實(shí)行實(shí)時(shí)更新到數(shù)據(jù)庫,前期不需要開發(fā)數(shù)據(jù)庫持久化服務(wù)。等用戶積累到一定程序之后,發(fā)現(xiàn)更新數(shù)據(jù)庫比較慢的時(shí)候,再單獨(dú)做一個(gè)數(shù)據(jù)庫持久化服務(wù)。

四、服務(wù)器架構(gòu)
1、登陸時(shí),客戶端首先向登陸的web服務(wù)器請(qǐng)求登陸信息,登陸成功之后,返回登陸的token,為了適應(yīng)大規(guī)模的web請(qǐng)求和登陸服務(wù)的穩(wěn)定,可以使用nginx做負(fù)載均衡。
2、登陸成功之后,請(qǐng)求負(fù)載均衡服務(wù)器,獲取一臺(tái)連接的業(yè)務(wù)服務(wù)器。這個(gè)負(fù)載均衡服務(wù)器可以和登陸web在一個(gè)進(jìn)程中,也可以獨(dú)立出來。
3、拿到登陸成功的token和需要連接的業(yè)務(wù)服務(wù)器的ip和端口之后,再去連接業(yè)務(wù)服務(wù)器。連接成功之后,要使用token到登陸服務(wù)器去驗(yàn)證,這個(gè)用戶是否登陸了。
4、同一個(gè)房間的用戶要連接到同一臺(tái)物理服務(wù)器上面。在上面已經(jīng)說過了。
5、redis用來做共享緩存。
6、mysql做持久化存儲(chǔ)。
7、數(shù)據(jù)庫持久化服務(wù)器,統(tǒng)一做數(shù)據(jù)入庫操作。