卡牌游戏后端架构特色

  1. 分区分服运营

    开服节奏快,滚服玩家多,老服玩家流失率高,造成存储数据中有效率较低。

  2. 开服时创角压力大

    OB时流量迅猛,写压力相对较高。

  3. 平时在线量低,活动节点在线量暴增

    平时数据库读写压力小,0点及部分活动时间,活跃玩家人数暴增,数据库读写压力也会暴增。

  4. 离线玩法多

    离线数据读写相对较多,但还是集中在战力比较靠前的活跃玩家。

  5. 跨服社交类玩法多

    跨服玩法多,尤其是跨服匹配类玩法,造成单服全员参与的排行榜设计较多。

  6. 运营后期合服需求多

    老服留存低,长线运营后,老服存在鬼服情况多,合服需求势在必行。

少三为什么选择 Redis

  1. 读写速度快

    Redis 是内存数据库,能支持超过 100K+ 每秒的读写频率。

  2. 开发成本低

    Redis 是一个 key-value 存储系统,并且支持多种数据类型,包括 set,zset,list,hash,string五种数据类型,操作非常简单。

  3. 离线玩法实现简单

    Redis 是内存数据库,全量数据均在内存中,玩家的离线数据和在线数据没有区别,也没有冷热数据读写差异。

开发 RedisLV 的原因

  1. 数据持久化对业务有影响

    Redis 分别提供了 RDB 和 AOF 两种持久化模式,但实际使用中对业务均有一定的不利影响。RDB 方式虽然是 fork() 出一个子进程来进行持久化工作,表面上对业务没太大影响。但在内存空间相对有限的游戏服务器,且完全依赖内存的Redis系统来说,持久化时瞬间的内存暴增是一个灾难。而AOF方式持久化的数据恢复速度也是一个问题,维护时对业务的影响时间较大。

  2. Redis + ssdb 的设计存在数据不同步的风险

    为避免 Redis 持久化对业务的影响,我们专门起了一个进程,负责将 Redis 的操作同步写入到ssdb中,虽然解决了 Redis 持久化对业务的影响,但也造成了 Redis 和 ssdb 数据不同步的风险。

RedisLV 的痛点

先介绍一下 RedisLV,RedisLV 是 Redis + LevelDB 的组合设计,是我们前技术大牛霸首对 Redis 的一次魔改,在 Redis 内存操作基础之上加上 LeveDB 的存储操作。我们几个项目使用下来也发现一些痛点,这些痛点在卡牌游戏业务中也能忍受,但总归缺少了点什么,我们的新项目就必须直面这些问题:

  1. 内存占用高

    我们是 AllInOne 的设计,游戏进程、Redis 进程、ssdb 进程均在同一台服务器上,然后 Redis 仅用到了其内存数据库的特性,导致其对内存空间的依赖,对服务器内存配置要求就相对较高了。

  2. key-value 存储系统不利于数据迁移与合服

    key-value 存储系统的存储 key 之间没有关联,一个玩家的数据存在很多个存储 key。如果没有合理规划的话,上百的存储 key 都有可能(少三项目有近150个玩家的存储 key),非常不利于数据迁移及合服,玩家级数据备份也存在困难。

  3. 写操作对磁盘 IO 性能有依赖

    这个问题应该是 RedisLV 设计之初没有考虑到的一点,我们都知道 LevelDB 的存储也是写内存,写操作不会直接写磁盘,为什么还会有对磁盘IO的性能依赖呢?而且即使是写磁盘,LevelDB 的顺序写文件,对磁盘也是最温柔的写操作啊。但我们忽略了 SST 文件合并这个操作,一旦某一个 level 的 SST 总文件大小超过一定限制,就会触发 Major Compaction,即 SST 文件合并。Major Compaction 简单来说就是会把 level n 和 level n+1 层的部分文件进行合并,重新写入到 level n+1层。这个过程会非常复杂,会对磁盘形成瞬间的 IO 压力。

其他可能方案

Redis + MySQL

这是一个游戏行业里常见的数据存储方案,Redis 作为内存数据库使用,数据落地存储到 Mysql 中。业务侧需要把 Redis 读写操作和 MySQL 操作进行封装,业务侧使用时无感,这样的同步写操作对 MySQL是一个考验。当然也有做异步写的方案,则会面临一个新的问题,Redis 和 MySQL 数据一致性问题,同样考验着框架设计者的能力。

优点:

  1. 备份、数据迁移、合服方便;

缺点:

  1. 异步写 MySQL 存在数据一致性问题;
  2. 存在冷热数据交换对读速度的影响,对业务开发要求也高;
  3. 读写操作复杂,封装要求高;
  4. 单服全员排行榜需要另外的 Redis 存储或代码设计辅助;

云 Redis

云 Redis 是由云厂商提供的一套数据库系统,兼容开源 Redis 协议标准的、提供持久化的内存数据库服务,有高可靠及可扩展的集群架构优势,能够满足高读写性能场景及容量需弹性变配的业务需求。

优点:

  1. Redis 的优点都有;
  2. 功能强大,维护省心,工具完善;

缺点:

  1. key-value 设计,合表不方便;
  2. 对云厂商的依赖性较大;
  3. 成本相对自建高很多;

MogoDB

MongoDB 是一个高性能,开源,无模式的文档型数据库系统,使用 C++ 语言编写。MongoDB 是面向文档的,它可以管理类似 JSON 的文档集合。数据可以被嵌套到复杂的体系中并保持可查询可索引,让应用程序可以以一种更加自然的方式来为数据建模。

优点:

  1. 内存占用可控,有冷热数据交换机制;
  2. NoSQL 设计,无表结构概念,也支持合表;

缺点(问题):

  1. 最大的问题就是问题未知,无应用经验;
  2. 读写速度比 Redis 稍慢;
  3. 单服全员排行榜需要另外的 Redis 存储或代码设计辅助;

理想中的存储方案

什么才是卡牌游戏理想中的存储方案,我们觉得必须满足以下几个条件:

  1. 读写操作简单,速度快;
  2. 有成熟的冷热数据交换机制,可节约内存;
  3. 读写及备份操作不能影响业务,可接受有限的数据不一致;
  4. 能够支持合表,能够支持玩家数据迁移及合服;
  5. 可接受集群化,总体内存使用可控即可;

经过一段时间的考察,我们发现 MongoDB 算是一款比较接近理想中的存储系统,但还需要一些验证,后续验证数据会再次进行分享。大家对这个方案认可吗,或者还有更好的建议,欢迎一起讨论。

少年码上记-微信公众号