作者:周耀
用户背景
建信金科是中国建设银行的金融科技子公司,由以前的建设银行软件开发中心整体转制而来、公司持续致力于成为 “新金融” 体系的科技推动者和生态连接者,助力中国建设银行集团数字化转型,赋能 “数字中国” 建设,让金融科技尽其所能,让社会更美好。现在同时也在做 To B 的数字化转型咨询业务和数字化建设业务。通过使用Flink建信金科获得了较大的收益,其中包括:更有时效性的流程服务,更灵活的流程配置与流程还原,更完整的流程指标监控分析,更有效的集团资源复用。
业务需求
流程运营是以客户为中心,通过流程,数据,技术驱动,实现运营旅程及资源的数字化管控,构建 “纵横贯通,横向融合” 的全集团智能运营体系。以信用卡流程为例,每个用户都可以通过银行的手机 APP、微信或者其他渠道申请建行的信用卡。用户提交申请之后,申请会流转到信用卡审批部门,审批部门会根据用户的一些综合情况判定额度,再将信息流转到发卡制卡部门,最后到配送部门,通过邮寄的方式送到用户的手中,用户激活后就可以开始使用了。其中每一个关键的业务节点,例如:申请,审核,发卡,制卡,激活可以称之为一个业务动作。多个业务动作串联,就能形成一个业务视角的业务流程。
对于信用卡这类关键且高频的应用,行内有一套专门的流程系统来满足用户需求,但是一些相对来说低频且数据分散且各个系统之间的数据互相隔离的场景,例如上门收款、ATM 现金加钞、现金供应链流程、对公开户流程等,类似的流程应用有几百种。如果对每一个这样的流程应用都单独进行开发和建设,不仅成本过高,而且对每一个组件都需要进行侵入性的改造,会引入更多的不确定性。因此需要建设一个系统能够接入所有日志信息,把各个系统的数据打通,把分散的各个业务系统中的信息站在业务的视角将业务流程还原出来,从而让业务人员站在业务的全局视角来看这些数据,就能让数据产生更大的价值,也非常符合银行这几年数字化转型的趋势。
为了满足各类业务用户,各类角色对流程分析的需求,流程运营主要负责4件事:
第一是站在业务人员的视角完整呈现业务流程的现状;
第二是对业务流程中可能出现的问题进行诊断;
第三是针对业务流程进行指标监控分析;
第四是对业务流程进行优化重塑提供建议。
为了达到这些目标,建信金科遇到了一些业务的挑战:
业务数据来源于多个系统多个流;
横向看:数据来源于多个系统,比如审核系统、发卡系统、激活系统,这些系统可能分属于不同的逻辑子系统,部署在不同的物理子系统中;
纵向看:这些系统大多都是前后端分离部署,既有前端的埋点,也有后端的请求响应,如果是简单的堆砌,不能将这些数据站在业务的角度以一个全局的视图还原出业务流程,很容易导致数据孤岛。
业务流程还原的需求灵活性高。希望能够提供一种机制,让业务去自主配置流程,在迭代中不停地完善流程; 业务数据还原的实时性要求高。要求是能够在业务发生后实时地加工流程; 业务数据量庞大且持续到达。日均几百亿的数据,7×24 小时不停地到达。
为了解决业务上面临的挑战,建信金科通过应用Flink,将数据从网卡、埋点、日志、数据库 CDC 等接入,再用Flink做实时的流程数据流程的处理,接着将流程处理的结果加工存储到存储系统里,例如: HBase、GP 和 Oracle等。最后由上层的应用将结果进行可视化。
接下来分别介绍建信金科在流程分析和流程指标两个场景下的生产实践,首先来看流程分析场景。
在建行,数据通常来源于三个渠道,分别是客户渠道、员工渠道和外联渠道。客户渠道的交易主要是手机银行 APP 上发起的;员工渠道的交易主要是指建行分布在各个网点的银行柜员操作发起的,比如去银行办理一笔存款业务,柜员就会在员工渠道发起一笔存款交易;外联渠道是指外部系统调用建行的接口形成的交易。
渠道发起的每一个业务动作对应数据处理系统的三条日志报文,分别是请求、响应和埋点,它们都有全局唯一的跟踪号。这里存在一个难点是对源源不断的三条数据流提取唯一标识,并根据这个唯一标识把三条数据 join 连接起来,形成完整的一个业务动作。此外,这里还涉及到消息先来和后来、中间状态存储以及消息延迟到达的问题。具体来说,每个业务动作对应的 3 条数据 80% 的情况下会在 5 秒钟内到达,但是由于网络的抖动或者采集的延迟,需要容忍一个小时左右的延迟。
为了解决这些问题,方案进行了三次演化。
第一个方案采用滑动窗口,当请求响应到达之后,先把它分开再提取唯一业务标识,然后再做一次 keyBy。因为这里存在一个前后到达的问题,有可能是请求先来,也有可能是响应先来,所以采用了一个 10 秒钟的滑动窗口,5 秒钟滑一次。如果请求来了响应能够在 5 秒之内到达,就能在窗口内连接上并直接进行业务操作输出;如果 5 秒内没有到达,就要把状态提取出来存到 Redis 中做等待。等下一次响应来了,它就会先去 Redis 上根据业务标识去查看有没有请求,如果有,就拿出来再进行业务操作和业务处理。也就是把请求和响应先做一次连接,然后把连接上的请求响应和埋点再做一次连接,相当于做了两次实时 join,并把 Redis 作为状态存储,将没有连接上的消息存放在里面。但是这会导致一些缺点:
吞吐量低。随着数据接入的消息越来越多,Flink 设置的并行度就要越来越大,使用的 Redis 连接数请求也会越来越多,受限于 Redis 的吞吐量和连接数限制,达到一个阈值之后就会限制整体的吞吐量;
Redis 运维压力大。数据量大了之后,没有连接上的数据就会越来越多,Redis 很快就会满了。为了保证稳定性就需要做一些手动的清除; 需要手动在 Flink 里面写一些额外的代码与 Redis 进行交互; Redis 的状态积压变大,会导致里面的参数或者数据过期,或者被挤出。
第二个方案是采用 Flink 自带的 interval join。Interval join 是 Flink 框架自带的特性,使用 RocksDB 做状态存储,相当于用它替换掉 Redis。使用这个方案的初衷一方面是希望能够降低运维压力,另一方面,随着数据量增大它可以很方便地做横向扩展。
第一个优化是数据到达之后,根据配置做一些过滤,把不需要的数据提前过滤掉,使得需要处理的数据量下降很多。第二是使用 interval join,对请求响应做一次 join,然后把 join 上的数据跟埋点再做一次 join。这里面的逻辑跟前面的 1.0 方案保持一致。同时,为了达到容忍一个小时左右数据延迟的要求,我们设置一个 30 分钟的上下限区间。
但这个方案的问题在于经常出现 OOM。由于使用的是 Flink on K8s,分析起来比较复杂,后来通过阅读源码,发现 Flink 的 interval join 会将它上下限时间区间内的数据全部保留在状态里面,直到数据过期才会删除,这也导致了一些新的问题。
在进一步分析了行内的 Join 场景之后发现,在行内的情况下请求、响应、埋点一定是一对一的关系,不会像数据库一样存在一对多的关系。鉴于这个背景,这一个小时区间内很多数据不需要保存在状态后端里,所以可以自己做状态管理,将不必要的数据从状态后端删除。于是演化出了第三个方案,通过自己实现KeyedProcessFunction来手动管理中心状态。
在第三个方案中,数据到达以后会先做一次过滤,不管它是请求/响应/埋点,统一把它 union 起来,再根据提取出来的唯一标识进行 key by 分组,分组之后,具有相同唯一标识的消息就会落在同一个 slot 当中。每条一条消息来了以后会去检查响应和埋点是否已经到达,是不是符合 join 的条件,如果满足了条件就把它输出同时清楚状态后端中的数据,如果不满足输出条件,就把消息存在 RocksDB 的状态后端中继续等待。这样就可以做到手动管理状态,减少了 90% 的状态存储,带来了很大的收益。
有了流程的基础数据,建信金科针以此为基础实现了实时指标计算。实时的流程指标计算也进行了 2 次方案迭代。
1.0 版本的实时指标使用了流计算和离线计算来同时处理,受限于团队对技术栈和工具的熟练度,做的是分钟级别的准实时指标。首先,数据来源是 Kafka,经过 Flink 进行预聚合处理之后 sink 到 Kafka 里,再由 Spark 周期性地调入,把数据从 Kafka 写到 GP 库里。这个方案是以 GP 库为核心,用 SQL 进行指标计算,将指标计算结果再写回到 Oracle 里面,最后再由应用去消费。
随着对 Flink 和工具的愈发熟悉,团队也在思考如何做到秒级的真实时。2.0 版本可以直接从 Kafka 里接数据进来,再用 Flink 进行实时指标计算,直接把数据写到 Oracle 里面,做到了端到端的秒级的延迟,是一个真实时的指标。
在银行,渠道、产品和机构是三个非常重要的维度。建信金科对线上生产的业务流程分别做了渠道、产品和机构的分布统计,比如需要对每个网点统计线上线下员工渠道办理的业务流程占比是多少、流程从开始到办结,会不会是因为中间有材料没有准备齐全而发生回退,以及每一个环节的平均处理时长等。
《Apache Flink 案例集(2022版)》——5.数字化转型——建信金科-Apache Flink 在国有大型银行智能运营场景下的应用(下):https://developer.aliyun.com/article/1227939