游戏后端内存和持久化的一致性问题
引发这个问题的思考是来自开发中的一个问题。场景是这样的,中台向游戏服务端发放用户的道具,服务端收到发放用户道具请求时,需要解决下面几个问题:
- 用户在线和不在线的处理区别
- 用户在线时收到道具的客户端通知和状态同步
用户在线和不在线的处理区别
用户的状态数据在内存中有一份、在硬盘中有一份。客户端的状态通常依赖于内存中的用户信息,也就是内存数据和硬盘数据的更新存在延迟性。为了提高响应性,对于用户信息的修改和查询应该优先内存,用户信息延迟入盘。
但是无法保证后台在发放道具或者什么更改用户信息的操作时,用户在线数据存在于内存中,所以对用户离线的情况,也就只能优先硬盘,在用户加入游戏时重新加载数据。
提高响应性的代价是存在数据丢失的风险,内存往往是不安全的,如果在内存中的用户信息还未来得及持久化时,服务器崩溃,就会导致用户信息的丢失。这是非常严重的,可能会带来巨大的损失,比如付费道具的发放。为了提高安全性,建议采用持久化优先的策略,优先持久化到硬盘,直到发放端知道入库成功,在通知服务端将数据加载进内存,通知客户端更新状态。
内存和硬盘持久化的数据一致性问题
本质上这个问题就是内存和硬盘持久化的数据一致性问题,持久化优先策略是常用的策略,但不是所有的情况都适用与持久化优先,这需要根据情况而定。如果有些场景需要背包道具信息的变化的响应非常高,并且数据丢失的损失不大的情况下,持久化优先策略反而会导致体验的下降。
分布式环境下道具发放通知一致性问题
同一个游戏逻辑节点为提高可用性,可能会启动多个相同节点,第三方中台对用户的操作在内存优先的高响应的道具系统下会带来分布式跨服上的问题,如果需求要求我们具有高响应的道具收发响应,就需要解决跨服带来的数据一致性的问题。
这个问题是这样的,在内存优先策略中,发放道具的消息会随机打到一个服务器上。此时服务器会查看发放对象是否存在于自己的服务器,假设此时玩家在这个服务器上,然后用户掉线重连,会重新拉取数据库的道具信息,导致内存被刷回去,道具发放无效。这是第一个问题!
第二个问题,同样是用户收到道具后掉线,掉线后马上重连,那么在上一台带有新道具状态的数据持久化之前,用户重连进新的服务器并拉取到老的道具信息。上一台带有新道具状态的数据持久化后,用户下线会把自己拿到的老的道具信息重新刷回数据库,导致道具发放无效。