现在做的游戏项目(bingo cooking)的排行榜服务是单进程的,它基于redis的sorted set对排行榜数据做排序。
需求大概是这样的
- 排行榜每天算一个赛季,每天结算一次
- 对所有玩家在游戏核心玩法中的得分做排行
- 整体上算一个“大榜”,有多个“子榜”,即青铜、白银、黄金、白金、钻石
- 新玩家加入排行榜的时机的控制
- 可以实时更新玩家得分,同时要更新玩家在子榜上的排名
- 玩家分数符合某种规则后,跃迁到新的榜,如青铜到白银
主要功能可概括为
- 对外(即实现游戏核心玩法的游戏服)提供接口实时更新玩家得分的接口
- 每天做一次结算
现在的情况
- 处理游戏核心玩法的进程有多个(以下简称为G)
- G通过http请求排行榜服务的接口以更新玩家得分
- 结算时,排行榜进程要通过http请求G,G负责给玩家发奖励
单进程的排行榜不具备高可用的特性,所以我想对其做一些改造
- 排行榜服务改为多进程
- 单独有一个排行榜进程(以下简称S)处理赛季结算,不处理玩家分数更新。这样做之后,修改“赛季结算”功能时(部署代码或配置,然后重启进程)不影响玩家分数更新。
- S结算时从redis读的数据必须不能是再被修改的。可通过安排合适的开始结算时刻来达到这个要求。
- 其他排行榜进程(以下简称R)处理玩家分数更新,不处理赛季结算。这样做之后,修改“更新玩家分数”相关接口的实现时(部署代码或配置,然后重启进程)不影响赛季结算。
- R在修改redis数据时,可能要使用“事务”、“分布式锁”等机制以“同步”多进程同时读/写相同数据的行为。
- G向R发起请求,中间加一个代理(Nginx或者AWS ELB皆可),代理上配多个R的IP、PORT、endpoint等信息。这样做之后,如果有部分R不可达(功能更新时的重启,进程BUG或崩溃,或网络、硬件故障),可以将请求转发到其它R。
- S向G发起请求,中间加一个代理,代理上配多个G的IP、PORT、endpoint等信息。这样做之后,结算可以通过多个G完成,不需要限定为一个G。可以达到这样的效果:如果结算过程中部分G不可达,仍然可以完成结算。
- 被代理的目标进程(R或G)日常部署重启前,先从代理中摘除。进程重启完成并可以正常提供服务后再加入到代理中。也就是“迭代更新”