Flink 从0到1实战实时风控系统「W结」

302 阅读5分钟

Flink 从0到1实战实时风控系统

核心代码,注释必读

// download:3w ukoou com

Apache Flink是一个面向数据流处理和批量数据处理的可分布式的开源计算框架,它基于同一个Flink流式执行模型(streaming execution model),能够支持流处理和批处理两种应用类型。由于流处理和批处理所提供的SLA(服务等级协议)是完全不相同, 流处理一般需要支持低延迟、Exactly-once保证,而批处理需要支持高吞吐、高效处理,所以在实现的时候通常是分别给出两套实现方法,或者通过一个独立的开源框架来实现其中每一种处理方案。比较典型的有:实现批处理的开源方案有MapReduce、Spark;实现流处理的开源方案有Storm;Spark的Streaming 其实本质上也是微批处理。
Flink在实现流处理和批处理时,与传统的一些方案完全不同,它从另一个视角看待流处理和批处理,将二者统一起来:Flink是完全支持流处理,也就是说作为流处理看待时输入数据流是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。

特性

  • 有状态计算的Exactly-once语义。状态是指flink能够维护数据在时序上的聚类和聚合,同时它的checkpoint机制

  • 支持带有事件时间(event time)语义的流处理和窗口处理。事件时间的语义使流计算的结果更加精确,尤其在事件到达无序或者延迟的情况下。

  • 支持高度灵活的窗口(window)操作。支持基于time、count、session,以及data-driven的窗口操作,能很好的对现实环境中的创建的数据进行建模。

  • 轻量的容错处理( fault tolerance)。 它使得系统既能保持高的吞吐率又能保证exactly-once的一致性。通过轻量的state snapshots实现

  • 支持高吞吐、低延迟、高性能的流处理

  • 支持savepoints 机制(一般手动触发)。即可以将应用的运行状态保存下来;在升级应用或者处理历史数据是能够做到无状态丢失和最小停机时间。

  • 支持大规模的集群模式,支持yarn、Mesos。可运行在成千上万的节点上

  • 支持具有Backpressure功能的持续流模型

  • Flink在JVM内部实现了自己的内存管理

  • 支持迭代计算

  • 支持程序自动优化:避免特定情况下Shuffle、排序等昂贵操作,中间结果进行缓存

Flink 从0到1实战实时风控系统实战

实时框架 1.0:基于 Flink DataStream API 构建

如果你熟悉 Flink DataStream API,那你肯定会发现 Flink 的设计天然满足风控实时特征计算场景,我们只需要简单的几步即可统计指标,

Flink DataStream 流图

实时特征统计样例代码如下:

| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ``` // 数据流,如topic DataStream dataStream = ... SingleOutputStreamOperator windowOperator = dataStream // 过滤 .filter(this::filterStrategy) // 数据转换 .flatMap(this::convertData) // 配置watermark .assignTimestampsAndWatermarks(timestampAndWatermarkAssigner(config)) // 分组 .keyBy(this::keyByStrategy) // 5分钟滚动窗口 .window(TumblingEventTimeWindows.of(Time.seconds(300))) // 自定义聚合函数,内部逻辑自定义 .aggregate(AllDecisionAnalyzeCountAgg.create(), AllDecisionAnalyzeWindowFunction.create());

| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

1.0 框架不足:

-   特征强依赖开发人员编码,简单的统计特征可以抽象,稍微复杂点就需要定制
-   迭代效率低,策略提需求、产品排期、研发介入、测试保障、一套流程走完交付最少也是两周
-   特征强耦合,任务拆分难,一个 JOB 包含太多逻辑,可能新上的特征逻辑会影响之前稳定的指标

总的来说,1.0 在业务初期很适合,但随着业务发展,研发速度逐渐成为瓶颈,不符合可持续、可管理的实时特征清洗架构。

##### [](https://jifuwei.github.io/yuque/Flink%20%E5%9C%A8%E9%A3%8E%E6%8E%A7%E5%9C%BA%E6%99%AF%E5%AE%9E%E6%97%B6%E7%89%B9%E5%BE%81%E8%90%BD%E5%9C%B0%E5%AE%9E%E6%88%98.html#%E5%AE%9E%E6%97%B6%E6%A1%86%E6%9E%B6-2-0%EF%BC%9A%E5%9F%BA%E4%BA%8E-Flink-SQL-%E6%9E%84%E5%BB%BA "实时框架 2.0:基于 Flink SQL 构建")实时框架 2.0:基于 Flink SQL 构建

1.0 架构的弊端在于需求到研发采用不同的语言体系,如何高效的转化需求,甚至是直接让策略人员配置特征清洗逻辑直接上线?如果按照两周一迭代的速度,可能线上早被黑灰产薅的“面目全非”了。

此时我们研发团队注意到 Flink SQL,SQL 是最通用的数据分析语言,数分、策略、运营基本必备技能,可以说 SQL 是转换需求代价最小的实现方式之一。

看一个 Flink SQL 实现示例:

| ```
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 
``` | ```
-- error 日志监控 -- kafka source CREATE TABLE rcp_server_log (     thread varchar,     level varchar,     loggerName varchar,     message varchar,     endOfBatch varchar,     loggerFqcn varchar,     instant varchar,     threadId varchar,     threadPriority varchar,     appName varchar,     triggerTime as LOCALTIMESTAMP,     proctime as PROCTIME(),      WATERMARK FOR triggerTime AS triggerTime - INTERVAL '5' SECOND ) WITH (     'connector.type' = 'kafka',     'connector.version' = '0.11',     'connector.topic' = '${sinkTopic}',     'connector.startup-mode' = 'latest-offset',     'connector.properties.group.id' = 'streaming-metric',     'connector.properties.bootstrap.servers' = '${sinkBootstrapServers}',     'connector.properties.zookeeper.connect' = '${sinkZookeeperConnect}}',     'update-mode' = 'append',     'format.type' = 'json' );  -- 此处省略 sink_feature_indicator 创建,参考 source table -- 按天 按城市 各业务线决策分布 INSERT INTO sink_feature_indicator SELECT     level,     loggerName,     COUNT(*) FROM rcp_server_log WHERE     (level <> 'INFO' AND `appName` <> 'AppTestService')     OR loggerName <> 'com.test' GROUP BY     TUMBLE(triggerTime, INTERVAL '5' SECOND),     level,     loggerName; 
``` |
| ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

我们在开发 Flink SQL 支持平台过程中,遇到如下问题:

-   一个 SQL 如果清洗一个指标,那么数据源将极大浪费
-   SQL merge,即一个检测如果同源 SQL 则进行合并,此时将极大增加作业复杂度,且无法定义边界
-   SQL 上线需要停机重启,此时如果任务中包含大量稳定指标,会不会是临界点