集群实现细节(4)-冷热数据划分及同步
玩家数据在 Redis 与 MySQL 之间的同步
由于 Redis 操作可以保证多个进程读写同一个玩家数据时的原子性。所以之前多个逻辑服务器读写同一玩家数据时没有什么问题,但是现在 Redis 和 MySQL 之间需要同步玩家的数据(例如定时将 Redis 里的在线玩家数据刷进 MySQL 里做持久化)。这个同步的逻辑代码放哪呢?
观察需求特性,玩家上线加载到 Redis 做 Cache、定时更新持久层、玩家离线时清掉 Cache 并更新到持久层,都是 Redis 和 MySQL 之间的数据交互。这些可以放到一个服务里,单进程实现,或者集成到现在的逻辑服务器里。
方便实现,做下限制。玩家登陆的逻辑服务器记为他的 owner 服务器,每个玩家数据的 Redis/MySQL 同步只由他 owner 来做。 这样问题就简化了。
这里有些做法是突然想到的,就像《暗时间》里提到的联想式的,而不是归纳演绎的。最近在看《暗时间》,好书,里边就提到边写边思考,思考时“大脑内存”有上限的,边写就能把部分思考分支换出笔记这种“硬盘”上,然后大脑专心思考其中一两个分支,想的差不多,再回过头将“笔记硬盘”上的数据换入“大脑内存”……将正在思考的东西写博客的习惯已经形成一段时间了,看了书后,更深切体会到这种好处。
如果逻辑服务器宕机,它上边的玩家就掉线了,而这台逻辑服务器是不能对这些玩家做离线数据持久化的。这种情况需要进一步思考TODO。另外之前这种玩家怎么标记为离线,需要再想一遍,也TODO了。
从本质出发 Review 我们的存储架构
不要走的太远而忘了为什么出发,从本质上思考,弃掉那些不必要的思考分支,简化问题。
本质我们的架构是为实现游戏的玩法目标来做的,另一方面我们考虑开发成本、维护成本、机器成本。好的架构是权衡目标实现程度和这些成本的耗费。
目标是实现同一国家的玩家不分区分服。之前缓存和持久化都是用 Redis 来做,开发成本和维护成本都挺低的。但是需要很多机器。现在控制机器成本,所以需要分析我们数据的特点,将冷数据放到 MySQL 这种机器需求量少的数据库。具体到表的分析这里就不方便贴了。说下大概分类:
- (1)离线玩家的冷数据,离线玩家的私人数据,不需也不能与别人交互的;
- (2)离线玩家的热数据,例如名字,好友是想看到离线好友的名字的;
- (3)在线玩家的一直更新的数据,例如经验值,游戏货币等;
- (4)在线玩家的到强实时玩法时才更新的数据。
(1)里的数据无疑问放在 MySQL 里。(2)里的数据还得根据情况看是否一致放在 Redis 里,即离线的玩家这部分数据也放在 Redis 里。(3)里的数据无疑问在线是放到 Redis 里。(4)里的数据可以根据情况考虑下延迟加载什么的,即玩家上线时这部分数据不马上加载到 Redis,而是等玩家开始这个玩法时才从 MySQL 里加载到 Redis 里。这个需要考虑这个玩法的数据量以及是否玩家参与度高。
扩展
先了解 MySQL 单表数据上限、然后 MySQL 单库上限。这里的上限指不影响效率的上限,而不是物理上限。拿到上限数据后,做预分库分表。分库分表也要好好想想。
查了下,MySQL 5.1里 InnoDB 引擎表空间最大容量为 64TB。在查我们公司服务器配置表里硬盘,最低有 100G 的,最高 600 多 G 的。
初步确定 MySQL 的 sharding 和 partition 为这样:不同物理机之间的 sharding 为分个大的 ID 段,单个物理机上即单库内的如果表还是很大就做自己的 partition。最终看上线怎么定,再定这个跨机 sharding 的 ID 段长度,至于单机的 partition,对代码来说是不需要管的,运维根据性能搞就行了。
先简单算下,每人 100k,500w 人一个 sharding,需要大约 500G 空间。
其他架构展望
有单机内容;需要联网时才联网;弱联网时弱联网,强实时时做强实时联网。一直纠结这个会不会影响现在的存储架构,但是想了下,不大影响,变的只是链接形式,玩家数据处理还是一样的。