摘要:本文由腾讯游戏增值服务部数据中心许振文分享,主要介绍腾讯游戏实时计算应用平台的建设实践。内容包括:
建设背景
统一实时大数据开发 OneData
统一大数据接口服务 OneFun
数据服务微服务化 & ServiceMesh 管理
Tips:点击文末「阅读原文」即可回顾作者原版分享视频,PPT下载:
https://flink-learning.org.cn/developers/flink-forward-asia-2020/
一、建设背景
首先介绍一下相关背景,很早之前我们就开始做游戏开发游戏运营,尤其是在五六年前开发过程还是比较痛苦的。很多玩家希望玩了游戏之后立马能得到奖励,这其实是实时数据营销应用和离线数据营销应用的区别之一。
游戏是一个即时刺激反馈的项目,离线数据运营的痛点包括:延迟大,体验差,反馈慢。而通过实时数据运营,可以提高用户体验,增加游戏收入,解决离线指标运营痛点,运营干预越及时,效果越好。
下图是基于我们数据应用平台衍生出来的一个数据服务任务系统。很多时候有一个比较好的任务引擎去驱动一件事情,事情的结果会向一个比较好的方向去发展。比如游戏内的任务系统,玩家有任务可以领取,有奖励和反馈,这是游戏中很熟悉的场景。
另外一个是排行榜,也是一种刺激性的措施,是对大家努力、潜力或者是能力的一种认可。这种场景非常常见,在游戏里面我们用的也非常多。这是一个典型的游戏的运营场景,当然这个背后缺离不了数据,尤其缺离不了实时数据。
以下是我们数据平台演化的过程。
最开始是手工作坊式开发,我们在接到游戏的数据营销活动开发时,去分析需求、数据接入、逻辑编码开发、资源申请、发布验证交付,接口开发测试,线上监控,资源回收。这种开发过程门槛高,成本高,效率低,而且数据复用性差,易出错,不易沉淀系统。所以一定要往平台方向去走。
但同时也需要具备一定的前提,首先是数据的标准化和数据字典统一。我们在 10 年到 15 年基本上完成了游戏数据标准化的过程,包括标准化的接入和标准化的字段映射。在此之上,我们有统一的游戏数据服务,包括数据计算和接口服务。我今天讲的主要就是这一部分,然后在上面能够去支撑各种各样的业务。所以我们的最终目标也是能够建立一个一站式的开发环境,开发者只关注如何实现逻辑即可,其余联调、运维发布、线上运营保障都由平台提供配置化解决方案。
我们的开发思路主要有三点。
第一点是规范化。流程规范,数据开发规范和开发框架。
第二点是自动化,包括资源分配,发布上线,监控部署。
第三点是一体化。从数据开发到数据接口开发,到测试发布和运维监控,要一站式完成。
所以我们抽象出来两个核心的服务,一个是数据服务,一个是统一的接口服务开发。因为在我的思考当中,大家做数据给谁去用,用什么样的方式提供数据给大家用,我认为最好的方式是 API 的方式,所有的实时数据能够以 API 的方式提供出去,在数据应用的主动、被动场景之下都可以覆盖到。另外,在这两种场景下必须有一个流程系统来协调它。
以上是主要的思路,为各种数据应用场景提供一站式的数据开发和应用解决服务,统一活动管理、数据指标计算开发管理和各种数据应用接口自动化生产管理的一站式服务。
二、统一实时大数据开发 OneData
首先来看一下游戏数据的链路。数据产生之后,我们会有一个 data server,然后会把数据传输到消息队列,消息队列现在主要是 Kafka,Pulsar 也在逐步跟上。再到计算层,然后在储存部分去做一个隔离。再到数据 API 这一层,计算的数据能够直接对外产生场景化的应用。这应该也是大家很多场景当中会想到的一种思路。但是我们把整个过程都能串起来,在一个站点里面就能完成完成,不需要在多个站点里面跳来跳去,会大大降低技术栈的门槛。
首先是大数据这一块。原来用 C++, Java 去消费 Kafka 消息队列,但是现在比较少了。我们现在从编译测试到提交发布的过程要做到三点,
第一个是指标配置 SQL 化。因为 SQL 化对很多产品人员来说门槛是比较低的,但是我们比 SQL 化还要更低,即图形化的 SQL。大家只要选哪张表,哪些字段,计算条件,聚合维度是什么就可以了。明确告诉你要填的就是这些字段,从这张表里面选出来就可以。这张表其实就是我们刚才说的接进来的 Kafka 表,所以我们这块就做了两个方面,一方面是支持基本的 SQL,另一方面大家都不需要懂 SQL,你只需要懂这张表,怎么去设计算法就可以了。
第二个是在线 WebIDE。udf 这一块其实是很麻烦的,完全开放是不受控的。我们到目前为止积累的 udf 函数不到 100个。如果这 100 个函数官方提供,就不需要去做了。所以我们提供在线 WebIDE 的方式。
第三个就是数据场景化配置,后面详细介绍。
刚才说了两个 SQL,一个是 Flink SQL,我们要原生支持。另外一种就是自研 SQL,它可以图形化的配置,拖拉拽就可以配置出来,填表单就可以配置出来。除此之外,我们还提供在线函数的 Jar 包的方式,在这里面我们要做 SQL 的解析和代码的生成,另外还要做到 JIT 和隔离性,还有日志的统一上报告警。
我们的一个思路是数据计算必须要服务于场景,必须要能够在某些地方输出。所以我们在有了核心引擎层之后,上面是产品化服务层。比如说实时统计分析服务,用户选择这几张表和字段,平台给出统计结果。另外一个就是实时指标计算服务,就是很多特征值的计算。还有通用规则触发服务,比如说用户一登录,我们立马就要判断弹窗内容是什么,给他送礼包、还是给他推荐一个活动或者任务。再往上是应用系统层,包括任务系统,用户实时干预系统,等等。
以对下游的 qps 的控制为例,比如下游只能承受 500qps,但是当活动时用户量达到 1000 人,是否仍能按照 500qps 的调用速度,剩下的慢慢调,但保证服务正常运行等,这种场景也需要有一些通用的干预的用户关怀类的服务。
下面介绍一下我们自研的 SQL。我们当前用 SQL 解析的方式去做代码的生成,最终生成一串代码,而不是执行一个语法树,因为执行语法树的成本太高。所以我们通过 SQL 解析进行这样的一些判断。如下图所示,最下面就是判断结果。最终生成了如下一串代码。
这是一个执行过程,自研 SQL 和 Flink SQL 之间的一个对比。
FlinkSql 适合的场景:状态值不能太大,最好不要超过 1G。ETL、数据转发等非常适合。
自研 Sql 适合的场景:状态值非常大,超过 10G,甚至 100G,借用三方存储进行状态存储。
举个例子,某个用户最近几天的行为表现,如累计杀人数、对局数等,用户数量上亿。我们的游戏业务场景需要支持大维度和长累加计算,无论多大的数据量,只要存储介质能够承受得住,采用自研 SQL 都没问题。
这里提到一个问题,包括两点:
配置的同表 SQL 重复消费数据。
相同纬度的数据指标每个保存一份浪费存储。我们整个平台有 13,000 多个指标,如果每个指标都要起任务的话,13,000 多个任务的消耗是非常巨大的。很多任务计算的是同表同维度的,比如说两个 SQL 语句都是查询的同一张表,而且聚合的维度也相同。这种情况下其实可以把它们合成一个 SQL 去算,如下图所示。
但是这里面坑也很多,因为一个 SQL 出问题,就全挂了。我们要做到一个 SQL 出问题,也不要影响其他 SQL。虽然我们把性能和效率提升上去,资源也节省了,但是带来的程序管理上的成本也是非常高的。目前我们的总指标 13000+,纬度 3200+,实际节省计算和存储约 60% 以上。
这个是我们在线的 WebIDE 的做法,无需搭建本地开发环境,在线开发测试,严格的输入输出管理,标准化输入和输出,一站式开发测试发布监控。有两种方式,第一种,我们有一个 Java 文件暴露出来,这个文件可以修改,但修改的幅度有限,提前用到的库已经固定了,不能随便乱加。我们在系统上做了一些控制,常用的一些 udf 或者是用户要去做的一些个性化的开发都可以满足。另外一种就是直接提交 Jar 包了,但需要做一些审核。
下面是一个非常典型的场景,我们做游戏运营的时候,通过这种渠道去通知用户,比如说今天有活动你来参与。他登录之后有日志,我们立马能够感知到。通过 Flink 去做计算,我们可以定规则,用户是今天第几次登录,或本月累计登录多少次,或者是其他的一些离线的指标、实时的指标。算完之后就可以给用户去做任务系统推荐之类的事情,这是一个基本的游戏运营的过程。
下面是 Flink 特性的应用。
首先是时间特性:基于事件时间水印的监控,减少计算量,提高准确性。
另外一个是异步化 IO:提高吞吐量,确保顺序性和一致性。
下图是我们的一些案例介绍。
三、统一大数据接口服务 OneFun
第三部分是游戏数据接口服务。有了前面的铺垫之后,大数据开发的门槛很低了。但是开发数据服务接口的门槛仍然很高。有没有一种服务让我能够把数据以 API 的方式提供出去,让别人继续来操作。在经过探索之后,我们有这样一种思路,就是函数化的服务。函数化服务是一种构建和部署服务端软件的新方式,是面向部署单个的函数的一种方式。
所以我们开发了这样一个服务,在这块也是一个类似的核心层,底层是 K8s。执行引擎主要是两种,一种是快速的规则表达式的判断,还有一些比较复杂的困难表达式的判断。另外还有一个就是 JavaScript、Golang 的这种函数支持。然后在上面能够形成产品化服务,包括规则接口服务,函数接口服务,函数推荐服务,实时排行服务。
下面是函数引擎的一个执行,目前我们支持了这 4 种,分别是 Privileged V8,V8,Go VM,Lua VM。然后有统一的接入层,所有的函数片段能够动态加载进来,然后在这里面去执行。
执行的时候我们通过 Common Library 的一个公共库在这块去做。比如说,数据 redis,http, SQL 等,在公共库我只要实现一遍,其它地方做一个应用就可以直接过来。通过这样的一个执行引擎,我们的数据指标能够以 API 的方式规范化的提供给用户。
这是函数开发的一个接口。通过函数接口开发,降低启动成本,更快的部署流水线,更快的开发速度,系统安全性更高,适应微服务架构,自动扩展能力。这块做了之后,我们把数据到应用层,到用户层的通路打通了。原来我们的数据都是在后台计算完了之后放到数据库里面,等着别人来写接口。现在一个人通过图形化的页面去配指标,再通过这种页面方式去配接口,或者写少量的代码,完成一个数据接口服务的开发,就可以上线了。
这是一个 Flink 实时计算和函数服务结合的例子。比如,等级达到 15级,且一个月之内活跃天数少于 5 天的用户,赠送皮肤。玩家的登录日志过来之后,Flink 计算的时候要判断等级,再判断登录天数。登录天数是用自研的 SQL 算出来的结果值。满足条件的话进行一个 RPC call,调用的结果需要依靠函数服务。
下图为游戏内基于实时数据的社交关系推荐。比如说,活跃期的在线好友推荐,成熟期的在线站队推荐,流失衰退期的好友召回,都会通过离线和实时的方式,以及 API 接口去完成。
以下是我们整体的一个架构图。底层灰色的部分不是这个平台的一部分。只有上面这一部分是整个平台的内容,包括服务场景,配置管理系统,服务调度系统。这个平台不关注底层的 Flink 在哪,K8s 在哪,只要有人能提供类似的计算资源即可,但前提是稳定。整体架构就不详细介绍了。
四、数据服务微服务化&
ServiceMesh 管理
目前线上总上线活动 8.5K+,平均每周新上线 100+。如何保障应用服务支撑公司数百款业务的数据应用,如何快速复用,灵活开发同时还要稳定服务。
我们的业务开发场景面临的困难包括:
功能模块快速组合。
功能模块各自独立开发迭代。
不同功能根据实际情况独立部署运营。
所以我们引入了微服务,微服务化带来的便利包括:
开发更加灵活高效。
去中心化效率更高。
能力得到沉淀和复用。
下图为我们针对线上流量的一个管理平台。我们参考业界比较著名的 ServiceMesh 框架,做东西南北流量的管控。在整个体系当中,如果数据 API 开发门槛过低,大量的 API 会很容易生成。但是 API 的使用是否规范、API 安全等是我们关注的问题。
所以我们花了很多功夫,希望把这些安全问题、管理问题解决好。我们在内部做了这个东西南北流量的管控,构建了这样一个平台专门去做流量的一个管控。
如下所示,东西流量的管控依靠我们的流量治理系统,一个平台能够支持多个集群。我们在去年花了差不多半年时间把多集群的问题解决掉,能够严格控制 data API 的接口允许哪些人访问,以及允许哪些服务访问。数据很多时候是高敏感性的,包括一些用户的画像数据,不能存在安全问题。所以我们基于 istiod 和 K8s 的一些功能,去做东西流量的治理。东西流量主要是集群类的流量。
对于南北向的流量管理,主要是出口流量。比如说,出去的流量一般都需要加密和鉴权,至少要启用简单的 acl 鉴权。所以做了这样一个管控的方式,把各种信息能够更快的下发到数据面,能够在数据面这块去做一些鉴权,还有一些告警日志追踪。
另外,在线服务很容易出现一些问题,在我们预知的流量波动或者未知的流量波动的情况之下,如何知道下游的服务应该做多大量的扩容。在我们上线的时候经常会出现这样的问题,上线了突然来一波流量,需要扩容但结果我们只扩了一个服务,其他服务没扩,或者是漏掉了一些服务。这种情况下漏掉的服务肯定会成为整个服务的一个瓶颈点。
所以我们用 ServiceMesh 的技术来做全链路流量的分析。全链路前端通过上报数据,自动生成 DAG 图形展示,经过压测后,将链路数据生成快照, 通过时间点对比,可以快速的分析出各个模块的流量放大与瓶颈点。如此,我们就知道了入口如果要扩容一倍,或者增加一台机器的时候,相应的服务是否需要扩容,以及需要增加多少。在测试了这个功能,包括可观察性、安全性以后,我们认为这块还是非常有必要去做的。
以下是内部的一些案例介绍。整个游戏板块都是基于我们的实时加离线的数据,包括现在所有的 170 多款游戏,比较活跃的游戏里面中还会涉及营销活动,缺了数据玩不转,缺了我们的平台,缺了我们的实验数据也玩不转。