方案概述
應(yīng)用場景
游戲業(yè)務(wù)開合服,指一些大型網(wǎng)絡(luò)游戲?yàn)榱宋峦婕遥谶\(yùn)營一段時(shí)間后,會(huì)開啟新服務(wù)區(qū),當(dāng)新服務(wù)區(qū)開放后,老服務(wù)區(qū)用戶存在流向新服務(wù)區(qū)的趨勢,用戶數(shù)逐漸減少,為了改善老服務(wù)區(qū)用戶的游戲體驗(yàn),延長游戲生命周期,游戲開發(fā)商通常會(huì)進(jìn)行新老服務(wù)區(qū)合并,將新開和原有的兩個(gè)服務(wù)器(區(qū))的數(shù)據(jù)合并到一個(gè)服務(wù)器(區(qū)),使新老玩家就能在同一個(gè)區(qū)進(jìn)行游戲。在這個(gè)過程中,會(huì)遇到如何將不同服務(wù)器數(shù)據(jù)同步的相關(guān)問題。
解決方案
在游戲開合服方面,使用分布式緩存服務(wù)(DCS)的Redis緩存可以應(yīng)用到以下場景:
- 跨服數(shù)據(jù)同步
游戲合服后,需要將多個(gè)游戲服務(wù)器的數(shù)據(jù)進(jìn)行同步,以保證游戲數(shù)據(jù)的一致性。可以使用Redis的消息隊(duì)列pub/sub機(jī)制,將數(shù)據(jù)變更消息發(fā)布到Redis的頻道中,其他游戲服務(wù)器訂閱該頻道,接收數(shù)據(jù)變更消息,從而實(shí)現(xiàn)數(shù)據(jù)同步。
- 跨服資源共享
游戲合服后,可以將多個(gè)游戲服務(wù)器的資源進(jìn)行共享,例如玩家道具、金幣等。可以使用Redis的分布式鎖機(jī)制,來保證多個(gè)游戲服務(wù)器對資源的訪問互斥,避免資源沖突。
- 跨服排行榜
游戲合服后,可以將多個(gè)游戲服務(wù)器的排行榜進(jìn)行合并,以展示全服的排名情況??梢允褂肦edis的有序集合機(jī)制,來存儲(chǔ)排行榜數(shù)據(jù),并進(jìn)行排名計(jì)算和查詢。
在以上三種應(yīng)用場景中,“跨服資源共享”的實(shí)現(xiàn)方式可以參考使用DCS實(shí)現(xiàn)熱點(diǎn)資源順序訪問,“跨服排行榜”的實(shí)現(xiàn)方式可以參考使用DCS實(shí)現(xiàn)排行榜功能。
本篇文檔主要介紹如何通過Redis的消息隊(duì)列pub/sub機(jī)制,實(shí)現(xiàn)“跨服數(shù)據(jù)同步”。
在使用Redis進(jìn)行游戲合服方面的應(yīng)用時(shí),需要考慮數(shù)據(jù)一致性、性能和安全等方面的問題,避免出現(xiàn)數(shù)據(jù)錯(cuò)誤、性能瓶頸或者安全漏洞等問題。
前提條件
- 已創(chuàng)建DCS緩存實(shí)例,且狀態(tài)為“運(yùn)行中”。
- 客戶端所在服務(wù)器與DCS緩存實(shí)例網(wǎng)絡(luò)互通:
- 客戶端與Redis實(shí)例所在VPC為同一VPC
- 客戶端與Redis實(shí)例所在VPC為相同region下的不同VPC
如果客戶端與Redis實(shí)例不在相同VPC中,可以通過建立VPC對等連接方式連通網(wǎng)絡(luò),具體請參考:緩存實(shí)例是否支持跨VPC訪問?。
- 客戶端與Redis實(shí)例所在VPC不在相同region
如果客戶端服務(wù)器和Redis實(shí)例不在同一region,僅支持通過 云專線 打通網(wǎng)絡(luò),請參考云專線。
- 公網(wǎng)訪問
客戶端公網(wǎng)訪問Redis 4.0/5.0/6.0實(shí)例時(shí),需要開啟實(shí)例公網(wǎng)訪問開關(guān),具體請參考開啟Redis 4.0/5.0/6.0公網(wǎng)訪問并獲取公網(wǎng)訪問地址。
實(shí)施步驟
- 使用Redis-py庫中的Redis()方法在每個(gè)游戲服務(wù)器上創(chuàng)建一個(gè)Redis客戶端連接。
- 使用pubsub()方法在每個(gè)游戲服務(wù)器上創(chuàng)建一個(gè)Redis訂閱者和發(fā)布者。用于訂閱其他游戲服務(wù)器發(fā)布的消息,以及發(fā)布本地游戲服務(wù)器的數(shù)據(jù)更新消息。當(dāng)某個(gè)游戲服務(wù)器需要更新數(shù)據(jù)時(shí),它會(huì)將更新的消息發(fā)布到Redis消息隊(duì)列中。其他游戲服務(wù)器會(huì)收到更新消息并相應(yīng)地更新各自的本地?cái)?shù)據(jù)。
- 定義一個(gè)publish_update()方法發(fā)布更新消息,并在listen_updates()方法中使用subscriber.listen()方法來監(jiān)聽更新消息。
- 當(dāng)收到更新消息時(shí),通過調(diào)用handle_update()方法來處理更新消息并更新本地?cái)?shù)據(jù)。在游戲服務(wù)器中,通過調(diào)用publish_update()來發(fā)布更新消息,以及調(diào)用listen_updates()來監(jiān)聽更新消息。
示例代碼
以下是使用Redis-py庫實(shí)現(xiàn)消息隊(duì)列pub/sub機(jī)制進(jìn)行游戲跨服數(shù)據(jù)同步的示例代碼(本示例代碼以python2為例):
import redis # 創(chuàng)建Redis客戶端連接,Redis實(shí)例連接地址和端口需替換為實(shí)際獲取的值 redis_client = redis.Redis(host='localhost', port=6379, db=0) # 創(chuàng)建Redis訂閱者 subscriber = redis_client.pubsub() subscriber.subscribe('game_updates') # 創(chuàng)建Redis發(fā)布者 publisher = redis_client # 發(fā)布更新消息 def publish_update(update): publisher.publish('game_updates', update) # 處理更新消息 def handle_update(update): # 處理更新消息,更新本地?cái)?shù)據(jù) print('Received update:', update) # 監(jiān)聽更新消息 def listen_updates(): for message in subscriber.listen(): if message['type'] == 'message': update = message['data'] handle_update(update) # 在游戲服務(wù)器中調(diào)用發(fā)布更新消息的方法 publish_update('player_data_updated') # 在游戲服務(wù)器中調(diào)用監(jiān)聽更新消息的方法 listen_updates()
輸出結(jié)果:
D:\workspace\pythonProject\venv\Scripts\python.exe D:\workspace\pythonProject\test2.py Received update: b'player_data_updated'