登录 |  注册
首页 >  网站架构 >  腾讯技术园 >  亿级 QQ 会员活动运营系统的设计之道

亿级 QQ 会员活动运营系统的设计之道

1. 前言

随着 QQ 会员用户的日益增涨,每周都要上线大量各种玩法的 H5 活动来满足产品和运营的需求。大概在 2014 年,那时手游非常火爆,我们部门有一个游戏特权小组(大概 10 多个人),就是专门每天开发这种游戏相关的 H5 活动的。上线一个活动,从需求评审到设计重构,再到开发,到测试,最后上线。整个流程下来,大概一周左右,效率非常低下,已经无法满足运营快速上线的诉求,并且重复性工作也非常多,对开发同学不能得到好的技术提升。于是,我们整个开发团队开始思考着怎么去提升开发和运营的效率。因此我们需要设计一套能快速上线、扩展性好、可复用性高的运营系统。于是,QQ 会员活动运营系统(以下简称 AMS)应运而生。

这里说的“道”,包含两层意思:一是这套系统设计的过程,二是从这套系统总结出来的方法思路。

2. QQ 会员活动运营系统简介(AMS)

2.1 AMS 简介

AMS 是一个包括重构、开发、测试、发布、运营、监控等全生命周期的活动运营平台。

AMS 最新统计数据大概如下:

  • 每年为部们运营的活动带来的收益为 100+ 亿;

  • 最新峰值PV为 10 亿 +,日均PV为 5 亿;

  • 每天 600+ 个活动在现网运营;

  • 4000 多个运营人员,10 多个业务部门在使用。

下图为 AMS 近 30 天的 PV 请求,10 月 28 日有活动推广,请求量达到峰值 10.61 亿。

qq.png

整个公司内部使用 AMS 的业务部们主要有:QQ 会员、QQ 浏览器、QQ 动漫、QQ 阅读、游戏中心、互娱、QQ 钱包、财付通、鹅漫 U 品等。

qq产品.png

2.2 什么是活动?

1. 活动的定义

简单来说,就是由一系列逻辑规则组合而成的一个 H5 页面。比如下面的截图,都是一个个活动。

2. 这些活动的规则一般比较多(这里的规则你可以理解为参与的条件,我们简称为 Rule),比如下面是我们业务比较常见的条件 Rule:

  • 是否为会员

  • 是否为超级会员

  • XX 游戏的注册时间是否大于 XX 时间

  • XX 游戏的游戏角色等级是否大于 XX 级

  • 最近是否登陆过 XX 游戏

  • 是否有抽奖机会

  • ……

3. 只要用户满足了上面指定的一些条件后,就能获得指定的奖励(一般是虚拟奖励),并给用户发货(这里的奖励发货我们简称为 OP),比如下面是我们业务比较常见的发货:

  • 游戏道具

  • 游戏礼包

  • 会员成长值

  • 1 个月的会员

  • Q 币

  • ……

当然,更多时候,这些活动的条件 Rule 都是 N(N > 1)个组合在一起的。比如,要满足的条件 Rule 为:

  • 条件一,是会员;

  • 条件二,最近登陆过天天酷跑游戏。

要满足上面 2 个条件,用户才能获得一个游戏礼包,那么这里的发货 OP 为:游戏礼包。

想当初,我们要实现上面的逻辑,我们会写出一个大的 API 接口,然后在这个接口里实现上面 2 个条件的判断,如果满足条件,就进行发货操作。这种开发模式持续了一大段时间后,我们发现重复性的工作太多,很多代码冗余,代码也越来越难以维护。为了避免这种问题,于是我们把上面这些条件 Rule 和发货 OP 进行抽象,并封装成一个个 Rule 和 OP 组件。然后,由 AMS API 引擎来进行加载并执行。

那么我们又是如何设计这套 API 引擎的呢?

3. API 引擎的设计

3.1 设计目标

