作者|网易游戏高级大数据开发工程师 & Doris 内核代码贡献者 胡彪
随着网易游戏品类及产品的快速发展,游戏数据分析场景面临着越来越多的挑战,为了保证系统性能和 SLA,要求引入新的组件来解决特定业务场景问题。为此,网易游戏引入 Apache Doris 构建了全新的湖仓一体架构。经过不断地发展,目前已扩展至十余集群、为内部上百个项目提供了稳定可靠的数据服务、日均查询量数百万次,整体查询性能得到 10-20 倍提升。
网易游戏数据与平台服务部旨在通过数据科技为网易旗下众多游戏提供运营及决策支持,是推动游戏商业成功、品质提升以及渠道优化的重要支撑。近年来,随着网易游戏品类及产品的快速增加,数据规模呈爆炸性增长,每日新增数据达百 TB 级别,不仅需要对玩家基本行为指标(活跃度、付费情况、用户新增等)进行分析,还需深入游戏内部复杂数据,对譬如游戏行为、游戏性能等详细信息进行分析。面对如此大规模的数据增长,如何高效实时的提供数据支持成为必须面对的一大挑战。
为了满足各大业务场景对实时分析时效性的要求,同时保证数据快速写入和极速查询,网易游戏数据与平台服务部亟需一个合适的 OLAP 引擎补充原有的离线数仓架构体系。经过大量的产品调研,Apache Doris 与网易游戏技术中心的整体要求高度契合。因此在 2021 年引入了 Apache Doris,并经过不断地发展,目前已发展至十余集群,为内部上百个项目提供稳定可靠的服务。
本文将分享网易游戏在选型数据仓库架构升级过程中的思考以及基于 Apache Doris 构建湖仓一体全新架构的解决方案,并分享 Apache Doris 在关键业务场景中的落地实践。此外,本文也将分享网易游戏在 Apache Doris 集群运维上的建设及管理经验,以供读者思考或借鉴。
早期架构及挑战早期数据架构如上图所示,数据主要来源于业务数据库、游戏日志及接口数据,通过实时与离线两条链路对数据进行加工。在查询入口层面,我们自研了统一查询引擎 SmartSQL,可基于 RBO、CBO 和 HBO 实现对 Trino、Spark 和 Hive 的智能查询路由。如果用户想要进一步加速查询,数据将通过 ETL 计算成结果数据写入至 HBase 中供点查访问。此外,日志数据还将额外写入一份至 Elasticsearch 中,为日志分析场景提供数据支持。
然而,这一架构在使用过程中也暴露出了许多问题:
运维成本高:涉及组件较多,包括 Hive、Spark、Trino、HBase、Elasticsearch 等,运维复杂度相对较高,需要投入较多的人力。
研发成本高:过多的组件也带来较高的研发成本。面对新增的需求,不仅要开发 Spark、Trino 作业,也要开发 HBase 作业,这要求分析师理解并学习不同组件的使用方法及数据模型,使用成本及难度较高、开发流程长。
数据时效性差:该架构数据处理链路长,需要经过多次流转,时效性和查询效率均无法满足业务需求。
为了应对早期架构的局限性和挑战,我们在选择新的 OLAP 解决方案时,重点考虑了以下几个核心需求:
具备简洁的架构设计,能够满足多种业务场景的同时降低系统组件的复杂度,进而降低运维成本、提高系统的稳定性。
提供统一易用的能力,可由单一组件替代之前架构中的多个组件,降低用户的学习和使用成本,提高研发效率。
具备实时高效的数据处理能力,能够支持实时数据的高并发写入和亚秒级查询响应,满足业务对高时效性的要求。同时希望新引擎符合实时数仓及湖仓一体发展趋势。
基于以上需求,经过深入评估,我们最终选择了 Apache Doris 作为 OLAP 解决方案,以下是具体的选型依据:
基于 Apache Doris 构建全新的湖仓一体架构随着 Apache Doris 湖仓一体的能力日趋成熟,我们基于 Apache Doris 构建了全新的湖仓一体架构,并针对不同应用场景设计了不同的数据解决方案:
数仓分层存储:将数据实时写入 Apache Doris 中,所有热数据的查询均在 Apache Doris 数据仓库中进行,根据 TTL 策略将热数据转冷至数据湖中;
数据湖查询加速:将 ODS 层数据写入数据湖中,DWD、DWS、ADS 层则存储在 Apache Doris 中。上层数据应用在执行查询时,对于高 QPS 和低延迟要求的 SQL 直接走 Doris 内表,明细数据则通过 Apache Doris 提供的 Hive Catalog 以及 Iceberg Catalog 查询湖中数据,同时还可通过外表物化视图将外部数据经过物化视图写入内表。
全新的湖仓一体架构充分结合了仓和湖的能力,实现存储和查询的统一,并基于 Apache Doris 物化视图等能力可以进一步简化数据建模加工、实现数据湖查询加速等能力。
Apache Doris 在网易游戏质量保障中心场景下的应用QData 是网易游戏质量保障中心下属的大数据团队,团队职责是从质量角度出发,针对游戏产品生命周期中的支付、奖励、性能、登录等主题,为游戏提供实时监控、离线分析、报表等服务,以提升游戏性能、优化设备表现。
该业务场景的特点以及对 OLAP 引擎选型时的要求如下:
日实时流数据量近百亿,写入作业并发数超 200,要求 OLAP 引擎能够支持高并发写入;
在某些分析场景下,需要用到 Hive 历史数据,要求支持从 Hive 中快速同步大量历史数据;
需要完整支持行为分析类型的函数,且要求 P95 指标查询不超过 3s;
日常会有变更字段和更新数据的需求,要求引擎支持数据更新且不影响正常写入和查询;
而这些需求与 Doris 功能特性十分契合,因此数据与平台服务部与 QData 配合将 QData 的数仓从其他引擎迁移到了 Doris 中。
全新数仓架构如上图所示,我们将 Doris 数仓分为 ODS、DWD、DWS 层:
对于超大表,ODS 层数据仍然保存在 Hive 中,进一步 ETL 之后再将聚合后的数据导入到 Doris 中实现查询加速。
对于规模适中的表,Kafka 数据直接导入 Doris 中,通过仓内 ETL 和物化视图的方式实现数据聚合、查询加速。
一般来说,游戏产品会在版本发布当天公告更新及优化信息。为精准监控游戏运营的各个环节、为玩家提供良好的游戏体验,数据团队需监控玩家打开游戏时,从 Patch(游戏补丁)更新到最后登录过程中转化情况,量化各环节的转化数据。这就要求对玩家设备 ID 进行精确去重,而去重的数据量高达 10 亿级别。
如果直接使用 COUNT(DISTINCT) 往往会占用大量内存和 IO,并且查询时间 >20s,特别是当表中有大量不同的值时,查询性能受到的影响更大,无法满足性能要求,因此我们提供以下两种方式进行优化:
方式一:首先在 Hive 中构建玩家设备 ID 全局字典表,接着将该表导入到 Doris 表对应的 Bitmap 列;
方式二:针对明细表创建物化视图,通过 bitmap_hash64 函数将字符串转化为 Bitmap 类型。使用 bitmap_hash64 而不使用 bitmap_hash 的原因是 bitmap_hash 在数据量大于 2000 万时碰撞较为严重,导致结果不准确。
针对不同的使用场景,我们可选择不同 Bitmap 优化方案。优化后,在 14 亿数据的场景下,Bitmap 查询峰值所占用的 Doris 内存从 54GB 下降到了 4.2GB,查询时间从 20 秒下降到了 2 秒以内,提升效果颇为显著。
02 物化视图提速查询游戏性能是玩家游戏时最直观的体验,良好的性能可以确保游戏流畅度、响应速度和画面质量。性能问题可能导致卡顿、延迟或崩溃,严重影响玩家满意度和游戏口碑和留存。因此需要对玩家游戏时的性能数据进行进行监控和分析。
衡量游戏性能相关的数据指标有很多,例如:FPS、卡顿次数、内存峰值等 8 种,单一指标相关的维度多达 10 余个。而游戏策划等部门希望在网页端可针对多种指标和多个维度进行自定义聚合查询,查询响应时延需要控制在 2s 内。
对于该需求,我们可以基于常用的数据维度设计物化视图,来满足用户绝大部分自定义聚合查询的需求。Doris 的一大优势在于能够自动识别并匹配最优物化视图进行查询,因此建议可设计 2-3 个物化视图,过多的物化视图可能会对数据导入速度造成影响。相较于之前基于 Presto 进行多维分析时查询耗时长达 20-40 秒的情况,使用 Doris 后的查询时间已经提速至 1-2 秒。这不仅提升了用户体验,也为数据分析工作带来了极大的便利和效率。
03 多种写入方式配置式作业生成在数据写入方面,考虑到不同业务方的写入方式不同,我们在部门层面提供了多样化的写入方式。对于 Kafka 流,提供了一键映射 Doris 表的功能实现快速开发 Flink 作业;对于离线 Hive 数据的同步,提供了 Broker Load、Hive Catalog、Seatunnel 三种方式写入;对于其他数据源数据的同步,基于 Seatunnel 可实现各类型数据源的集成写入。
04 基于自研大模型问答和拖拽式生成查询我们研发了大模型问答系统,提供基于大模型问答的查询模式和拖拽式生成查询。用户可以通过自然问答的方式便捷地生成 Doris SQL 查询语句,也可通过界面化拖拽式操作生成 SQL 查询语句,并迅速获取到 SQL 执行结果以及对应的图表显示。在大模型生成查询方面,成功率高达 92%。同时,为了满足不同用户的需求和习惯,我们仍然支持用户通过 JDBC 接口对接自己的报表系统,旨在为用户提供更灵活、高效的数据查询体验。
05 QData 场景下的问题整理在 QData Doris 集群的使用过程中,我们遇到了一些问题,借此机会将这些问题及其相应的解决方案整理如下,以供大家参考。
Hadoop 上的数据经过一段时间会被 EC 化处理、节约存储成本,但 EC 化后的数据无法通过 Broker Load 导入,因此将 Broker Load 依赖的 Hadoop Client 版本升级至 3.0,解决了部分冲突、实现正常导入。
用户在查询 TB 级大表分区时,在完成分区过滤的情况下,仍会出现 IO 打满情况,这是因为使用 Unique 模型查询的时候,进行了两次聚合操作,第一次是把数据进行 Compaction,第二次才实际用到过滤条件。临时的解决办法是跟用户沟通是否可以修改模型,根本的解决方法是升级集群版本,借助 1.2 版本的 Merge On Write 特性,使得查询能够应用索引。
在 1.2.4 版本中, 用户把 Java UDF Hive UDF 迁移到 Doris 中后发现 Doris 不支持 Hive UDF 的重载,所以我们把源码做了改造,使其能够支持 Hive UDF 的重载。
自网易互娱内部引入 Apache Doris 后,经过两年多的发展,集群已形成了非常可观的规模:
总集群十余个,国内 / 海外均有布局,总节点数达上百个;
内部项目对接数达上百个,日均查询量超过 500 万;
最大单集群存储数据总量达到 PB 级,日均通过实时作业以及离线导入的数据量达到数十 TB。
面对如此庞大的集群规模,如何高效管理成为重点关注的问题。以下是我们对于 Apache Doris 集群管理运维的思考:
基础建设:在确定 Apache Doris 选型后,首先需要制定部署规范、运维规范;其次需做好业务接入规范,提前与业务沟通、明确不同业务场景下适用的机型规格;同时需完善各类基准测试,建设完备的元数据元信息,以确保提供标准统一、性能可靠的数据服务。
监控报警:首先需梳理集群监控的分级指标,将 Doris 报警级别分为 P0、P1、P2 三个等级,并根据不同的等级设定报警规则和升级机制,部分指标提供用户侧的报警功能。然后统一监控入口,设定好监控大屏,能够通过大屏快速获取到所有集群节点的状态信息(可基于官方提供的 Prometheus 模板迭代建设)。
安全性的保障:制定备份规范、及时进行数据备份,进行周期性故障演练,确保出现故障时能够稳定快速的恢复。不仅如此,还需要配置集群巡检规则、巡检机器环境,如 Doris BE 部署时要求设置文件句柄数、关闭 Swap 等,确保机器环境处于健康状态。
平台化及可视化:将上述规范平台化、可视化,通过自动化工具和脚本进行集群运维管理,避免人工操作失误带来的风险。同时平台还可为业务方提供数据报表、分析和审计等功能,帮助业务方了解集群状况及发展趋势。
基于上述集群运维目标及方向思考,我们内部自研了一套 Doris Manager 系统,实现对 Doris 集群的可视化管理,架构图如下:
基础服务层的 Galaxy 和 Aladdin 都是网易游戏内部的系统, Galaxy 是内部配置管理中心,Aladdin 是流程管理平台,这两个平台结合可以实现集群运维部署的标准化。以 Doris 集群服务注册启动的流程为例,第一步启动 FE Master,第二步注册 FE FOLLOWER,第三步启动 FE FOLLOWER,第四步注册 BE,第五步启动 BE,这些固定的步骤可以在 Aladdin 平台创建为流程。当 Aladdin 将上述流程定义好之后,通过接口形式提供给 Doris Manager 调用,进而实现集群一键部署和扩缩容等运维操作。
在平台安全方面:在认证上,使用了内部的 OPENID 打通内部权限,基于 RBAC 的权限模型能够较好的划分权限层级,区分不同角色的平台视角。在审计追踪上,记录管理平台上发生的任何行为,便于追踪操作历史;
在集群服务功能方面:针对用户最关心的内容设计了集群状态、综合功能、查询导入这几个模块,帮助用户监控集群状态、分析各类资源的使用情况;
在集群运维方面:设计了集群部署及托管、进程守护、数据备份、服务扩缩容等功能,以确保集群的稳定运行及高效管理;
在用户接入方面:通过 Gateway 网关实现白名单管控,通过负载均衡实现服务的高可用。
Doris Manager 平台的各类分析模块主要有以下 5 个数据来源:
Doris 审计日志:虽然官方提供的 Audio Log 插件,可以将审计日志写回到相应的 Doris 集群,但这种方式不便管理多集群场景。因此,我们将所有集群的审计日志统一采集到 Kafka 中(考虑到不同版本 Doris 的审计日志格式存在差异,因此进入 Kafka 流后,将对审计日志标准化处理,确保从多个 Doris 版本采集到的审计日志指标统一),然后对清洗后的审计日志进行双写,其一接入 Hadoop 集群,满足内部对审计日志永久保存的需求,其二接入独立的 Doris 集群,该集群将保留近 3 个月审计日志,以供 Doris Manager 进行用量分析、成本计算,并满足用户查看历史 Query 的需求;
FE/BE 日志:日志是观测性的重要指标之一,由于早期的 Doris 版本没有倒排索引功能,因此我们将 FE/BE 日志采集到 Elasticsearch 中,通过在 Doris Manager 平台调用 Elasticsearch 提供的接口,实现问题日志的快速检索。同时借助 Elasticsearch 配置集群日志级别的报警,比如 WARN 日志阈值报警、 Error 日志报警、关键字报警等;
Cluster API 数据:Doris 提供了丰富的 API,Doris Manager 可通过调用集群 API 获取到各种类型的信息,并将所需信息参与到模块计算中。需要注意的是,某些 API 会随着 Doris 的迭代发生变化,因此多个 Doris 版本间的接口兼容也是引入新版本时要着重测试的地方;
Fe Meta:在 information_schema 库下存放了大量的元数据信息,可以直接获取库、表、分区等各类信息;
集群 Metrics:Metrics 最直接体现集群运行的健康度等信息、FE/BE Metrics 是分析集群状态最佳的数据来源。
将这些数据采集到 Doris Manager 之后,我们通过内部规则、行业规范、配置约束和集群现状等现状设计了一系列分析模块,获取到分析结论可供管理员和用户进行查询分析、存储分析以及成本计算等行为。
集群服务状态管理的设计实现为帮助用户侧掌控集群各类运行状态,减少管理侧的运维人力成本,我们主要聚焦存储、导入和查询这三方面进行模块设计,设计目标如下:
查询:帮助用户全方位了解集群查询情况,提速查询。
导入:帮助用户掌控实时和离线导入的数据增量情况,导入问题报错辅助排查,减少人力运维。
存储:帮助用户减少冗余存储,节约存储成本,减轻元数据管理压力。
集群查询消耗的总资源和各用户消耗的资源都需要量化,以便开展用量预警、性能分析等工作。因此我们设计了“查询概览”模块,该模块主要有以下几个功能,帮助用户从全局概览上了解集群的查询性能变化情况。
支持查看集群近 3 个月各指标的走势,包括数量、Cputime、Memory、P 系列指标;
统计集群内各用户消耗查询资源占比;
以表格的形式精确展示指标详情,所有统计指标支持导出下载。
Doris 对于 Running Query 的可观测支持度还在逐步完善中,而在某些场景下用户需要了解实时 Running Query 的情况,便于 Kill 误提交或者不合理的大查询。因此 Doris Manager 设计了“当前查询”的模块,可自动刷新并获取当前运行的查询数量,帮助用户查看正在运行的 SQL。
慢查询治理对集群安全运行至关重要,不仅能及时释放数据库资源、降低安全风险,还能提高 SQL 质量和可维护性、提升用户的使用体验。为了帮助用户感知集群的慢查询,Doris Manager 设计了“查询分析”模块,支持按库 / 按时间查看慢查询汇总分布、查看慢查询在时间轴上的分布,同时支持按照查询时间、查询语句、查询用户、Catalog 和阈值等维度来查看并导出慢查询信息,以便更好的管理和优化数据库性能。
在执行计划上,Doris Manager 提供了两种展示形式,一种是图形化的、比较直观,另一种是文字类型的,帮助用户初步快速地定位慢查询问题。每条慢查询记录后均设有便捷的操作按钮,用户只需点击即可直接查看查询计划,从而对查询速度慢的原因进行初步分析,无需再繁琐地切换终端去执行 EXPLAIN 等语句。
对于一些无法通过执行计划来定位的慢 SQL,官方提供了 Profile 功能,因此 Doris Manager 对其功能进行了集成——“Profile 管理”模块。假设发现 Scan Node 耗时过长,很可能是 Bucket 参数设置不当所致,基于这些 Profile 信息,平台侧将提供针对性的诊断与优化建议,方便用户调整并优化查询性能。
在日常稳定使用集群服务时,用户可能不会频繁登录平台关注查询情况,这可能会使用户忽视掉某些查询 SQL 速度的下降。因此 Doris Manager 开发了“查询报表”模块,可在每日上班前推送查询报表,该报表包含前一日的慢查询分布、明细数据以及各项查询指标值,通过该方式及时让业务洞察上一日的查询情况、做出相应的优化调整。
02 导入分析模块在导入方面,Doris Manager 同样也设计了“导入概览”模块,并将实时和离线的导入数据分开统计,让管理员和用户更清晰了解各类型导入指标的走势,辅助用户评估导入规模的变化。而对于导入具体的指标,则可以进入到“集群监控”页面查看指标分钟级别的走势。
在导入报错指南上,Doris Manager 设计了“报错分析”模块用于分析报错返回的 URL, 这是因为如 Flink Doris Connector、Seatunnel、Spark Load 等写入方式底层都是通过 Stream Load 写入数据。当发生错误时,Doris 将返回一个报错 URL,但由于公司内部网络隔离,相关端口并未对用户开启,因此用户无法访问报错链接,而且某些报错内容对于刚接触 Doris 的用户理解起来较困难,因此我们基于 Stream Load 源码梳理了日常常见的报错信息,并整理到 Doris Manager 中形成知识库,作为智能诊断的支撑。
03 存储分析模块当用户的集群投入运行一段时间后,表数量和数据量通常会持续增长,直到迫切需要治理,而用户往往难以准确判断哪些数据表仍具有使用价值。因此 Doris Manager 通过解析用户的查询语句,设计了“热度分析”模块。在页面左上角通过计算汇总的每个库、每张表的热度信息来给集群打分,帮助用户直观地了解集群数据使用率。右上角则按照库维度按照利用率评分升序展示信息,帮助用户确认存储治理的优先级。
页面的下方则可以按照库、表、分区粒度展示和导出对应粒度下资源的创建、时间、更新时间、表数据量、表行数、Tablet 数、最近 7 天 /15 天 /30 天的读热度、以及最后的查询时间信息。该模块帮助所有集群平均下降约 20% 的数据存储量。
Tablet 是 Doris 中的重要概念,是数据移动、复制等操作的最小物理存储单元。因此 Tablet 治理一直是 Doris 运维人员需要重点关注的内容。如果不规范设置 Bucket 数会带来较严重的负面问题,影响集群的整体性能和稳定性。具体来说不规范分为两种情况,一种是 Tablet 设置得过多,一种是 Tablet 设置得过少。
当 Tablet 数量过多时,主要分为三种情况:
可删除表:通过向用户提供表热度信息,帮助用户判断可删除的表;
非分区表:采用重删重插的方式,通过优化表的存储结构,进而减少 Bucket 的数量;
分区表:
动态分区:当 Bucket 出现异常时,借鉴 Doris Auto Bucket 思维,结合历史数据进行分析和拟合,计算出最理想的 Bucket 数量,基于此来修改动态分区值。如果空分区过多时,可以提醒用户调整参数,减少预创建分区数;
静态分区:只能根据每个分区的推荐值来重建分区。
当 Tablet 数量过少时,与过多时的治理方式一致,区别仅为增大 Bucket 值。
虽然我们在业务接入阶段会给用户同步建表规范,但是仍然无法杜绝不遵守规范的行为,而用户也无法感知当前集群 Tablet 的分布是否合理,管理员给集群业务方提出修改要求后,业务方也不知道用哪种方式去处理。因此 Doris Manager 结合上述治理思路开发了“Tablet 分析”模块,该模块会按库、按表、按分区展示 Tablet 实际值和预期值,对于存在差异的行,提供了“点击进入优化”的按钮,按钮背后的逻辑则是治理规则的应用。首先给用户展示基础信息,并评估等级,等级取决于预期值和实际值的差异,分为紧急、严重、提醒、健康四类,然后提供表热度走势图,辅助用户判断这张表是否还在被使用中,最后是将优化方案及所需详细的操作步骤和相关 SQL 展示给用户,帮助用户快速完成 Tablet 的治理。
结束语自网易游戏内部最初引入 Apache Doris 至今, 已建成十余个集群、为内部上百个项目提供稳定可靠的服务、日均查询量数百万次,Apache Doris 已成为网易游戏内部数据服务体系中不可或缺的一部分。
后续我们也将继续跟随社区版本迭代节奏,截至发文前,Apache Doris 2.1 系列版本已经逐步稳定,该版本推出许多重磅功能是我们非常关注的,后续我们也会将工作重点聚焦于以下几方面:
存算分离:期望引入更廉价的存储介质,同时希望在数据湖场景下更灵活的进行弹性部署。
倒排索引:鉴于内部使用 Elasticsearch 的用户对倒排索引比较感兴趣,且 Apache Doris 倒排索引的能力已趋于成熟,后续将尽快测试并应用。
资源隔离:新版本的内置调度功能和 Workload Group 能更好地简化架构和隔离资源,我们希望在业务场景上使用进而完善湖仓融合方案。
完善 Doris Manager:我们希望 Doris manager 能够提供 On K8S 小实例部署模式,降低用户在专属集群需求上的接入门槛。另外计划建设 Doris manager 对新版本特性的管理支持,比如推出跨集群数据同步等功能。
剥离几百万行代码,复制核心算法去美国?TikTok 最新回应来了
软件工程的兴衰轮回:2 年巨变,裁员风暴下小团队逆袭,老技术反迎第二春?