需求:
开发一个风控系统,系统包括, 规则引擎和计算引擎, 主要的内容如下:
1. 规则的增删改和实时生效, 规则的分类执行
2. 按照一定的纬度计算累计值,比如按照 IP, 用户 id, 账户 等纬度。
3. 需要支持滑动窗口,滚动窗口,长度窗口等
遇到的问题主要有以下几点:
1. redis 做流计算太过勉强,一是根据业务上的需求,需要统计的key 至少有几亿个,最多也有几十亿个,另外redis 中需要存储少量的交易的信息。估算下来量也是非常可观
2. redis 中 hot key 特别明显,比如按照商户的纬度去统计,如果不对商户的key 进行拆封,像盒马那种流量的商户,对redis 的压力是非常大的。
我们采用的是redis 的cluster 模式,这样的话redis hot key 对redis 影响会更大。对其进行拆分是非常必要的,比如 按照小时拆分。
3. 流式计算中,一个是乱序导致累加的计算不准确(有负值),另外一个是消息延迟. 当时我们尝试使用flink 中的水印的概念去解决问题,发现并不适合。这个坑也是我们实践过后才发现的。
最痛苦的经历是乱序和延迟消息的解决,现在是采取纠正的方式解决。
规则引擎
规则引擎我们选用了drools,简单的探索了drools core, drools DRL, drools CEP 等,但是回头看看,针对drools的使用缺点还是很多, 而且很明显,暂时还没有替换的打算.
1. 使用 drools CEP 如何做分布式? 我们发现drools CEP中的几种窗口都是内存计算的,应用到分布式中就没有很好的办法,几乎做不到,除非drools 也去集成redis等这种分布式缓存。
2. 使用drools 觉得很笨重,因为依赖比较多,二是我们只用到了 drools 中的 if else 等判断,许多其它的功能基本就用不到,因为 1 中解决不了分布式的问题。所以从这点来说drools 已经废了,根本不用在创建kiesession 这种 重量级的东西。
3. drools中支持的运算符不是特别充分,比如像 log 运算,sum, max, avg 这种的运算等都是不支持的. DRL 语言对业务人员来说不是非常的友好。
4. 另外drools 中的 连续,非连续的规则,没有看出来如何配置,至少flink cep 是有这样API的。
综上所描述,不得不吐槽下 drools真是无语,也许了解的很简单,还有别的方式,另外drools workbench 也是很无语,很复杂,估计drools 厂商想通过这种方式挣钱。
总体感觉,如果有别的选择,最好不要选用drools,分布式的问题没有解决,就等于废了,因为各种分布式窗口都需要我们自己去实现。怎么办呢?
规则引擎最后还是采用了drools,根据具体的业务含义创建不同的kiesession, drools 起到了if else 判断的作用,至于滚动窗口,长度窗口和滑动窗口都通过redis来做计算。遇到头疼的问题,是
1. 根据不同的统计纬度,大概计算了下,需要几十亿个key,在redis 中做计算
2. 滑动窗口暂时靠 redis的zsort 的数据结构,性能不是非常好
3. 热点key 的问题,特别对于大商户的热点key 的问题,需要做拆分,拆分起来是比较复杂的
4. 消息延迟和消息乱序问题。
所以计算引擎的需求一般是
1. 计算很快,大几百个规则,能够很快的计算出准确的结果来
2. 计算准确率,当面对乱序和延迟消息的时候,如何计算的更加准确
3. 计算的量的问题,正如前面提到的,几十亿个key,另外还需要存储一些信息,计算的中间状态等,如何在redis 中丢失,就会造成计算不准确。
基于以上的问题,关键是如何做的更好,优化的更好,说实话,我没有找到答案,可以做的就是不断的优化redis 计算(暂时不能上大数据,比如flink, spark 等),减少redis 的操作带来的网络开销。
其实最后还要提一下,如果能采用内存计算,不用分布式计算,会不会速度更快点,比如根据业务来做分片,这样在各个实例统计的中间值就不用汇总,那么每个实例只需要内存计算就好,不需要访问redis而带来的网络开销。但是这样做也会带来架构层面的调整,比如 如何做 fault tolerance, 如何做 状态持久化, 等一系列的问题。
从使用redis结果来看,效果也不是那么差,不考虑非常热点key 的情况下,最高tps 也达到6000多(2 台机器,16core,32G 内存), 一般公司的业务其实是可以满足的,对于非常热点的key,后续的优化是继续拆分.
一个好的风控系统是非常难的,做以笔记,以希望不断成长