華為云計(jì)算 云知識(shí) 使用分布式緩存服務(wù)DCS實(shí)現(xiàn)游戲開合服的數(shù)據(jù)同步
使用分布式緩存服務(wù)DCS實(shí)現(xiàn)游戲開合服的數(shù)據(jù)同步

方案概述

應(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

      同一VPC內(nèi)網(wǎng)絡(luò)默認(rèn)互通。

    • 客戶端與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í)施步驟

  1. 使用Redis-py庫中的Redis()方法在每個(gè)游戲服務(wù)器上創(chuàng)建一個(gè)Redis客戶端連接。
  2. 使用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ù)。
  3. 定義一個(gè)publish_update()方法發(fā)布更新消息,并在listen_updates()方法中使用subscriber.listen()方法來監(jiān)聽更新消息。
  4. 當(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'