导语 大哥说,今年手Q游戏的春节红包你来做。那该怎么做?以及怎么做才能让大哥放心?本文从后台的角度出发讲述了这个过程和方法,对于关键的前台部分也有所涉及。
目录
- 1.需求背景
- 1.1.红包类别
- 1.2.体验流程
- 1.3.后台需求
- 2.需求分析
- 2.1.礼包列表
- 2.2.区服信息
- 2.3.领取礼包
- 3.整体方案与项目分解
- 4.需求开发
- 4.1.功能需求开发
- 4.2.性能需求开发
- 4.3.容错需求开发
- 4.4.监控需求开发
- 5.系统保障
- 5.1.系统容灾
- 5.2.过载保护
- 5.3.柔性可用
- 5.4.立体监控
- 6.演习验证
- 6.1.灰度演习
- 6.2.压测演习
- 6.3.异常演习
- 7.总结
1. 需求背景
1.1.红包类别
2017 年的手 Q 春节游戏红包共有刷一刷/ AR 地图/扫福三种,如下图所示:
1.2.体验流程
虽然红包分三种,但在游戏业务侧这边的体验都是一样:用户得到一个红包卡券,打开后展示一个(刷一刷红包)或者多个(AR 地图红包)游戏的礼包列表,用户选择一个礼包后弹出区服组件,用户确认对应的区服角色信息后会礼包会在 48 个小时内发放到账。体验如下:
1.3.后台需求
游戏红包的设计容量为入口卡券页流量 80k/s,以上体验流程一共涉及三个后台接口:
- 礼包列表:用户界面的礼包内容需要根据后台接口返回礼包列表进行排序和过滤展示
- 区服选择:用户界面弹出的区服组件需要后台接口返回用户区服角色信息
- 领取礼包:用户点击“确认”按钮领取礼包,后台进行游戏道具发货
2.需求分析
2.1.礼包列表
这个功能使用现有能力比较容易解决。活动共有十种游戏,每个游戏有两种礼包:拉新(面向非注册用户,价值 80 元)/拉活跃(面向注册用户,价值 20 元),一个用户只能获得这两种礼包中的一种,产品策略允许拉新的用户获得价值较低的拉活跃礼包,反之则不允许。页面展示按用户偏好排序十个游戏,每个游戏展示一个拉新礼包或者一个拉活跃礼包。
出于降低除夕当前流量负载和柔性考虑,在红包活动前,十种游戏的礼包内容作为前端静态数据已经预先通过离线包/CDN 下发;红包活动时,后台接口根据用户偏好返回的游戏礼包列表,只是提供前端礼包内容进行过滤和排序,失败了也有前端默认的游戏礼包列表,保障用户体验。
过滤:读取存储,用户有注册的游戏返回活跃礼包,用户没有注册的游戏返回拉新礼包。
排序:一个两层排序,第一层排序读取存储(key 为用户,value 为用户所注册的游戏列表),用户注册的游戏(拉活跃)排在用户没有注册的游戏(拉新)前面;第二层排序,对于拉新游戏列表和拉活跃游戏列表内部,使用神盾算法对用户这10款游戏的偏好再进行二次排序。对于外部接口的依赖只有 CMEM 存储和神盾算法接口,这两个接口以及合并这两种数据给出最终的个性化推荐礼包列表接口都可以平行扩容以支持 100k 级别的 QPS。
2.2.区服信息
这个功能是现有能力。这个角色信息的来源是 IDIP ,但由于该接口较缓慢(2s 左右)且容量较低(低于 10k/s),故后台做了一层缓存,将 IDIP 的区服信息永久性缓存到 CMEM 中,前台也有本地缓存,在实践中,前台缓存命中率为 60%,后台为 35%,多级缓存后走到 IDIP 的请求量只有5%,对 IDIP 影响不大,只需要扩容现有的区服 server 和 CMEM 即可。
2.3.领取礼包
这个功能使用现有能力解决存在困难。游戏中心日常发货的道具和平台比较多,平台分为 IEG-AMS/MP 两种,MP 发货对于发游戏道具和发 Q 币又是两种接口,故我们在架构上使用 Facade 模式,使用 AMS 作为发货 proxy,屏蔽了底层发货的复杂性,向游戏中心提供统一的发货接口,但比较遗憾的是从AMS 到游戏的发货接口都是同步接口,发货能力较低,发货能力最高的王者荣耀也只承诺了 3k/s 的发货速度,明显不足以直接承受 100k/s 级别的红包发货,故这里的核心问题是需要有一个队列来解决生产/消费速度不对等的问题。
去年的红包是后台收到发货请求后落地到本地文件返回用户成功,再由一个本机的 daemon 跑落地文件按游戏方所能提供的发货速度进行实际发货,相当于使用本地队列缓冲。但这个方案存在某台机器挂掉后如果不能恢复会丢失一部分本地的发货数据造成漏发,以及每个高并发业务都要重新做这一套东西不方便通用的问题。
从架构上思考,其实最合理的方案是作为发货 proxy 的 AMS 提供异步发货的能力,将用来解决生成/消费速度不匹配的 MQ 做在 AMS 内部,为业务提供通用的异步发货能力,业务侧就不需要考虑发货超过游戏方能力的问题,新业务有类似的场景也不需要重新开发。
游戏中心是业务侧,AMS 是平台侧的能力,属于另一个中心的业务,于是一开始我们准备推动 AMS 做异步发货的能力,这样业务就只要调用发货接口就可以了,很是方便。但事情并没有想象中顺利,与 AMS 的开发和 PM 开会沟通了几次,异步发货的能力他们也有做技术规划,但年前他们有其它需求要做,没有时间支持。和 leader 讨论了一下这个能力最好还是放在 AMS 做成通用以便以后有同样场景的业务使用,前台也有同学开发过 AMS 功能,可以由游戏中心业务侧的前后台同学合作完成 AMS 异步发货功能的开发,在春节红包中应用,再将这个功能交接给平台侧的同学维护,达到双赢的效果。
3.整体方案与项目分解
整体方案图如上图所示,由于整个项目涉及多方开发,而且模块较多,整个模块的开发周期较长,作为一期开发的话无法跟上基础侧卡券的验收和安排的几次演习/压测,故按「大系统小做」的原则,根据模块的重要和紧急程度分为几期迭代完成,每一期有独立的里程碑目标并达到对应的验收/演习/压测要求:
第一期(方案图左侧部分)为功能需求,在 12 月 9 号上线通过卡券方面功能验收,先使用当前的同步发货接口,对性能无特别要求。
第二期(方案图右侧偏左部分)为性能需求,在 12 月 20 号上线参加第一次演习,对发货进行异步化改造,要求直接面向用户的外网发货接口能支持 100k QPS 的峰值流量。
第三期(方案图右侧偏右部分)为容错需求,在 12 月 27 号上线参加第二次演习,对发货进行对账补送改造,保证发货的可靠性。
第四期为监控需求,在 1 月 6 号上线参加第三次演习,确认各项关键数据的采集,并将采集到的数据展现到一个统一视图上,以便除夕期间值班人员实时了解红包系统的整体运行情况和出数据报表。
4.需求开发
4.1.功能需求开发
核心问题:不同场景的数据一致性
{3.1 后台礼包推荐接口}为用户推荐礼包,用户领取时需要经过{4.1 AMS 外网发货新 OP}校验领取资格,后台的推荐数据必须能和 AMS 的资格校验数据能够对上,否则会出现后台推荐的礼包用户领取时却通不过 AMS 的资格校验导致领取不了的问题。
{4.1 AMS 外网发货新 OP}接口处理的是单个游戏的领取礼包的请求,资格校验操作判断一个用户是否注册了某个游戏。这个是 AMS 现有的通用功能,数据存储在 AMS 的 CMEM 中,简化描述就是一个 key-value 模型,key 为 uin+appid,value 如果有注册则为 1,没有则为 0(实际为了节省存储空间,使用 bitmap 桶实现,具体参见号码包系统使用文档),导入的数据源是产品在除夕前一周提供 10 款游戏的全量注册号码包,每个游戏一个文件,文件内容是注册用户的 QQ 号。
但{3.1 后台礼包推荐接口}接口返回的是多个游戏的礼包列表,需要获取十个游戏的用户注册状态。如果读取 AMS 现有的接口/存储,会有两个问题:
- AMS 号码包服务也要承受等同于推荐列表接口 48k/s 的流量,需要进行扩容。
- AMS 号码包服务调用 CMEM 虽然可以一次请求合并 10 个 key 进行批量读取,但请求到了 CMEM 的 Access 机还是要读取多个 Cache 块,性能并不如单请求单 key 读取。
解决方案:同质异构的数据冗余
后台将号码包数据进行重新组织存储到后台申请的另外一个 CMEM 中,key 为 uin,value 为用户已注册的 appid 列表,已注册的游戏推荐拉活跃礼包,没注册的游戏推荐拉新礼包,这样只需要查询一次 CMEM 就可以得到十个游戏每个游戏的礼包推荐类型是拉新还是拉活跃。
由于 AMS 和后台使用的是同一份号码包数据,只是应用场景不同,数据组织形式不同,两份 CMEM 数据同质异构,故后台推荐的礼包可以通过 AMS 的资格校验。
4.2.性能需求开发
核心问题:用户领取礼包流量远超游戏发货能力
红包活动具有时间短(单场 5~30 分钟)、大用户量参与(1.5 亿+)参与的特性,请求并发高,游戏红包入口流量设计为 80k/s,流经各个模块有衰减也有增幅,最终用户领取礼包请求预估为 96k/s,而游戏方提供的十款游戏总发货能力只有 5k/s(单款游戏最大为王者荣耀 3k/s),请求峰值接近处理能力的 20 倍,同步调用会导致游戏方发货接口过载,造成大面积发货失败,这个问题如何处理?
解决方案:发货异步化
使用一个缓冲队列来解决生产消费能力不对等的问题。用户领取请求到达 AMS 进行基础的资格校验后将请求放入 MQ 中,返回用户成功并告知会在 48 小时内到账。再由后台发货 Daemon 从 MQ 中读取请求,通过限速组件控制保证以不超过游戏方发货能力的速率进行发货操作。使用的 MQ 是部门近来建设的 RocketMQ,具体参见会员消息队列( RocketMQ )接入指南。
4.3.容错需求开发
核心问题:安全发货
三场活动发放的礼包总数预计将近 4 亿,如何保障这些礼包对于合法用户能都发货到账,不少发也不多发?如何防范高价值道具被恶意用户刷走?有没有可能内部开发人员自己调用接口给自己发礼包?
解决方案:对账补送/订单号/安全打击/权限控制
- 订单号解决不多发的问题
用户领取礼包的接口{4.1 AMS 外网发货新 OP}调用成功,会为这个请求附带一个 UUID 生成的一个全局唯一的订单号,再放进 MQ 中,{4.3 AMS 内网发货 OP}从 MQ 中取出消息,调用游戏方发货接口前都会先校验这个订单号是否用过,没用过则将订单号以 key 的形式写入 CMEM,再进行发货操作。如果出现对同一个发货消息进行重复发货,则会发现订单号已经用过了不会进行实际的发货操作,保证以订单号为标识的同一个发货请求只会进行一次发货操作。
- 对账补送解决不少发的问题
发货失败是不可避免的,诸如网络波动/游戏方发货接口故障之类的问题都可能导致调用发货接口失败。在同步领取环境下,用户可以通过重试在一定程度上解决这个问题。但是对于异步发货,用户点击领取后发货请求由{4.1 AMS 外网发货新 OP}放入 MQ 中就算成功了,即使后台调用游戏的实际发货接口失败了没有实际到账,用户对此也无感知不能进行重试但是会投诉,后台发货系统必须通过自身的容错保证即使游戏方的发货接口不稳定偶尔会失败,用户所领的礼包能最终到。这里我们使用了对账补送方案。
对账:用户领取礼包调用的接口{4.1 AMS 外网发货新 OP}成功写应发流水,{4.3 AMS 内网发货 OP}调用游戏方发货接口的写实发流水,由于部分消息会堆积在消息队列中,这部分称为队列堆积流水。故实际要进行补发操作的流水由以下公式可得:
失败补发流水= 应发流水 - 实发流水 - 队列堆积流水。
由于订单号的存在,可以保证同一个发货请求重复发送也不会多发,对队列中堆积的消息提前进行补发操作也不会导致多发。故当队列中堆积的流水较少的时候,采用应发流水与实发流水的差集作为失败补发流水是合理,只是每个对账周期会对队列中堆积的消息进行两次发货操作,对性能略有损耗。
后台每个小时运行一次增量对账功能,检测 MQ 消息堆积量量低于某个阈值,则进行对账操作,截取上次对账到此时的应发流水/实发流水,两者相减得到补发流水。
补送:对对账操作得到的补发流水调用游戏方发货接口进行发货补送操作。
- 安全打击解决高价值道具防刷的问题
对于领奖的请求,都要求都要求带上登录态,对用户进行身份验证,同时对于高价值的道具开启安全打击,上报安全中心进行恶意用户校验,防止被恶意用户刷走。
- 权限控制解决内部人员监守自盗的问题
对于发货的机器都要安装铁将军,用户需要使用 RTX 名和 token 才能登录机器,审计用户在机器上的操作行为;
发货模块对于调用方是需要严格授权,调用方需要申请 key,包含程序路径、程序 MD5、部署模块等信息,保证发货功能不被随意调用。
4.4.监控需求开发
核心问题:红包涉及多个系统的自有监控,数据收集困难
在监控方面有两个主要诉求:
(1)我们对外提供的服务是否正常?如果有问题,如何快速地发现问题、分析问题?
(2)实时知道用户在整个系统的行为漏斗模型,每一步的转化率是多少?
游戏红包涉及红包基础侧/业务前台/业务后台/AMS/MQ 平台等多个合作方,各个系统有自己的监控系统,数据来源不一致,活动当天一个系统一个系统地收集的话效率太低。
解决方案:汇总各个系统的关键数据到一个视图
红包作为一个涉及多个子系统的聚合系统,我们需要一个汇总了各个子系统关键数据的整体视图,才能够较全面地监控业务核心指标,对系统和业务有较全面把控,避免在监控系统中跳转检索而耗费有限的时间,为迅速响应解决问题提供保证。
接口封装:虽然红包涉及的多个子系统,各自有各自的上报方式和监控系统,但是对于关键数据大都有提供 HTTP 形式的查询接口,我们通过封装,将接口的定义统一为 key-value 形式,以(监控项 id,开始时间,结束时间)为 key,value 为(开始时间,结束时间)段内监控id的值之和。
配置化:一场红包活动的监控,可以由一个时间段加若干个监控项定义。比如刷一刷红包,时间段为除夕当天 20:00~20:30,监控项为若干页面的点击量,若干礼包的发放量,若干后台接口的请求量,若干 MQ 的堆积量等等。
通过对接口的封装和配置化,新增一场红包活动,只需要增加一个时间段和若干个监控项的配置文件,比如下图的 AR/刷一刷混场/刷一刷专场就是通过 3 个配置文件定义 3 场活动,新增一场活动也只需要增加一个配置文件,并可以在一个视图上灵活切换,相当方便。
从上图中我们就可以实时看到实发和应发是大致相等的,队列没有出现堆积,用户在各级页面的转化率,可以很方便地判断系统的健康状态和分析定位问题。
相关推荐