中原银行 OLAP 架构实时化演进
- 1. OLAP 实时化建设背景
- 2. OLAP 全链路实时化
- 3. OLAP 实时化探索
- 4. 未来探索方向
中原银行成立于 2014 年,是河南省唯一的省级法人银行,2017 年在香港联交所主板上市,2022 年 5 月经中国银保监会批准正式吸收合并洛阳银行、平顶山银行及焦作中旅银行。合并后总资产突破 1.2 万亿,在国内城市商业银行排名第八位,下辖 18 家分行、700 余家营业网点及 17 家附属机构,先后荣获“年度十佳城市商业银行”、“铁马十佳银行”、“最佳上市公司”等称号。
1. OLAP 实时化建设背景
近几年实时需求涌现,尤其是银行更加重视挖掘实时数据的使用与价值。主要表现在逐年增多的实时报表、实时大屏等面向 BI 的场景。还有实时指标或特征计算等面向 AI 的场景。从技术角度,实时 OLAP 相较于传统 OLAP 发展起步较晚,多种多样的实时数据需求对实时 OLAP 体系也提出了更高的要求。随着近年来技术迭代,如 StarRocks、ClickHouse 等支持实时 OLAP 场景的数据库也是推陈出新,对于解决银行业的实时场景也带来了更多可能。
银行业想要获取实时报表数据,这样基本的 OLAP 场景需要解决哪些困难呢?
首先需要全链路实时化。全链路是指数据实时采集、实时分析、实时写入数据库以及实时提供查询分析。整个链路的实时化相较于传统的 OLAP,各个环节均有一些难点需要克服。比如受到银行记账模型无法变更、数据库管理严格、数据安全要求较高等多方面的限制,当前金融行业数据实时采集也不是一路畅通的。另一方面来说,对于流计算业务,实时计算面临数据源多、整合困难、技术复杂、监控运维成本较高等问题。业务需求也往往涉及多个数据部门配合,多种业务类型交织,一旦流计算任务出现问题,监控分析排查也会比较困难。
其次,从生产实践得知,实时场景仅有实时数据往往是不够的,需要配合离线数据才能计算出所需的业务数据。尤其是在银行体系下,面向规范化、精准化加工的传统离线数仓体系,能够较好的解决财务分析等场景,且在很长时间内仍是主流方案。离线数据加工的复杂度往往也较高,当前阶段尚无法达到全部业务数据的实时化计算。
最后,普遍依赖维度表。众所周知,在 kimball 维度建模中,分为事实表和维度表。在我行,基于事实表的场景基本上已经解决。但银行业的报表大多都基于维度表的统计分析,该场景也是银行业实时报表落地困难的关键因素之一。
为了解决该场景,我行进行了大量的生产实践,但仍未有较好的解决落地方案。希望随着实时技术的发展能够彻底解决该场景。
2. OLAP 全链路实时化
首先介绍一下实时化的演进历程,对整个发展过程和未来的方向有一个概括性的了解。
- 第一阶段:起步。基于 Kafka 的实时 ETL,包括实时采集、实时加工、实时载入、实时OLAP。该架构能够解决的问题大都是基于事实表的统计分析,已经在行内有大量的落地案例,但无法解决银行基于维度表的统计分析。另外,该方案很难形成规模化的数据分层复用,Kafka数据无法查询和长期持久化等问题也比较突出。
- 第二阶段:探索。为了解决银行业大量基于维度表统计分析场景,先载入后分析,也就是 ELT 的方式。过程是先实时采集,然后不进行逻辑加工直接实时载入,最后再实时 OLAP 查询阶段进行逻辑加工。
- 在 ELT 探索初期,我们采用过微批全量的方式,在数据实时写入到数据库后,定时执行全量加工逻辑,类似于离线数仓跑批的概念。只不过是从每天跑批缩短到了小时级别,甚至分钟级别,达到准时加工的效果。显而易见这种方式不可取,存在时效性差、跑批不稳定等问题。
- 随着 MPB 数据库的发展,查询性能也得到了极大的提升。使用 View 视图嵌套加工逻辑的方式也进行了探索,也就是把业务数据以 CDC 的方式载入 MPP 数据库的明细层,分析查询逻辑使用 View 封装,在查询时触发底层计算。这种方式也可以解决维度表的统计分析,但每次查询资源消耗太大,无法大范围推广。这种 ELT 方式虽然能够解决一部分的实时场景,但局限很大。
- 第三阶段:优化。接下来到了优化升级和未来方向选择的节点。为了解决银行业基于维度表的实时 OLAP,必须把部分计算向前移动到 Flink计算。数据湖 Flink Table Store(Apache Paimon)的出现,使基于维度表的全量统计分析成为了可能。也就是前期一部分的加工工作在 Flink 中完成,另一部分聚合等计算工作在 OLAP数据库中完成,两者分摊了计算的时间消耗。
- 第四阶段:未来。在未来还是希望能够把全部加工逻辑在 Flink 端完成,向着存算分离流批一体的流式数仓方向发展。
全链路实时化具体是怎么做的呢?承载哪些业务或者使用了哪些组件呢?上图我们从下往上看。最下面是数据源,分为了四类实时数据,分别是业务的数据库数据、客户的行为埋点数据、网络流量日志类数据、应用消息直接产生的数据。所有数据均打入 Kafka,供后续的实时计算平台使用。
中间是实时计算平台,加工逻辑使用 Flink SQL 和自定义函数处理,Flink 任务运行在 Yarn 或 K8s 上,当前主要推广运行在云环境上。使用 Kafka 和 Flink Table Store(Apache Paimon) 作为数据的传输和存储,维表统一使用 ES 提供。在银行业维表使用比较普遍,同一张维度表可能使用其中的多列进行关联,且维度表往往需要实时的,如在新开户场景。在我们平台上,使用频率较高的维表,引用次数达 60 多次。
再往上来到了数据服务层,提供在线服务的同时需要支持实时数据的写入,常用场景是直接写入业务目标数据库 Oracle 或 MySQL 提供在线服务。大多数场景数据是写入公共的 ES 或者 StarRocks,提供查询或者在线分析服务,后期也会提供直接对 Flink Table Store(Apache Paimon) 的查询。
最上层是各个业务场景的实时数据需求,如实时反欺诈、实时营销、数据安全行为分析、实时报表等场景。
左边的数据源有关系型数据库 Oracle、MySQL,还有在起步阶段的国产 OceanBase。银行当前主要使用的还是 Oracle,我们采用商业的实时数据采集工具 Attunity Replicate,该工具在部署方式、抽取数据的时延和吞吐表现优秀。对少数 MySQL 采用了开源的 Flink CDC 工具,该工具满足各个场景的需求。明年行内将大范围推广国产的 OceanBase 数据库,其自带的 OMS 数据迁移工具是抽取该库的最好选择。
这几种关系数据库均采用 JOSN 格式,全部写入 Kafka 中。对于手机银行、微信银行等用户行为埋点数据,使用的是商业神策平台提供的能力。实时计算平台直接从神策的 Kafka 进行数据消费。交换机的流量镜像等日志经过报文解析后也直接写入 Kafka,这部分的实时流量是最大的。另外还有少量产品是把相关的实时数据直接写入 Kafka。
对于 Kafka 中的 topic,也有多种方式适配不同的数据场景。对于关系型数据库,一张表对应一个 topic。对于用户行为,采用大宽表的形式把所有数据都写入同一个 topic。采用 Kafka 作为统一对接下游流计算平台,达到复用 topic 的目的,如核心的交易流水表复用了三十多次。
通过介绍发现不同场景的实时数据最优的采集工具也不同,通过各种采集工具抽取了各个业务部门的数据,但海纳百川,都需要流入 Kafka 对接后续的实时计算。
最后抛出来一个疑问,对于纷繁复杂的数据源,大家是如何统一管理起来的呢?
2018 年首次引入实时计算业务,主要以代码开发为主。2019 年开始系统的建设实时计算平台,以 Flink SQL 开发实时业务,能够界面配置、启停、监控任务。2020 年支持运行在 K8s 云平台上,能够手机小程序远程监控,承载的任务也达到了 100 多个。2021 年开始支持 CDC 同步场景,探索实时 OLAP,承载的业务也达到了 200 多个。2022 年支持了最新的 Flink Table Store(Apache Paimon) 湖存储,也引入了高性能的 OLAP 引擎 StarRocks,探索实时报表场景,承载的业务也达到了 300 多个。
几年实时任务的运行现状如下:
实时任务个数 380+,以每年 100+的速度稳步增长。支撑了二十多个项目组的业务需求。日均处理数据行数 50 亿+,日均接收数据量 20T+。
这么多的实时任务多种多样,如流量日志计算指标,数据量大但逻辑简单;监控用户账户信息,数据量小但引用维表个数较多;监控用户行为埋点数据,使用了 CEP 进行复杂事件处理。
显然数据加工实时化在链路中处于关键位置,平台化也能够降低使用门槛,加快开发效率。用户能够像使用普通的 SQL 一样,对实时的数据进行处理,不需要关注流计算底层复杂的处理过程,极大地降低了实时数据开发的门槛。
其中主要的功能有数据源管理、实时任务开发、任务运维监控、项目管理、集群管理等功能。在实时任务开发模块中,主要有数据源配置、源表/维表/结果表配置、SQL 开发、自定义函数、SQL 语法检测,包括上线过程中需要的导出和导入功能。
在任务运维中有收发统计、集群资源监控、异常短信告警、远程小程序监控等,同时具备企业级的权限管理、租户管理等功能。该平台涵盖了实时数据开发的全生命周期,平台化可以彻底规避繁重的底层流计算处理逻辑,繁琐的提交过程等。为用户打造一个只需要关注实时计算逻辑的平台,助力企业向实时化、智能化大数据转型。
前面也已经提到了,实时计算的场景往往离不开离线数据,不管是在数据加工阶段,还是在查询分析阶段,实时数据主要是写入 Oracle、MySQL、ES、StarRocks 等。
以 StarRocks 为例,写入的既有离线数据,也有实时数据。既有写入 ODS 层明细层数据,也有计算汇总后的 ADS 层汇总数据。StarRocks 作为一款 MPP 架构的高性能数据库,能够支撑 PB 级的数据量,拥有灵活的建模方式,可以通过向量化引擎、物化视图、位图索引、稀疏索引等手段构建统一的数据存储系统。
我行搭建了一站式商业智能 BI 平台,该平台有客户行为分析系统——知秋、一站式报表平台——鲁班、一站式大屏——鸿图、自助分析平台——云间、一站式活动运营平台——智赢等系统,未来还会加大对 Table Store 的投入,作为实时数据的统一存储。
接下来我们看一下典型 ELT 链路的工作过程。当前银行业的数据库主要还是 Oracle,采用商业的 Attunity Replicate 实时采集数据。该工具提供全量和增量的实时同步,秒级时延,数据以 JOSN 格式统一写入 Kafka,以便复用 topic。也可以按照主键哈希顺序写入 topic,以保证分区有序性。
然后基于 Flink SQL 构建的实时计算平台进行业务逻辑处理,统一使用 ES 作为维表,关联离线和实时的数据。这里没有选择 Hbase 和 Redis 作为维表是因为他们只能主建关联,构建二级索引又比较麻烦。另一方面,维表数据量最大也就是千万级别,使用 ES 能够满足所有场景。
最后数据实时写入 StarRocks 中,StarRocks 支持快速 update,提供高效 OLAP 的能力,能够应对多种查询场景。这个典型的 ETL 链路对于事实表的行为分析有很好的效果,比如用来统计交易笔数、交易金额、业务量等指标,但对于维度表的分析却无能为力,比如计算分支行存款余额场景。
3. OLAP 实时化探索
我们以银行的典型动账场景为例,一次动账操作其实是一个事务,至少要操作两张表。第一张表是交易流水表,记录转账的一次行为,第二张则是用户的属性表,其中有一个字段是用户的余额,需要随着转账同步更新。
上图中的两个表是演示两次转账动作,该场景在 12:00:01 秒张三转入 100 元,客户表张三的余额也从 100 更新为 200。12:00:02 秒,李四转出来 100 元,客户表李四的余额也从 200 元更新为 100 元,在这个转账场景下进行分析。
流水表的特点,主要是 insert 操作,记录行为信息,适合增量计算,如统计开户、取款、贷款、购买理财等行为事件。刚才提到的典型的基于 Kafka 的实时计算能够较好的解决该场景,比如实时营销包括大额动账提醒、工资代发、理财产品购买、申请反欺诈、交易反欺诈等。在贷后管理也有应用,如零贷贷后临期催收、扣款等。
客户属性表的特点,主要是 update 操作,记录属性信息,客户的总资产、贷款、理财、基金、保险等产品的余额是在维度表中,所以常使用维度表全量计算资产信息,如资产余额类的计算等。
应用的场景主要是实时报表和实时大屏,比如对公 CRM、零售 CRM;经营管理;资产负债管理等。
接下来主要探讨的是基于维度表的实时全量计算场景。以在行内落地的对公 CRM 实时存贷款场景为例,来讲解一下涉及哪些方面的工作。对公 CRM 实时存贷款功能面向总分行领导、支行行长、客户经理等,可以随时查看行内分支行及客户的存贷款情况,从而时刻掌握全行的资产最新状况。
从数据的角度来看,分为三个部分,实时数据、离线数据、实时查询分析数据,也就是在查询的时候才开始进行逻辑计算。
先来看一下实时数据,不断变化的有存款余额、贷款余额、应解汇款、实时汇率、新开账户等。刚才提到实时场景往往离不开离线数据一起进行配合计算,离线数据主要包括员工信息、机构层级、归属关系等基本信息,还有离线跑批生成的年末月末余额、绩效关系、管户关系等。
这两部分数据均载入到实时 OLAP 引擎,用户查询的时候在引擎内计算资产负债明细汇总,根据绩效关系对资产负债进行分组聚合。实时的存贷款和日终、月终进行比较,分支行根据存贷款进行排序等。对公 CRM 提供的查询功能有全行汇总、分支行汇总、分支行明细、分支行下转、客户明细、年末月末比较、趋势分析等。
了解了实时存贷款业务功能,下面我们来看一下是如何实现的。上图是该案例的技术架构图,也就是使用了实时的 ELT。
首先,实时数据全部来自于 Oracle 数据库,通过实时采集导入到 Kafka。使用流计算平台,以 CDC 的形式写入到 StarRocks,在其中构建全量和增量的数据。作为 ODS 原始层,离线数据在数仓中跑批生成,使用离线同步工具,百川平台以 T+1 的形式写入 StarRocks,然后在 StarRocks 中使用 view 灵活的对数据进行转换处理。View 视图可以随业务进行调整,上层应用直接查询封装好的视图实现即席查询。当用户进行点击的时候,触发原始的数据进行计算,如查询某分行的存款余额。
该方案可以解决基于维表的实时全量计算场景,无需跑批,现场计算,端到端分钟级甚至秒级完成。尤其是在月末、季末等关键节点,给分支行的领导查询最新资产负债等信息带来了极大的便利。
当然,该方案并不完美,缺点是当 view 的逻辑较为复杂,数据量较多时,查询性能影响较大,因此比较适合数据量不大、对 QPS 要求不高、灵活性要求较高的场景,且需要计算资源比较充足。
该方案的探索也让我们得出了一个宝贵的经验。虽然 OLAP 引擎性能强大,但仍然不能把所有的计算逻辑全部在引擎中执行,必须向前推移。但是 Flink 只有计算没有存储,这个问题该怎么解决呢?具体有哪些方面的困难呢?下面来分析一下。
想要解决基于维度表的实时全量计算,存储需要以下三个能力。
- 第一、存储全量数据,并支持快速更新。维度表有大量的更新操作,比如在结息日源库进行跑批的时候。
- 第二、支持流批写、流批读,尤其是流读。流读是数据驱动计算分析,只有能够流读才能使用数据自动计算分析,而不是使用微批调度或者查询时触发分析计算。
- 第三、支持存储“完整”的 changelog。完整的数据库日志存储是数据驱动计算正确性的重要保证。
4. 未来探索方向
今年发布的 Flink Table Store(Apache Paimon) 能够很好的解决之前遇到的问题。Flink Table Store(Apache Paimon) 是一个统一的存储,用于在 Flink 中构建流式处理和批处理的动态表,支持高速数据摄取和快速查询,是一种湖存储格式,存储和计算分离。导入数据时双写到数据文件和日志系统,并且支持流批写入、流批读取,支持快速 update 操作。还支持丰富的 OLAP 引擎生态,比如 Hive 等。我还了解到 StarRocks 也在支持数据湖查询,相信在不久的将来 StarRocks 也能够支持查询 Flink Table Store(Apache Paimon)。
在加入 Flink Table Store(Apache Paimon) 后,原有的 ELT 架构的基础上进行优化升级,带来了如下变化。
在流计算平台中,把原始数据写入 Flink Table Store(Apache Paimon),实时存储历史全量和实时更新的表数据,然后计算逻辑使用 Flink SQL 实现,最后把初步汇总的数据写入 StarRocks 中,原始明细数据在 Flink 中计算,极大减少了 StarRocks 的计算量。
这种架构我们在生产上已经进行了初步尝试,效果非常显著。但这并不是终点,上图展示的就是未来的蓝图,我们将朝着流式数仓的方向进行演进。流式数仓能够支持存储全量的数据和完整的 changelog,也支持批量导入离线数据。使用廉价的存储和存算分离,能够更加灵活的进行弹性计算。
数仓的分层可以解决实时数据的复用,多指标随着数据的实时流动而实时变化,数据主动的变化驱动分析,从另一个角度说也是在使用空间换取时间。当数据在源头发生变化时就能够即刻捕捉到,让所有数据实时的流动起来,并且对所有流动中的数据都可以进行实时或批量的查询。
离线数据和实时数据共同存储在 Flink Table Store(Apache Paimon) 中,离线分析 SQL 和实时 SQL 完全一样,最终达到流批一体的效果。那么为什么现在不直接采用这种架构进行构建呢?当前阶段这个架构还无法落地,比如其中聚合计算有大量的撤销动作,多个层次间的实时数据流动也需要大量的资源和调试技能,不过我相信流式数仓一定会到来。