导读:本文根据张旭老师在〖2023 中国数据智能管理峰会-上海站〗现场演讲内容整理而成。分享概要如下:
一、准实时数据平台
二、架构演进实践
- 实时数据湖架构
- 数据服务总线实践
三、总结&未来规划
一、准实时数据平台
光大银行数据资产部以提升服务和经营效率为核心目标,负责光大银行的数据管理和数字化转型工作,提供关键性的底层技术支撑。在整个数字化转型和业务升级过程中,数据资产部支撑业务关键资源、保障关键基础设施运行,在我行扮演着重要角色。
准实时数据平台则是光大银行数据资产部-大数据平台团队下的重要项目。
准实时数据平台始于2016年研发,至今已有6-7年的演进,上图是平台的整体架构图,数据流向从左到右。
初期平台的定位是准实时数据采集与流式计算,向外提供准实时技术支持和按需开发的流式数据加工等服务。基于此,平台分为三个模块:数据采集、数据标准化和数据发布。
简单来说,我们的数据采集接近于数据贴源层的逻辑,整个流程更像一个实时的数据仓库。数据源通过两种方式被传送到我们的Kafka贴源层:
- 第一种是传统关系型数据库的CDC数据,这些数据会通过我们的OGG工具进行同步并存储于贴源层,另外,业务系统中的有异步导出需求且对延时敏感的数据通过Kafka API直接写入到贴源层。这些数据大多不可被直接使用于下游业务应用。因此在标准化模块进行公共逻辑处理,数据会被传递到SparkStreaming或Flink实时流式任务,随后被存储于Kafka标准层。在标准层进行的处理后,其中的一部分数据可以被直接用于下游应用的消费。
- 另一种数据则通过各种相对复杂的计算逻辑(flink/spark)或批处理技术写入到我们最终的发布层。与前两层处理不同,第三层着重处理业务逻辑并将最终的数据提供给下游系统进行实时订阅。
整个架构经过多年演进,展现出如下三个特点:
- 具有清晰的分层逻辑,并且基于实时数仓的设计逻辑;
- 该架构涵盖广泛的组件,包括明显的业务逻辑处理,初衷是提供流式数据加工架构相关的服务;
- 兼具准时数据的存储平台和计算资源服务提供平台。
随着大数据领域多年的发展,组件分工也更加细化。组件细分为大数据架构提供更高的可维护性、可扩展性、安全性、稳定性、性能、效率和易用性,使得整个架构更加灵活和强大,能够更好地满足不断增长的数据处理需求。
然而,反观我们的系统,存在两个问题:
- 首先,我们必须维护大量业务处理逻辑,随着时间推移,这对我们平台的资源分配和能力优化带来了巨大压力;
- 其次,我们维护了大量组件,从导入层到存储层、计算层、上层调度层,使得该平台的定位相对较模糊,需要更加明确和细化。
因此,我们需要加强对架构的管理,以缩小各个组件之间的差异,同时优化架构的组织和协调,使之更加适应未来的需求。
二、架构演进实践
针对上述问题,我们结合整个准实时数据平台的组件架构特点,将平台拆分成了两个子平台:
- 实时数据湖平台
- 数据服务总线平台
整个准实时数据平台维护的相关组件从左到右,包括数据接入和导出层、消息中间件层、数据计算层以及数据存储层。最上层是调度层,分为资源调度和任务调度,资源调度也由我们完成。
这样的拆分更好地解决平台定位不清晰的问题,同时也提高了平台组件之间的协作效率。
数据服务总线平台拆分后以Kafka为中心的部分,该部分包括前端封装的SDK和OGG,以及随后引入的Schema Registry组件,致力于提供更完备的流式数据供给能力。
同时,我们引入了Apache Hudi,并结合原有的流式计算组件生态,构建出实时数据湖平台,旨在实现实时数据的高效处理和存储。该平台致力于实时贴源数据存储,在数据的管理、查询和可视化分析等方面提供优化的解决方案。1、实时数据湖
下图是实时数据湖的数据处理链路,中间是绿色的部分是数据湖的存储层,由Hudi和HDFS实现。
左边是数据导入层,分为两部分:
- 一是我们存量的贴源数据,基于Spark的批量任务从数据湖导入;
- 二是实时贴源数据,基于Flink实时流任务,从数据服务总线贴源层导入。
这两部分共同汇总在实时数据湖,实现了一个完整的实时贴源数据存储,对外提供分钟级的一个贴源的数据的可见性。
右边是数据导出层,分三种场景:
- 一是基于 Spark/Hive的这种批处理的导出的能力,给下游的数仓和其他业务系统提供更稳定、低时延的数据可用性;
- 二是基于Flink去提供秒级的实时数据的消费的能力;
- 三是基于内部的多源分析查询平台(Presto),提供实时数据的OLAP查询能力。
实时数据湖提供的是分钟级贴源数据存储,填补了数据湖天级延迟场景和数据服务总线秒级延迟场景之间的空白。实时数据湖不仅是一种存储方式,更提供了快速响应业务需求能力,实现了现代化的数据处理,推动了企业数字化转型进程。
此外,对于光大内部许多业务而言,对数据的实时性并不需要完全做到秒级,分钟级的延迟就已能够满足当前六成的业务需求。
下图是我们内部一个核心的业务运营系统的数据处理链路,在引入实时数据湖之前和之后的演进路线:
未使用实时数据湖之前,数据来源于Kafka的ods层,通过Spark Streaming的流处理写入Hbase,然后经过Hive的Tez批处理,最终通过基于Hive on Hbase表提供给业务查询。整条数据链路的延迟时间非常长,达到了小时级别,这种延时对运营系统的性能影响非常大,明显减缓了业务触达的时效性。
演进后是基于Hudi的改进的数据处理链路,可以达到分钟级的一个延迟。数据来源还是Kafka贴源层,会基于Flink的流处理,再去实时导入到Hudi,最终通过 Presto提供给业务实时贴源数据的交互查询的能力。
整条链路经过改造后,数据可见性延迟从小时级别下降到了分钟级别,处理环节相对简化,同时Hudi提供了更稳定的数据来源。2、数据服务总线
数据服务总线方面的实践,主要涉及三个方面:
- 基于Confluent开源的Schema Registry实现了schema解耦;
- 对Kafka的原生API进行了封装,以便更好地对外提供服务;
- 提升了服务的可观测性和可视化水平。
1)Schema的解耦
下图是优化前的数据流转图。
黑色实线表示数据流转的方向,黑色虚线表示元数据流转的方向。数据来源于Oracle数据库,通过OGG进行导入,以Avro的格式,通过Kafka做数据层的解耦,由下游基于Schema去做解析,下游解析数据的Schema来源于上游OGG接收到数据变更自动生成(即图中蓝色的.avsc文件)。
所以,在上游表结构发生变更时,游必须同步去更新这个Schema文件才能完成数据的解析,这个Schema文件导致上下游系统在数据层是未完全解耦的状态;当上游系统发生变更时,下游系统需要先基于旧的Schema完成旧数据的消费,然后再把新的Schema同步过来,重启服务使用新的Schema消费新的数据。
总的来说,这个变更流程比较复杂,且下游对上游存在依赖,并且如果上游在投产的时候,没有来得及通知下游,当Schema变更以后,下游系统会使用旧的Schema去解析新的数据,可能就会导致无法预知的程序宕机,影响下游服务的稳定运行。
为解决这一问题,我们引入了Confluent的Schema Registry来实现Schema的解耦。
上图展示了在引入了Schema Registry后的数据流转图。
数据的流向和之前一样,主要区别是:在OGG侧感知到源端的表结构变更时,会主动去Schema Registry注册新的Schema,同时将获取到的Schema ID和数据一起写入Kafka。下游消费系统从消息中获取新的Schema ID,也会去Schema Registry请求获取对应的Schema,并使用这个Schema去解析数据。
因此,当Schema发生变化时,下游的自动获取和更新,免去了非必要的重启和未通知变更情况下的宕机问题。同时,我们通过Schema Registry将Schema中心化存储起来,方便后续进一步的管理。同时,引入Schema Registry以后,上游系统和下游系统都会对它有很强的依赖关系,这对Schema Registry服务本身的高可用提出了高要求。
①Schema Registry高可用实践
上图右侧是Schema Registry单个实例的内部实现原理。最上层是接口层,对外提供Restful形式的访问接口,注册请求(写请求)过来后,会基于内部的store层将数据以消息的形式写入Kafka的topic中,也就是说Schema Registry底层的真实存储实际上是一个Kafka的topic;而Store层会缓存所有的Schema,对于读请求,会直接从内存中获取。
高可用实践分为客户端和服务端两部分:
客户端:高可用的一部分依赖于客户端本身对Schema的缓存,在这种情况下,服务端如果暂时不可用,只会影响新增Schema的注册和解析;同时为了让服务端部署多个实例,以此避免单点问题导致的服务不可用问题,也要求客户端配置多实例地址。因此,我们在自研的SDK里集成了自动化配置这个功能。
服务端:除多实例部署以外,每个实例本身也做了独立的部署,以此避免和其他服务混部造成影响;第二层是服务层自身的存储缓存,在底层存储出现问题时,可以提供读服务。
同时,针对业务的需求,我们实现了集群跨域部署和容灾方案。
在我们内部,存在跨域获取数据的需求,自然就会产生跨域获取Schema的需求。
上图有两个域,左边是DC A,右边是DC B。在A域里,生产者将相关数据写入Kafka集群,将Schema注册到Schema Registry服务。在消费端,同时在A域和B域都会有对数据的消费需求,数据的同步一般的方案就是Replicator或MM等工具完成,比如topic1同步到B域对应A.topic1;在B域,拿到数据后,需要获取Schema ID对应的Schema才能去解析出数据。因此,我们需要跨域获取Schema的解决方案。
上图最下面蓝框中的就是一个跨域的Schema Registry集群的实现。橙色是A域的Schema Registry实例,绿色是B域。整个集群会有一个主节点,通过参数设置只能在A域产生。同时,Schema Registry底层的存储也使用A域的topic(即图中的_schemas),这是为了保证数据没有跨域写入,并尽量避免因为网络问题导致的数据重复或丢失问题。
对于写请求,都会转发给主节点实现,这要求B域中的Schema Registry实例开通和A域中的Schema Registry实例之间的网络关系;对于读请求,节点要缓存Schema数据,需要和底层的存储通信,这要求B域中的Schema Registry实例开通和A域中的Kafka Broker节点之间的网络关系,读请求是增量获取,跨域请求对网络流量的影响也会比较小。
针对单个域的Kafka集群故障或机房故障,数据本身的备份可以通过同步工具完成,由于Schema Registry底层的存储也是一个topic,它的数据也可以通过这种方式备份。在主节点集群出现问题时,我们可以通过脚本去实现参数的一键切换,从而保证服务的可用性。
以上是整个Schema Registry的跨域灾备方案。
我们使用的Schema Registry是Confluent的开源版本,在光大银行的系统整合过程中,进行了一些改造,主要包括两个方面:
- 安全&权限:这是将开源系统集成到企业内部所必需的改进之一,所以Schema Registry的实现充分考虑到这点,为使用者提供了标准的插件接口。我们基于这个接口实现了一个RBAC鉴权机制,确保服务的安全性,同时还增加了审计日志,以便进行用户请求的跟踪。
- 运维:我们先将服务与Kerberos整合,再把服务的内部指标和行内监控系统进行了打通。上图是测试环境的示例,由于Schema Registry服务本身对高可用性要求较高,我们在监控和报警方面前期做了很多工作,未来也将不断优化。
2)SDK封装
我们对Kafka客户端所做的二次开发做了SDK封装,提供统一的客户端接口,解决了以下问题:
- 减少不同客户端版本带来的性能差异和稳定性问题;
- 方便升级管理、灾备切换等;
- 更好地规范客户端行为,增强对客户端的数据面控制。
在上图右侧,我们展示了SDK已经实现及计划实现的特性,下面重点介绍下消费定制化这一特性。
如图所示,在消费定制化的使用场景中,某个生产者写入的某个数据,在下游可能并不是关心的,以订单数据为例,有些业务可能只关心订单的流转状态,有些业务只关心下单后的物流信息。因此,在大部分情况下,下游消费数据只是上游写入数据的一个子集,不同的消费者子集也可能不同。
基于这些场景,我们实现了消费定制化订阅的特性,将业务真正关心的schema托管到我们自研的Schema Manager服务中,在SDK消费时,可以提供给下游业务真正关心的数据,从而满足不同消费者的不同数据需求。
该特性的对外暴露由SDK封装实现,底层依赖于Schema Registry和Schema Manager,其中Schema Registry实现了用于中心化托管和对外服务的schema写入,而Schema Manager实现了用户自定义schema的中心化托管和对外服务,在SDK侧,我们实现了和这两个服务之间的交互,及自定义schema的获取,并完成底层异常情况的处理以及消费数据的抽取。
上图展示了消费定制化特性的处理流程,其核心实现有两个方面:
一是实现了和Schema Manager之间交互及容错的能力,并且提供给客户端调整能力,实现了一层缓存以提高效率。在未来,我们将考虑在客户端中实现checkpoint机制,以提高可用性。
二是实现了基于读schema解析时的兼容性,对于一些字段的偏差,我们可以自动处理,并提供给业务一些常用匹配策略的配置。
3)可观测性&可视化
最后介绍一些我们在观测性和可视化方面做的事情。
首先,我们对Kafka进行了全面的监控。之前,我们发现基于Kafka的机制的产品端监控粒度比较低,且缺失很多关键指标,如Kafka服务端网络请求处理线程的繁忙率,业务侧消费延迟等。因此,我们结合Kafka本身的指标以及我们内部的云原生监控体系,实现了更细粒度的监控报警方案,以更好地掌握Kafka的状态。
其次,我们还开发了服务控制台。前面我们提到,通过Schema Registry我们可以将schema的中心化存储。但是,这种数据并不是一种结构化的存储,这就需要我们通过控制台进行可视化的管理。自定义的schema也通过控制台去完成创建、更新和删除的操作。下面的图展示了一个租户自定义schema列表的示例。
三、总结&未来规划
1、总结
通过结合大数据领域新兴技术,我们对整个平台进行了拆分,解决了多项问题,当前准实时数据平台实现了以下收益:
1)更清晰的平台边界;
2)覆盖分钟级实时贴源数据场景;
3)数据服务总线生态建设;
4)提升了运维和运营能力。
2、未来规划
1)实时数据湖
实时数据湖平台目前处于持续落地阶段,未来我们将持续迁移适用于分钟级实时数据库的全部贴源场景,同时探索基于行业经验的湖仓一体和流批一体场景。
2)数据服务总线
- 持续围绕消息中间件生态进行拓展,基于SDK实现客户端的灾备切换功能,并结合服务端的灾备,共同实现平台级别的灾备方案;
- 由于总线的上下游接口的一个重要计算框架是Flink Connector,因此我们将基于它进行二次开发,实现部分核心功能,为接入的业务提供统一的体验;
- 除增强客户端接入能力外,我们将积极开发管理控制台,将一些重要的Kafka运维操作和服务部分运营能力整合到我们的控制台上,以提高整体的运维和运营效率;
- 着手计划长期的信创集群建设。
讲师介绍:张旭,光大银行准实时数据平台技术负责人,专注于分布式系统内核研发。在OLAP & 消息中间件领域有较丰富经验。开源爱好者,Apache RocketMQ committer,Prometheus contributor。