经过自身业务场景的详细分析,我们的 API 引擎的设计目标为:

  • 每个接口请求都有一个唯一的活动号(actid);

  • 接口输入输出结构要统一,这样在前端才能做统一的解析处理;

  • 可灵活装载任意个规则组件(Rule);

  • 可灵活装载一个发货组件(OP)。

3.2 工作原理

根据上面设定的目标,API 引擎的运行流程图大概如下(注:这里进行了简化,实际情况要复杂得多):

捕获.png

每一个请求接口用参数活动号 actid 来标识,先用 actid 查询出相应的配置信息(包括基本信息、Rule 信息、OP 信息),然后读取其中的 Rule 组件信息,并一一执行相应的 Rule 组件。如果其中一个 Rule 不满足条件,则直接返回错误的 JSON;如果全部 Rule 都满足了,则加载发货组件 OP 并执行,最后返回成功的 JSON。下面我再详细说明。

1. 每个接口请求都有一个唯一的活动号

这里的活动号参数,标识了一个唯一的业务逻辑,你也可以理解为接口名。API 引擎会根据当前的 actid 从 CMEM 存储里获取当前 actid 的配置信息(包括所有的 Rule、OP 组件信息)。

假如有个活动的业务场景为:只有会员,且会员等级大于 4 的用户点击参与后可以获得一个虚拟货币。那么这个 actid 对应存储的信息可能如下所示:

 {
       "actid":302620,
       "name":"领取礼包",
       "status":0,
       "start_time":1502726400,
       "end_time":1606780800,
       "rulecfg":{
           "rulecfg":[
               [
                   {
                       "rule":{
                           "name":"club"
                       },
                       "type":"==",
                       "value":"1"
                   },
                   {
                       "rule":{
                           "name":"viplvl"
                       },
                       "type":">",
                       "value":"4"
                   }
               ]
           ],
           "rule":[
               "club==1&viplvl>4"
           ]
       },
       "opcfg":{
           "op":"add_money",
           "plist":{
               "money_id":"302620",
               "num":"1"
           }
       }
   }
  • rulecfg 结构: 表示存储了 Rule 名为 club 和 viplvl 两个组件,type 是运算符,value 是比较的值 。

  • Rule 结构: 表示最终生成的运算规则。

  • opcf 结构: 表示执行的 OP 信息。

2. 接口输入输出结构要统一

还是上面的例子。其对外 API 请求的接口地址为:

http://iyouxi.vip.qq.com/ams3.0.php?c=page&gtk=e4b0b73337ae43e4c62b40528c258b7b&actid=302620

执行成功后的返回 JSON 结果如下:

{
       "ret": 0,
       "data": {
         "act": {
           "start_time": 1502726400,
           "end_time": 1606780800,
           "op": "add_money"
         },
         "rule": {
           "club": "1",
           "viplvl": "4"
         },
         "op": {
           "num": 1
         },
         "actname": "领取礼包"
       },
       "time": "1542180520",
       "actid": 302620,
       "msg": "success"
   }
  • ret 返回码: ret=0 表示用户满足条件,参与成功;反之表示用户不满足条件,参与失败。

  • act 结构体:表示该活动的基本信息,如开始时间,结束时间等。

  • Rule 结构:存储了的 Rule 组件信息。

  • OP 结构体:存储了发货 OP 信息。 统一了这些主要的结构信息,前端的 JS 才能做统一的解析。

3. 灵活装载任意个规则组件 Rule

我们又是如何设计的呢?

首先,我们先了解下规则组件 Rule 是怎么设计的。这里用一个是否为会员的规则 Rule 为例子,这个 Rule 组件的代码大概如下所示:

 /**
    * 是否会员(0:非会员;1:会员;2:会员但非有效)
    *
    */
   class Rule_club extends CellBaseRule implements IfCellRule
   {
       public function run( $rulePregResult = array() ) {      
           $this->runValue = ClubService::isClub($this->uin);
           return Code::SUCCESS;
       }
   }


