一,棋牌類伺服器的特點
1,棋牌類不分區不分服
一般來說,棋牌遊戲都是不分區不分服的。是以棋牌類伺服器要滿足随着使用者量的增加而擴充的需要。
2,房間模式
即在同一局遊戲中就是在同一個房間中,同一個房間中的人可以接收到其他人的消息。
3,每個房間的操作必須是順序性
這個特性類似與一般遊戲的回合制,每個玩家的操作都是有順序性的。
二,需要解決的技術點
1,資料共享
因為棋牌類遊戲不分區不分服,我們在設計伺服器的時候,是按世界服的思想去設計,即伺服器是一個n多台實體機的叢集。當使用者登陸伺服器,建立房間時,可能根據負載均衡算法,它可以在任何一台伺服器上面。是以,不管使用者登陸到哪一台伺服器上面了,都可以獲得自己的資料。我們可以使用redis來做資料共享。
2,如何進入房間
在同一局遊戲中,我們要求所有人都在同一個房間中,我們可以規定在同一個房間中的使用者,必須登陸到同一台實體伺服器上面。在建立房間完成之後,其他人根據房間号查找房間的時候,可以根據房間号,擷取這個房間所在的伺服器ip和端口,判斷一個目前使用者登陸的伺服器ip與房間所在的伺服器ip是否相同,如果相同,就不做切換,如果不一樣,用戶端就使用ip和端口,連接配接到房間所在的伺服器上面。
3,保證房間操作的順序性
建立房間成功之後,接下來的操作都要保證它的順序性,是以房間需要有一個它自己的消息個隊列。我們可以把每個房間到達伺服器的消息封裝為一個任務,把這個任務放到消息隊列中,然後有一個任務執行者去按順序執行這些任務。
三,系統架構
1,功能設計
a,登陸
一般都是需要接第三方登陸,登陸這一塊是http操作,我們統一提供一個web服務,用來做登陸驗證。因為在登陸時,調用第三方的http服務,這個過程可能很慢,如果放在邏輯伺服器的話,可能會卡業務邏輯任務。因為可能不同的玩家業務請求可能同在一個線程中,如果有任務卡了,那麼這個任務以後新來的請求請會卡住,導緻消息延遲。
b,擷取遊戲公告,也放在web服務中。公告一般是遊戲登陸的時候向伺服器擷取一次。把它放在web伺服器中,與業務邏輯分離的好處是,當業務邏輯伺服器維護或更新的時候,不影響使用者的登陸,和擷取公告,這樣使用者體驗會好一些。
c,建立使用者唯一的id,因為棋牌類遊戲伺服器是世界服,無分區,是以使用者的id必須是全局唯一的。可以利用redis的incr方法,原子的遞增,如果不想被别人根據userid的遞增推算出有多少注冊使用者,遞增的梯度可以随機,比如每次遞增的值從1到1024中随機一個。
d,建立房間,當房間主建立房間時,房間的id需要在任何台伺服器上可以查詢到,是以建立房間成功後,房間id要存儲在共享記憶體redis中,每個房間id對應一個房間所在的ip位址或伺服器id.這樣,當有使用者要進入房間,在查詢房間id時,可能判斷這個房間是否和自己登陸的遊戲伺服器相同。
e,查找加入房間
根據房間id查詢房間,查找到房間後,擷取房間所在的ip位址或伺服器id,如果發現和自己所登陸的伺服器一樣,直接可以加入房間。如果不一樣,把這個房間所在的ip和端口傳回給用戶端,讓用戶端重新與房間所在的伺服器建立連接配接,使用登陸時的token驗證使用者。
f,遊戲腳本調用
在驗證遊戲是否合法時,用戶端與伺服器都要驗證,驗證的算法是一樣的,是以可以使用腳本來寫,寫一份腳本,在伺服器與用戶端中同時使用。可以使用lua。同一個算法使用同一個腳本 ,這樣在開發新的同類型棋牌遊戲時,隻需要替換一下這個腳本就行了,不用再重複開發。
3,背景管理系統
這個一般是根據營運需求開發的,每個公司不一樣。不過有一點,背景管理系統可能要和遊戲伺服器通信,這種通信方式最好是采用redis的訂閱/釋出機制。這樣可以把某個消息事件同時發送到所有的業務伺服器上面。根據使用者所在的伺服器進行處理。
4,玩家同屏
玩家同屏是棋牌遊戲中的一個重點,對于做過那些大型的arpg,或mmo遊戲的程式員來說,這并不是什麼難事。因為同屏就是伺服器對用戶端的消息進行轉發。一個房間四個人,一個人出的牌或操作能被其他三個人同時看到。
因為棋牌遊戲的同步資料量比較小。一般常見的同步方式有兩種:
1,用戶端主動拉取。
用戶端定時主動向伺服器請求一個使用者的消息隊列,當一個玩家有操作需要同步到其他玩家時,在伺服器端先把這個消息放到這個使用者的消息隊列中。等待用戶端的拉取操作。這種方式的好處是,不需要考慮網絡閃斷或網絡不好的情況,資訊都是同步擷取的。缺點是,定時拉取的時間間隔很短,可能不到一秒就會拉取一次。
2,伺服器主動推送
當一個使用者出牌的消息需要同步給其他玩家時,伺服器會獲得這個玩家與伺服器建立的socket連接配接,然後伺服器使用socket 主動向用戶端發送消息。
這種方式要考慮網絡閃斷,消息丢失的問題。因為伺服器推送的消息,用戶端有可能會收不到。是以用戶端需要根據心跳來判斷網絡是否有斷開過,如果有斷開,需要重新從伺服器拉取整個房間狀态的消息。或者根據伺服器發送的消息号,如果用戶端發現接收到的伺服器消息号有跳号的,比如應該接收10,卻收到了12,說明中間有消息丢失,需要重新拉取整個房間的狀态資訊。
這種方式的缺點是,開發複雜,需要考慮一些網絡問題。優點是,隻有在有消息的時候才會推送,沒有的話不推送,不占用帶寬等系統資源,可以增加使用者同時線上量,也就是增加了伺服器的承載量。
5,資料同步和持久化
1,由于棋牌類的遊戲資料少,計算量也小,是以完全可以不使用記憶體緩存,而直接使用redis共享記憶體,使用者的所有資料都緩存在redis中。更新也同步更新到redis中,這樣不管一個使用者登陸哪一台業務伺服器,都能獲得自己的最新資料。
2,更新資料庫,由于資料第一緩存是redis,是以活躍的使用者資料都是可以從redis中直接獲得的,而不用查詢資料庫,是以資料庫的更新可以采取異步更新,而不會産會資料的延遲。需要注意的一點是,資料的異步更新必須保證是有順序的。那麼這就會産生一個問題,怎麼保證使用者的更新不會亂呢?
3,如何保證更新的順序性
因為我們的業務伺服器是多個的,使用者可能連接配接其中的任何一個,如果說登陸的是伺服器A,加入的房間在伺服器B上,那麼連接配接就會切換。為了保證資料更新的順序,我們可以做一個資料庫持久化服務,把需要更新資料庫的任務實時發送到這台伺服器上,由資料庫持久化服務執行對資料庫的更新。這樣不管使用者連接配接的哪台業務伺服器,它的更新都是有順序保證的。
4,一種快速簡單的方法
由于棋牌類的業務少,資料更新少,是以查詢可以有redis緩存,減少資料庫查詢的壓力,而更新實行實時更新到資料庫,前期不需要開發資料庫持久化服務。等使用者積累到一定程式之後,發現更新資料庫比較慢的時候,再單獨做一個資料庫持久化服務。
四,伺服器架構

