导读
风控场景面临的挑战
在风控业务场景中,黑产是极为猥琐的,他们会想尽一切办法来逃避我们的检测,因为在我们的系统里多待一分钟,他们就能得到网民的流量,就有可能获利。因此如何快速有效的发现黑产的攻击,能够实时的动态感知到黑产不断变化的作案手段是整个风控环节面临的巨大挑战。
图一 风控对抗大体流程
智能监控预警整体架构设计
谈到监控预警系统,首先想到的是依靠olap引擎,预警模块轮询olap引擎,获取数据进行告警。可视化监控功能依靠olap引擎也可轻松实现。该方案能否成功则重度依赖olap引擎,需要支持高qps,高吞吐。
针对集团提供的olap技术服务我们进行了比较:
druid |
druid目前无法以非人工的方式对接 |
clickhouse |
无法支持高qps |
es |
高频的统计聚合查询容易oom,且es成本较高 |
该方案为预警模块主动轮询获取指标数据,随着监控项的数量越来越多,势必对olap引擎的压力会越来越大。且olap技术没有银弹,需要重新进行方案设计。
指标是无论如何都需要计算的,可以在指标计算完成的时刻直接进行预警规则的判断来实现预警功能。监控功能可以使用olap引擎来实现,因为可视化监控属于用户点查的行为,qps很低。
整体技术实现如下图:
图二 智能预警系统整体架构设计
指标实时计算
指标的实时计算是核心能力,该服务面临海量的并发,随着业务的增长,需要能够轻松的在线扩容。Apache Flink技术方案无法解决这个问题。利用集团云平台可以实现这一点。针对我们的指标计算逻辑需求,均为pv、uv类。例如:
pv类 |
每分钟微聊中每个策略的命中量 |
uv类 |
每分钟微聊中每个appid对应的用户量 |
计算不涉及特别复杂的逻辑,遂决定自己实现一套计算服务,部署在云平台上实现灵活的扩缩容。
我认为计算类型无非两种,非相关计算(单条数据即可完成计算,例如map、flatmap、filter)和相关计算(数据需要相遇才可完成计算,例如聚合算子 reduce)。实际上还是MapReduce纯粹的思想。
整体流程如下:
图三 计算流程
compute服务进行非相关计算,可以灵活横向扩展。实时数据通过scf传给compute。进行pv、uv计算时,属于相关计算,数据需要相同的key为一组相遇才行。这里直接使用高性能kv存储进行数据的汇聚。目前我们使用redis集群。则redis中就会有统计好的指标结果了。
这其中有个问题就是compute是多少台,这个是不确定的。上游采集来的数据会均匀的分布在这些comptue节点上,每个compute节点计算完成后会写入redis。但是无法知道每个compute节点是否都计算完成写进redis了。这样其实是无法知道某个时刻下某个指标是否计算完成的。
这时不难想象为何flink、spark无法支持在线扩容,像这种计算框架在job启动时需要明确的声明计算节点有多少个,同时他们在运行时是一个主从的架构,每个任务也是分发到各个worker上的,这些worker计算完成后会跟master进行rpc通信。是的,是需要一个角色来负责协调这个事情。流程演变为下图:
图四 计算流程演变
增加coordinator协调者,每个指标在compute计算完成写入redis后,给协调者发消息。是否计算完成由协调者产生决定。
协调者目前只允许由一个节点在线,他负责协调compute集群。是典型的master-slave架构。经典的方案为compute均向coordinator注册,并且保持心跳。compute服务是灵活扩容的,coordinator根据心跳来维护一个注册表即可解决这个问题。
该方案即在业务中实现了注册中心,在当时项目实施阶段由于工期较短,采用了另一种”上闹铃的方案“。
”上闹铃“的分布式协调解决方案:
我们认为一个指标在compute集群里所有的节点计算完成的时刻应是几乎同时的,当每个compute节点计算完毕后跟协调者通信,协调者会针对该指标生成一个定时任务(10s后执行),紧接着又另一个compute节点跟协调者通信后,协调者会更改定时任务的执行时间(接受请求的时刻+10s)。相当于协调者会有一个容忍的时间,会等待这些compute节点的完成。该方案无需实现注册中心,对于compute服务是透明的,可以任意的扩容。
eventtime
设计到实时窗口统计计算,就会谈到时间语义。开始接触flink的时候,他有一个显著的特点就是支持eventtime语义。这是spark streaming不支持的。通过阅读《Streaming System》,其中确实也谈到了实时计算涉及到窗口统计的时候如何解决。通过方法论以及flink的相关源码,可以在我们自研的这套实时计算系统中用上eventtime。
首先是对数据中必须约定一个时间字段。例如我们就约定的字段名为"eventtime",内容为13位时间戳。当数据到来时,需要更新全局的watermark,然后需要根据窗口大小给数据分配对应的窗口。如何判断窗口是否结束了呢?也是通过watermark,当watermark超过窗口的结束时间,则窗口需要触发计算。
可以参考flink中WindowAssigner和Trigger相关代码。
分配窗口可以直接copy flink的代码
图五 代码演示
使用eventTime是无法实现准确的计算的。势必有些数据会存在丢失。但是如果使用processingTime,当服务重启进行追数据的时候,统计值会十分不准确,产生告警。我认为使用eventTime还是十分理所应当的。
优化
1. 在每个map阶段完成(也就是compute服务)时,可以进行map端聚合,俗称combiner
2. 进行uv类指标计算时,使用redis hyperloglog
clickhouse
信安有很多业务在使用clickhouse,其特点是可以对明细数据进行灵活高效的查询。对于该系统,由于都是计算好的统计值,且为了出监控图标,我这边在ck中存储的模型如下:
图六 数据存储模型
类似于hbase,value是汇总的结果。clickhouse有强大的聚合函数。当需要看一段时间的折线图时,直接进行如下的sql查询:
符合计算向数据移动的原则,ck产生的结果几户可以直接给前端做展示。
预警机制
实时计算服务每个指标计算完成后都会跟预警服务通信,则预警服务作为被动方接受数据即可。等待数据到来,根据告警配置进行逻辑判断。
连续N次进行预警
该实现方案实现逻辑为,针对每个指标在redis中维护一个hash结构,hash中有一个key记录着连续的次数,一个key记录着上次触发的时间。每当有新数据到来时和redis中的状态进行比较,若此次时间-上次触发的时间=时间窗口,则累加状态中的连续次数。否则对状态进行初始化。
在N分钟内达到M次进行预警
该类告警逻辑的实现为:在redis中利用zset存时间序列,当数据到来时先插入zset,在对zset进行N分钟的回溯,看是否有M个以上的元素即进行告警。利用zcount api即可。
失效预警
在信安风控场景中,策略命中量是一个重点关注的监控指标,当一个重要策略在一段时间内没有命中时,则是需要引起高度关注的。失效预警就是针对这类问题的。逻辑为监测某一个指标在过去N分钟内是否均为0。
由于没有数据,实时计算服务是不会调用预警服务的。此类告警逻辑的实现需要组织逻辑去查询clickhouse,若结果集为空,则需要触发告警。
目前业界已有阈值设置方式
在创建某些警报以监控数据的异常时,通常需要设置一些阈值来判断当前数据是否存在异常,当数据大于阈值或者小于阈值时判定为异常,发出预警并通知相关人员进行及时处理。所以如何设置一个合理的阈值,成为预警系统良好运行的关键环节。目前阈值的设置一般分为两类,一类是人工设置静态阈值,另一类是通过特定的算法生成动态阈值。
静态阈值
由于静态阈值配置简单,大量预警系统中都使用该种方式来进行异常判定。该种方式主要有配置便捷,资源开销小,开发流程短,开箱即用等优势,但同时其不足之处也很多,大的缺点是需要人工先验知识配置,同时无法适应长期的数据变化以至于需要单独的数据专家去长期的维护,造成人力成本高,报警准确率低,不及时等问题。为了解决这一问题,一部分预警系统转而使用动态阈值的方式去解决该问题。
动态阈值
针对静态阈值难以设置特定阈值或范围限制,动态阈值根据当前监控的历史数据以及当前数据,可以自动计算监控阈值,无需人工的过多干预。该种方式利用数据的变化趋势与规律去计算所需阈值,大幅度降低了人力成本,并且在预警效果上有了极大地提升。为此,我们采用动态阈值的方式来设计了智能预警系统。
fbprophet算法介绍
在实际风控业务中,监控数据存在以下五个特点:
1. 监控指标数量大
2. 监控数据点较少
3. 监控数据周期不一致
4. 突变数据多
5. 监控数据非线性
为了保证数据的拟合预测效果,本系统使用了Facebook开源的时序预测算法fbprophet。该算法使用少量数据就可以预测未来数据,拟合效果较好,同时可以提供预测数据的上下限用作报警阈值。
fbprophet算法模型主要由四部分构成,如图一,分别是趋势项、季节项、节假日项和误差项构成。
图七 fbprophet算法模型结构
拟合公式:
可以看出这是一种类似于generalized additive model(GAM)的模型,与以往的时间序列预测模型(例如ARIMA),这种模型将预测问题转变为曲线拟合问题。这种方式有以下几个优点:
1. 灵活度较高,不同的周期和趋势都能引入到模型中;
2. 在整个时间序列中,不需要提前设置固定周期,对缺失值有一定的容忍度;
3. 由于是曲线拟合问题,所以拟合速度非常快;
4. 整个模型中的所有特征参数都具有实际意义,便于理解与调整。
动态阈值应用效果及优化
由于fbprophet算法模型终会输出三个值:预测值、预测上限和预测下限,其中的预测上下限即可作为我们的报警阈值来使用。
在实际使用中,该模型拟合效果较好,数据统计时间窗口越长,拟合越稳定。下图是在58某业务场景中的一段预测曲线:
图八 58某业务时间序列曲线
该图中,红色曲线为预测数据线,红色线覆盖的黑色线为真实数据线,上面和下面的分别为上限数据线和下限数据线。从图中可以看出,fbprophet算法可以较好的拟合该业务的数据,能够捕捉数据的周期与趋势。图中圆圈标注为异常值,其真实值大于预测值从而发出报警。
由于不同的业务存在数据和使用要求的差异,我们为预警阈值的报警区间增加了个性化设置功能,可以按比例调节上下限的数值。对于稳定的数据,可以减小报警区间以增加其报警灵敏度;对于波动较大的数据,可以增大报警区间,提高报警的准确度。
总结与展望
李文学:2017年3月加入58, 数据开发工程师, 目前担任信息安全部数据方向负责人,专注于大数据应用架构。
霍光耀:58同城信息安全部数据开发工程师,2020年加入58同城,主要负责风控场景下实时计算架构,数据应用等工作。
庄伟:58同城信息安全部算法开发工程师,2019年加入58同城,主要负责业务风控算法设计与开发等工作。