这里的代码其实很简单,就是判断下当前用户是否为会员。并把结果返回给 runValue,然后交给 API 引擎进行运算。CellBaseRule 类 和 IfCellRule 接口类主要是定义了一些全局性的方法和属性,这里不再详细解说。

主引擎 API 通过获取该活动 actid 的 Rule 配置信息,依次加载相应的规则 Rule 文件,并一一执行相应的 Rule 组件。

4. 装载一个发货组件(OP)

原理其实和 Rule 差不多,唯一不一样的是,OP 只能有一个,而 Rule 可以有多个。这是为什么呢? 主要是因为,如果发货 OP 有多个,一旦某一个 OP 发货失败,我们没有好办法去处理事务回滚的问题。每个 OP 做的事情可能都是不一样的,请求的服务接口也是不一样的。基于这种考虑,系统只允许执行一个发货 OP。不过对我们业务来说,基本也满足了。

3.3 运营管理系统简介

讲到这里,有些人一定会问,我们如何在指定的这个活动号中加载那些 Rule 组件和 OP 组件呢? 答案很简单,我们不光设计了这套 API 引擎,我们还搭建了一套运营管理系统,在这套运营管理系统上可以自由的新建活动号(actid),然后在每个 actid 中配置相应的 Rule 和 OP 组件。

假如我们要开发如下的 H5 活动:

QQ活动.png

那么我们只要在运营管理系统中新建 3 个活动 id。

一个 H5 活动的所有 actid 活动列表,这里配置了 3 个 actid。

有了这套系统,我们开发活动大大节省了人力,比如以上面这个活动 H5 的开发为例,我们从原来传统的开发流程为:

  • 写 3 个 API 接口,并编码实现所有的业务逻辑;

  • H5 图片中的三个按钮,分别请求相应的 API 接口。

演化后的开发流程:

在运营管理系统新建 3 个活动号,并在每个活动号 actid 配置上相应的 Rule 和 OP,如果之前开发了相应的 Rule 和 OP,则直接配置使用;如果是新的 Rule 或 OP,则去扩展开发(实现上到目前为止,AMS 现成的组件 Rule+OP 已接近 2000 个了,大部分的活动基本都可以复用这些组件);

在 H5 中的按钮绑定相应 actid 的 API 请求。

总结下 AMS API 引擎的设计特点,可以归纳为以下 3 点

  • 组件化,对重复的 Rule、OP 进行组件化设计;

  • 配置化,对执行流程中的 Rule、OP 进行可配置化;

  • 自动化,对人工配置的数据进行自动检查其正确性。

通过 AMS 系统一期的设计,大大降低了人力成本,原来一个人可能要一周完成的工作,现在基本 1~3 天就可以完成。开发一个活动的效率是提高了,但要开发的活动却是越来越多。因为现在是从原来的一个人一周开发一个活动,变为一个人一周要开发 2~3 个活动。虽然这里提高了开发的开发效率,但是整个活动的开发流程却没有得到根本性的改变,流程还是比较多,参与的人也比较多,周期也相对较长。能否再次缩短时间呢?于是,经过开发和产品一段时期的反复沟通,AMS 二期开始了。

上面我们说的 API 引擎就是图中的业务层,而运营管理系统和活动模板对应图中的运营平台。

一个要支撑住峰值 10 亿 PV 的系统,光有一套代码层是远远不够的,其最重要的是要高可用。那么 AMS 是如何在高并发的情况下保证系统高可用的呢? 这里我分享 3 点 AMS 系统主要运用的设计原则。

1. 过载保护

主要是做了无效请求拦截、限流、限频、session 锁、安全打击等。

2. 柔性可性

AMS 系统的很多 OP 都是调用第三方的接口,执行时间也比较长,直接影响系统的 QPS。因此我们主要对服务进行降级处理,当有大流量推广时,我们把活动的发货方式由同步发货改为异步发货的方式,减少发货的时延,提高系统的 QPS。

