卡牌游戏理想中的数据存储方案
卡牌游戏后端架构特色
-
分区分服运营
开服节奏快,滚服玩家多,老服玩家流失率高,造成存储数据中有效率较低。
-
开服时创角压力大
OB时流量迅猛,写压力相对较高。
-
平时在线量低,活动节点在线量暴增
平时数据库读写压力小,0点及部分活动时间,活跃玩家人数暴增,数据库读写压力也会暴增。
-
离线玩法多
离线数据读写相对较多,但还是集中在战力比较靠前的活跃玩家。
-
跨服社交类玩法多
跨服玩法多,尤其是跨服匹配类玩法,造成单服全员参与的排行榜设计较多。
-
运营后期合服需求多
老服留存低,长线运营后,老服存在鬼服情况多,合服需求势在必行。
少三为什么选择 Redis
-
读写速度快
Redis 是内存数据库,能支持超过 100K+ 每秒的读写频率。
-
开发成本低
Redis 是一个 key-value 存储系统,并且支持多种数据类型,包括 set,zset,list,hash,string五种数据类型,操作非常简单。
-
离线玩法实现简单
Redis 是内存数据库,全量数据均在内存中,玩家的离线数据和在线数据没有区别,也没有冷热数据读写差异。
开发 RedisLV 的原因
-
数据持久化对业务有影响
Redis 分别提供了 RDB 和 AOF 两种持久化模式,但实际使用中对业务均有一定的不利影响。RDB 方式虽然是 fork() 出一个子进程来进行持久化工作,表面上对业务没太大影响。但在内存空间相对有限的游戏服务器,且完全依赖内存的Redis系统来说,持久化时瞬间的内存暴增是一个灾难。而AOF方式持久化的数据恢复速度也是一个问题,维护时对业务的影响时间较大。
-
Redis + ssdb 的设计存在数据不同步的风险
为避免 Redis 持久化对业务的影响,我们专门起了一个进程,负责将 Redis 的操作同步写入到ssdb中,虽然解决了 Redis 持久化对业务的影响,但也造成了 Redis 和 ssdb 数据不同步的风险。
RedisLV 的痛点
先介绍一下 RedisLV,RedisLV 是 Redis + LevelDB 的组合设计,是我们前技术大牛霸首对 Redis 的一次魔改,在 Redis 内存操作基础之上加上 LeveDB 的存储操作。我们几个项目使用下来也发现一些痛点,这些痛点在卡牌游戏业务中也能忍受,但总归缺少了点什么,我们的新项目就必须直面这些问题:
-
内存占用高
我们是 AllInOne 的设计,游戏进程、Redis 进程、ssdb 进程均在同一台服务器上,然后 Redis 仅用到了其内存数据库的特性,导致其对内存空间的依赖,对服务器内存配置要求就相对较高了。
-
key-value 存储系统不利于数据迁移与合服
key-value 存储系统的存储 key 之间没有关联,一个玩家的数据存在很多个存储 key。如果没有合理规划的话,上百的存储 key 都有可能(少三项目有近150个玩家的存储 key),非常不利于数据迁移及合服,玩家级数据备份也存在困难。
-
写操作对磁盘 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 数据一致性问题,同样考验着框架设计者的能力。
优点:
- 备份、数据迁移、合服方便;
缺点:
- 异步写 MySQL 存在数据一致性问题;
- 存在冷热数据交换对读速度的影响,对业务开发要求也高;
- 读写操作复杂,封装要求高;
- 单服全员排行榜需要另外的 Redis 存储或代码设计辅助;
云 Redis
云 Redis 是由云厂商提供的一套数据库系统,兼容开源 Redis 协议标准的、提供持久化的内存数据库服务,有高可靠及可扩展的集群架构优势,能够满足高读写性能场景及容量需弹性变配的业务需求。
优点:
- Redis 的优点都有;
- 功能强大,维护省心,工具完善;
缺点:
- key-value 设计,合表不方便;
- 对云厂商的依赖性较大;
- 成本相对自建高很多;
MogoDB
MongoDB 是一个高性能,开源,无模式的文档型数据库系统,使用 C++ 语言编写。MongoDB 是面向文档的,它可以管理类似 JSON 的文档集合。数据可以被嵌套到复杂的体系中并保持可查询可索引,让应用程序可以以一种更加自然的方式来为数据建模。
优点:
- 内存占用可控,有冷热数据交换机制;
- NoSQL 设计,无表结构概念,也支持合表;
缺点(问题):
- 最大的问题就是问题未知,无应用经验;
- 读写速度比 Redis 稍慢;
- 单服全员排行榜需要另外的 Redis 存储或代码设计辅助;
理想中的存储方案
什么才是卡牌游戏理想中的存储方案,我们觉得必须满足以下几个条件:
- 读写操作简单,速度快;
- 有成熟的冷热数据交换机制,可节约内存;
- 读写及备份操作不能影响业务,可接受有限的数据不一致;
- 能够支持合表,能够支持玩家数据迁移及合服;
- 可接受集群化,总体内存使用可控即可;
经过一段时间的考察,我们发现 MongoDB 算是一款比较接近理想中的存储系统,但还需要一些验证,后续验证数据会再次进行分享。大家对这个方案认可吗,或者还有更好的建议,欢迎一起讨论。