1,登陸時,用戶端首先向登陸的web伺服器請求登陸資訊,登陸成功之後,傳回登陸的token,為了适應大規模的web請求和登陸服務的穩定,可以使用nginx做負載均衡。
2,登陸成功之後,請求負載均衡伺服器,擷取一台連接配接的業務伺服器。這個負載均衡伺服器可以和登陸web在一個程序中,也可以獨立出來。
3,拿到登陸成功的token和需要連接配接的業務伺服器的ip和端口之後,再去連接配接業務伺服器。連接配接成功之後,要使用token到登陸伺服器去驗證,這個使用者是否登陸了。
4,同一個房間的使用者要連接配接到同一台實體伺服器上面。在上面已經說過了。
5,redis用來做共享緩存。
6,mysql做持久化存儲。
7,資料庫持久化伺服器,統一做資料入庫操作。
五,關于網關的問題
1,網關的作用
a,轉發消息包
b,業務的負載均衡,比如A業務由伺服器a處理,B業務由伺服器b處理,由網關進行轉發。
c,維護與用戶端的連接配接
d,帶寬的整合,一般的雲服務都是按購買的伺服器計算帶寬的。通過一台伺服器轉發消息,可以隻購買一個大帶寬就可以了。以節約成本。
2,棋牌類遊戲需要網關嗎?
我認為不太需要,因為棋牌類遊戲業務比較單一,做的最多的就是消息同屏轉發。最多是再有一些任務或活動,這些由一台伺服器直接處理完全可以搞定。而且開發網關也是一個複雜的工作,沒必要在這個上面花太多的時間。
轉自遊戲技術網:http://www.youxijishu.com/h-nd-157-2_323.html