▼ 关注「Apache Flink」,获取更多技术干货 ▼
摘要:现代的应用大都以前后端分离的模式开发,在建设银行新一代系统中每笔交易对应三条消息报文:前端的埋点信息,发送的 HTTP 请求,返回的 HTTP 响应。建设银行在全球有大量的网点和业务员,每天产生大量的金融业务交易,包含海量的消息报文,其中包含:运营配送,现金配送,信用卡审批等几百种应用场景。而金融业务以复杂,稳定,要求高为特性,在银行业尤其如此。
本篇内容整理自建信金融科技开发工程师周耀在 Flink Forward Asia 2021 行业实践专场的演讲。将根据建信金科集约化运营服务团队,使用流计算框架 Flink 的经验。围绕如何引入有状态流计算稳定,及时,高效的将埋点,请求,响应三条消息进行业务加工,合并,向后传递给应用消费,最终产生业务价值。向大家展示流计算架构在银行运营大数据中的演化过程,应对方案及走过的弯路。希望能对金融企业使用流计算提供参考和借鉴。同时希望将建信金科在建设银行打磨出来的产品和场景进行产品化,推广到更多的同业和行业中去。
本文将围绕公司介绍、业务背景与挑战、方案演进及业务效果、未来展望四个方面展开。
Tips:点击「阅读原文」查看原文视频 & 演讲PDF~
一、公司介绍
建信金科是中国建设银行的金融科技子公司,由以前的建设银行软件开发中心整体转制而来、公司持续致力于成为 “新金融” 体系的科技推动者和生态连接者,助力中国建设银行集团数字化转型,赋能 “数字中国” 建设,让金融科技尽其所能,让社会更美好。现在同时也在做 To B 的数字化转型咨询业务和数字化建设业务。
建信金科集约化运营服务团队主要做的智能运营产品有 4 大块,分别是流程运营、交付管理、运营风险管控和渠道管理。本文主要分享的是 Flink 实时计算在流程运营这部分的实践应用。
二、业务背景与挑战
流程运营是以客户为中心,通过流程,数据,技术驱动,实现运营旅程及资源的数字化管控,构建 “纵横贯通,横向融合” 的全集团智能运营体系。
以信用卡流程为例,每个用户都可以通过银行的手机 APP、微信或者其他渠道申请建行的信用卡。用户提交申请之后,申请会流转到信用卡审批部门,审批部门会根据用户的一些综合情况判定额度,再将信息流转到发卡制卡部门,最后到配送部门,通过邮寄的方式送到用户的手中,用户激活后就可以开始使用了。其中每一个关键的业务节点,例如:申请,审核,发卡,制卡,激活可以称之为一个业务动作。多个业务动作串联,就能形成一个业务视角的业务流程。
对于这样一个信用卡申请流程,不同的角色从不同的角度,希望从这个流程当中获取到的信息都不一样。
作为申请的客户,想知道申请的卡是否已经审核通过,什么的时候能够寄出?
作为线下推荐办卡的工作人员,想知道的是今天采集的客户信息,有没有材料不齐全导致流程被退回?
作为银行领导,可能想实时获取到这一天所在支行办了多少笔信用卡申请,办理审核的平均时间是不是相比较以往来说变慢了?
对于信用卡这类关键且高频的应用,行内有一套专门的流程系统来满足用户需求,但是一些相对来说低频且数据分散,且各个系统之间的数据互相隔离的场景。例如:上门收款、ATM 现金加钞、现金供应链流程、对公开户流程等,类似的流程应用有几百种。如果对每一个这样的流程应用都单独进行开发和建设,不仅成本过高,而且对每一个组件都需要进行侵入性的改造,会引入更多的不确定性。
所以我们希望建设一个系统能够接入所有日志信息,把各个系统的数据打通,把分散的各个业务系统中的信息站在业务的视角将业务流程还原出来,从而让业务人员站在业务的全局视角来看这些数据,就能让数据产生更大的价值,也非常符合银行这几年数字化转型的趋势。我们智能运营就能够很好地满足这个需求。
为了满足各类业务用户,各类角色对流程分析的需求,流程运营主要负责4件事:
第一是把业务流程的现状完整地呈现出来;
第二是对流程的问题进行诊断;
第三是针对流程进行监控分析;
第四是对业务流程进行优化。
所以,我们需要做的第一件事就是把流程还原出来。那么由谁去定义流程?经过思考后,我们得出的结论是下放给业务用户。在以前业务流程都是由开发者写在代码里,对于业务人员来说,信用卡审批只知道是否通过这样的结果数据,但实际上审核步骤可能会有一些依赖,比如步骤 A、步骤 B、步骤 C 都通过了才是真正意义上的审批流程通过。
如果把定义过程下放给业务用户,业务用户由于不知道系统的内部流程,起初可能也不知道 A、B、C 这三个步骤审批完成了才是真正完成,所以我们需要提供一个工具让业务用户去尝试。业务人员根据直觉先定一个流程参数,流程运营系统根据真实的数据按照业务人员定的流程去运行,还原成一个真实的流程实例,来验证看这个流程是否符合业务场景。如果符合,就用这个业务流程的参数上线,如果不符合,业务用户可以及时针对这个场景再进行修改迭代,一点点去完善,在迭代中不断完善业务流程。
接着,有了这些运行出来的流程之后就可以在这个流程上面建立一些流程应用,比如指标、监控预警等。还以信用卡申请业务为例,对于信用卡申请的通过率是多少,核发之后的激活率是多少等指标,
之后,我们会做一系列的流程的监控和运维。
最后,有了这些指标数据,就可以利用这些数据去指导赋能业务,提高运转的效率,提升服务满意度。
希望能将建信金科在建设银行打磨出来的产品和场景进行产品化,推广到更多的同业和行业中去。
为了达到这样的目标,我们也会面临一些业务的挑战:
业务数据来源于多个系统。我们建行也在做数据湖,但是数据湖里面的数据仅仅是一些数据的简单堆砌,如果无法形成一个全局的视图,就很容易导致数据孤岛。
业务灵活性高。希望能够提供一种机制,让业务去自主配置流程,在迭代中不停地完善流程。
数据的实时性要求高。要求是能够在业务发生后实时地加工流程。
数据来源于多个流。横向看数据来源于多个系统,比如审核、发卡、激活,这些系统大多都是前后端分离部署,既有前端的埋点,也有后端的请求响应,我们需要将各个系统数据收集起来,把对应的埋点和请求响应实时地关联在一起,才能得到一个业务操作。
业务数据庞大。日均几百亿的数据,7×24 小时不停地到达。
为了解决以上痛点,我们采取了一系列措施:
采用消息队列,通过 Kafka 把生产的业务日志和数据处理系统隔离出来,尽可能减少对应用的侵入式改造。
我们定义参数,通过站点和流程进行配置和管理。
我们使用了 Flink,能做到实时处理并且可以横向扩展。
我们使用了流批一体节省资源。
因为我们所有的流计算应用都是运行在建行的大数据云平台上的,所以我们先介绍一下大数据云平台。
上图是大数据云平台,数据加工的架构如下:从网卡、埋点、日志、数据库 CDC 等将数据接进来,再到Flink做实时数据处理,最后把处理完的结果加工存储到存储系统里,比如 HBase、GP 和 Oracle,最后由上层的应用将结果进行可视化。
三、方案演进及业务效果
在建行,数据通常来源于三个渠道,分别是客户渠道、员工渠道和外联渠道。
客户渠道的交易主要是手机银行 APP 上发起的,员工渠道的交易主要是指建行分布在各个网点的银行柜员操作发起的,比如去银行办理一笔存款业务,柜员就会在员工渠道发起一笔存款交易,外联渠道是指外部系统调用建行的接口形成的交易。
渠道发起的每一个业务动作对应数据处理系统的三条日志报文,分别是请求、响应和埋点,它们都有全局唯一的跟踪号。这里存在一个难点是对源源不断的三条数据流提取唯一标识,并根据这个唯一标识把三条数据 join 连接起来,形成完整的一个业务动作。此外,这里还涉及到消息先来和后来、中间状态存储以及消息延迟到达的问题。
为了解决这些问题,方案也进行了三次演化。
第一个方案采用滑动窗口,但是很快就出现了效率问题;
所以第二个方案是采用 Flink 自带的 interval join,但是遇到了程序 OOM 运行不稳定的问题。
接着我们使用了第三个方案,自己实现了一个 keyedProcessFunction,手动管理中心状态,解决了效率和稳定性问题。
正式分享细节之前,先介绍一下背景。每个业务动作对应的 3 条数据 80% 的情况下会在 5 秒钟内到达,但是由于网络的抖动或者采集的延迟,我们需要容忍一个小时左右的延迟,而且一个全局跟踪号只会对应一个请求、一个响应和一个埋点,也就是一个业务动作对应的三条消息只会成功 Join 上一次。
为了满足上述要求,我们很快推出了 1.0 版本,使用的是滑动窗口,当请求响应到达之后,先把它分开再提取唯一业务标识,然后再做一次 keyBy。因为这里存在一个前后到达的问题,有可能是请求先来,也有可能是响应先来。所以我们采用了一个 10 秒钟的滑动窗口,5 秒钟滑一次,如果请求来了,响应能够在 5 秒之内到达就能在窗口内连接上,就可以直接进行业务操作输出;如果 5 秒内没有到达,就要把状态提取出来存到 Redis 中做等待。等下一次响应来了,它就会先去 Redis 上根据业务标识去查看有没有请求,如果有,就拿出来再进行业务操作和业务处理。
也就是把请求和响应先做一次连接,然后把连接上的请求响应和埋点再做一次连接,相当于做了两次实时 join,并把 Redis 作为状态存储,将没有连接上的消息存放在里面。
但是这会导致一些缺点:
第一,是吞吐量低。随着数据接入的消息越来越多,Flink 设置的并行度就要越来越大,使用的 Redis 连接数请求也会越来越多,受限于 Redis 的吞吐量和连接数限制,达到一个阈值之后就会限制整体的吞吐量;
第二,Redis 运维压力大。数据量大了之后,没有连接上的数据就会越来越多,Redis 很快就会满了。为了保证稳定性就需要做一些手动的清除;
第三,需要手动在 Flink 里面写一些额外的代码与 Redis 进行交互;
第四,Redis 的状态积压变大,会导致里面的参数或者数据过期,或者被挤出。
所以我们演化出了第二个版本,interval join 版本。
interval join 是 Flink 框架自带的特性,使用 RocksDB 做状态存储,相当于用它替换掉 Redis。
使用这个方案的初衷一方面是希望能够降低运维压力,另一方面,随着数据量增大它可以很方便地做横向扩展。
第一个优化是数据到达之后,根据配置做一些过滤,把不需要的数据提前过滤掉,使得需要处理的数据量下降很多。第二是使用 interval join,对请求响应做一次 join,然后把 join 上的数据跟埋点再做一次 join。这里面的逻辑跟前面的 1.0 方案保持一致。同时,为了达到容忍一个小时左右数据延迟的要求,我们设置一个 30 分钟的上下限区间。
但是运行了几天之后,我们发现它经常出现 OOM,由于使用的是 Flink on K8s,分析起来比较复杂。后来通过阅读源码,我们发现 Flink 的 interval join 会将它上下限时间区间内的数据全部保留在状态里面,直到数据过期才会删除,这也导致了一些新的问题。
首先 checkpoint 体积会很大,我们通过阅读 Flink 的 Interval join 实现的源码发现,Interval Join 会将 30 分钟时间上下线内的状态都全部保存在 Rocks DB 状态后端中因为它会把 30 分钟内的数据全部保留下来,以便于处理一对多,和多对多的 join 情况。
第二,运行不稳定,它使用了 RocksDB 作为状态存储,RocksDB 本身是用 c++ 写的,Flink 使用 java 去调用它,很容易造成 OOM。并且由于一些约束条件,只能通过配置参数的方式给 RocksDB 配置足够的空间,防止它 OOM。对于我们行业的应用来说,一旦发生了 OOM 就会导致正在实时的业务中断,这是绝对不允许的。
其次,我们在分析了行内 Join 的场景发现:在行内的情况下请求、响应、埋点,一定是一个一对一的关系,不会像数据库一样存在一对多的关系。鉴于这个背景,我们考虑,这一个小时区间内,其实很多数据是不必要保存在状态后端里,所以我们想自己做状态管理,将不必要的数据从状态后端删除。于是演化出了第三个版本。
因为只会 join 上一次,所以在 3.0 的时候,自己实现了一个 keyedProcessFunction 代码去管理这个状态。
数据到达以后先做一次过滤,不管它是请求/响应/埋点,统一把它 union 起来,再根据提取出来的唯一标识进行 key by 分组,分组之后,具有相同唯一标识的消息就会落在同一个 slot 当中。每条一条消息来了以后会去检查响应和埋点是否已经到达,是不是符合 join 的条件,如果满足了条件就把它输出同时清楚状态后端中的数据,如果不满足输出条件,就把消息存在 RocksDB 的状态后端中继续等待。这样就可以做到手动管理状态,减少了 90% 的状态存储,带来了很大的收益。
首先使用 RocksDB 作为状态后端,相比于 1.0 版本,吞吐量提升了很多。
第二,它降低了开发的运维难度。第三提升了实时的处理能力,后面数据量再增多的时候可以通过增加更多的节点来进行横向扩展。此外,Flink 自带了很多 join 的方案,提供了良好的接口让我们更方便地去实现里面的逻辑。
有了流程的基础数据,我们在基础数据上针对这个流程基础数据做了一些指标计算,实时的流程指标计算也进行了 2 次方案迭代。
1.0 版本的实时指标使用了流计算和离线计算来同时处理,受限于对技术栈和工具的熟练度,我们做的是分钟级别的准实时指标。首先,数据来源是 Kafka,经过 Flink 进行预聚合处理之后 sink 到 Kafka 里,再由 Spark 周期性地调入,把数据从 Kafka 写到 GP 库里。我们是以 GP 库为核心,用 SQL 进行指标计算,将指标计算结果再写回到 Oracle 里面,最后再由应用去消费,这是我们使用的 1.0 版本。
随着我们对 Flink 和工具的愈发熟悉,团队也在思考如何做到秒级的真实时。2.0 版本可以直接从 Kafka 里接数据进来,再用 Flink 进行实时指标计算,直接把数据写到 Oracle 里面,做到了端到端的秒级的延迟,是一个真实时的指标。
在银行,渠道、产品和机构是三个非常重要的维度,我们对线上生产的业务流程,分别做了渠道、产品和机构的分布统计,比如需要对每个网点统计线上线下员工渠道办理的业务流程占比是多少?比如流程从开始到办结,会不会是因为中间有材料没有准备齐全而发生回退,还有每一个环节的平均处理时长等。
所以综合来说,Flink 的确给项目带来了比较大的收益。
首先 Flink SQL 使得加工的流程变得更容易。Flink1.11 之后,SQL 的功能慢慢完善,愈发地方便开发人员使用;
第二,它提供了端到端的、真正秒级的实时;
第三,使用 Flink 能够减少数据组件的交互,缩短整个数据链路,提高了数据的稳定性。
上图中间是建设银行手机 APP 端的一个现金预约、上门收款的业务流程。
首先是现金入账,然后现金清点,再是现金交接,最后业务受理完成。我们分析出来的流程和指标,除了可以在手机端的 APP 查看,也可以在员工渠道里面查看,比如左边每一个绿点代表一个站点,每个站点完成之后就能串起来形成一个完整的流程。
所以对于业务人员来说,第一个得到的价值就是流程的重塑。从指标的接入到指标的可视化到数据挖掘,最终根据流程得出来指标,去优化流程,形成了一个完整的业务闭环。
有了这些基础的数据之后,我们就可以针对业务流程进行风险的干预。比如某个客户要办理一个大金额的现金取款业务,系统会实时的通知网点经理对客户进行挽留和干预。
其次,流程分析带来了资源的优化配置。基于流程的应用可以监测业务资源的使用,比如某个流程突然申请变多,我们会考虑是不是岗位人手不够导致的办理时长过长,系统会及时进行预警监控,分配更多的工作人员。这样就可以通过资源的配置,优化资源使用效能,提升服务满意度。类似的流程场景,在行内也被推广到很多业务线应用,广受好评。
通过 Flink 对实时数据的加工,为建设银行做数字化转型提供了数据方面强有力的支撑。
四、未来展望
目前这套流程运营落地都只在我们建设银行内部,未来我们希望将这套智能运营流程的方法论进行产品化、平台化,并推广到更多的行业中去,让更多行业得到金融级的流程运营的实践。
往期精选
更多 Flink 相关技术问题,可扫码加入社区钉钉交流群~