3. 大系统小做

拆分大的系统为一个个小系统,减少子系统间的耦合及相互影响。比如我们在 Web 服务层部署时,部署了多个集群。即使某一个集群挂掉了,也不影响整个系统。就像下面的图一样,哪个系统更稳定,大家一目了然。

4. 小结

以上就是我分享的设计之道。最后再做下个总结,这里说的“道”,包含两层意思:

  • 一是设计过程,好的系统不是一开始就是设计得很好,而是经过了不断演化的过程。

  • 二是方法思路,AMS 主要有组件化、配置化、自动化。这里我再抽象一下,变得更通用一些。

    • 组件化:对重复不变的事组件化

    • 配置化:对变化的事配置化

    • 自动化:能让程序做的事尽量让程序自动化处理

另外系统的架构上主要使用了以下 3 种常用的设计思维:

  • 过载保护

  • 柔性可性

  • 大系统小做

QQ 会员运营系统(AMS)结过多年的不断积累及迭代,其实际情况复杂得多,技术细节也非常之多,本文其实做了很多简化。本文重点在于分享这套系统的设计过程和设计思维,希望对你有所帮助!

本文首发于 GitChat,未经授权不得转载,转载需与 GitChat 联系。 

原文链接: https://www.yukx.com/tencenttec/article/details/2329.html 优科学习网亿级 QQ 会员活动运营系统的设计之道

推荐文章
  • 近年来,在数字经济迅速发展的背景下,越来越多的企业开始建立健全业务系统、应用、借助数字化工具提升管理效率,驱动业务发展,促进业绩增长。在这一过程中,和许多新技术一样,低代码(Low-code)开发被推上了“风口”。一、低代码的定义与发展低代码开发平台通过抽象和最小化手工编码的方式,为开发和部署定制化
  • 该框架目前正在京东App后台接受苛刻、高并发、海量用户等复杂场景业务的检验测试,随时会根据实际情况发布更新和bugFix。有对区块链感兴趣的,可以参考项目作者另一个GVP项目,java区块链底层入门。如果只是需要用这个框架,请往下看即可。如果需要深入了解这个框架是如何一步一步实现的,从接到需求,到每
  • 在拥有大量并发用户的系统中,热key一直以来都是一个不可避免的问题。或许是突然某些商品成了爆款,或许是海量用户突然涌入某个店铺,或许是秒杀时瞬间大量开启的爬虫用户,这些突发的无法预先感知的热key都是系统潜在的巨大风险。风险是什么呢?主要是数据层,其次是服务层。热key对数据层的冲击显而易见,譬如数
  • seo优化分为seo站内优化和seo站外优化,本文就seo的站内优化提出一些建议。一般来说站内优化主要的地方有:三个标签(title、keywords、discription),即网站的标题、关键字和描述,要优化的关键词这三个标签中有没有合理的分步是seo站内优化的最重要一点。三个导航(主导航、次导
  • 推荐在闲鱼的应用不同于搜索的确定性,推荐场景面临的问题往往是不确定的。但是正是因为这种不确定,带来了非常大的可能。所以推荐在闲鱼基本上遍地开花的状态尽管如此,推荐在闲鱼仍然面临着非常大的挑战,而这些挑战和闲鱼C2C市场的定位和特性密切相关。总的来说,闲鱼有四个比较明显的C2C特性:浅库存。闲鱼的商品
  • 1.前言随着QQ会员用户的日益增涨,每周都要上线大量各种玩法的H5活动来满足产品和运营的需求。大概在2014年,那时手游非常火爆,我们部门有一个游戏特权小组(大概10多个人),就是专门每天开发这种游戏相关的H5活动的。上线一个活动,从需求评审到设计重构,再到开发,到测试,最后上线。整个流程下来,大概
学习大纲
亿级 QQ 会员活动运营系统的设计之道