目的
实时解析处理用户的注册,实名,申额,支用等用户业务流程数据binlog,计算用户生命周期的相应指标到Kudu中,并且需要将当用户指标数据发生变更后也要同时推送到kafka 给其他业务做增量计算,根据这些实时指标,进行后续实时营销等信息推送。
背景介绍
用户在app上进行简单注册后,会赋值给用户一个userid,但是后续实名等发生具体业务后,会给用户分配一个custno与userid映射关系相关联,接下来用户的所进行的业务例如绑定银行卡,人脸识别,申额,支用,还款等环节都是以custno作为用户标识,我们的目的是要统计用户在app的全生命流程,包括注册等还没有分配custno的用户,所以最终标签的主键设置为userid,分配后的用户需要实时的将custno转为userid。
问题描述
用户注册数据信息记录到注册表中只有userid,但是在用户实名时,用户需要进行ocr认证,绑定银行卡,银行卡信息数据记录到实名表中,且以custno为用户标识,完成ocr认证和绑定银行卡信息后,算完成实名,此时会分配custno并将userid 关系相绑定,数据记录到用户信息表中,但是当实名认证表中的数据从binlog过来到flink处理时,会出现用户信息表中custno和userid的映射数据并没有落表,导致匹配不到丢失。
解决方案试错
1:利用flink异步处理+Kudu异步api的方式+缓存来进行映射关联。
方式说明
binlog过来的数据解析按照custno作为keyby,利用AsyncDateStream进行异步关联,继承RichAsyncFunction函数,重写aysncInvoke方法进行维表关联,设置缓存cache,提高效率,先读cache,cache取不到,根据custno从Kudu用户信息表异步取数,进行拼接,并把该数据加载到cache中。
缺点
对于维表-用户信息表更新不是特别频繁可以实现join维表的目的,但是业务表中实名信息数据多半和custinfo表映射数据同时创建更新,对于更新频繁的用户信息表,很容易出现映射信息由于网络原因还没有落库,导致匹配不上数据丢失问题。
2:利用广播流缓存映射关系,通过State进行保存和管理。
方式说明
另起一个流接收用户信息表binlog数据,将解析的映射关系流广播出去,与实名信息流数据进行connect,重写BroadcastProcessFunction函数,在processeBroadcastElement中从广播流种将映射关系加载到BrodecastState状态管理保存,processeElement进行处理从State中取映射关系,对于存量用户的映射关系再通过异步+缓存的方式1进行读取。
缺点
对于用户首次进行实名时,写入两表数据都是事务性,用户信息流的数据由于数据量多消费慢等原因,产生数据迟到,故也出现了方式1类似的丢数据问题,但相比于方式1,丢数据问题得到一定缓解
3:通过intervalJoin方式,设置用户信息流的被join的时间区间,解决数据迟到导致数据丢失问题
方式说明:
由于方式2出现维表-用户信息表 流数据迟到原因导致数据丢失,于是进行改造,采用intervalJoin方式将实名信息流和用户信息流进行join,设置实践区间为前后30秒,intervalJoin原理不在这啰嗦,这样解决了新用户两表同时落数据维表数据迟到问题,但是对于存量用户,用户信息表的映射信息可能在几天或者几个月之前就已经入库,实名信息表某些数据进行了U操作,导致在flink消费实名信息表到该条用户数据时,而流2维表中在前后一分的时间范围内并不存在该数据流,所以在本次join后,又通过异步+缓存的方式,对于没有匹配到的用户进行异步关联库表数据。
缺点:
Dataframe api只支持InnerJoin方式,也就是说没有通过intervalJoin的数据直接丢掉,导致数据丢失,并没有按照我的设想(以leftjoin的形式),将为匹配到的数据流出,导致下一步异步加缓存未生效。但是通过延长时间间隔可以解决百分之98以上用户的问题,但是仍然有丢数据问题产生。
4:依然通过intervalJoin方式做首次关联,异步加缓存补充存量用户数据。
方式说明:
对于Dataframe api 不支持leftJoin方式,但是flink sql 支持,于是将两流转换,以sql interval join 实现了leftJoin方式再加上异步和缓存补偿存量用户,之后再转回stream流进行下面的业务操作。
总结:
目前采用方式4运行快一个月了,暂时还没发现丢数据问题,由于内网开发环境,代码不方便贴出来,望见谅,如果大家还有其他好的思路方式,也遇到了类似的问题,可以一起讨论进步。