当前位置: 首页 > 后端技术 > Java

风控系统就应该这样设计,通用,稳定!(推荐收藏)

时间:2023-04-01 13:18:55 Java

作者:wingli\链接:https://juejin.cn/post/7182774381448282172一、背景1、为什么要做风控?这还不是产品老大的恩赐。目前我们的业务使用了很多AI能力,比如ocr识别,语音评价等,这些能力往往是昂贵的或者是资源密集型的,所以在产品层面,我们也希望能够限制使用次数用户可以使用能力,风控必不可少!2、为什么要自己写风控?这么多开源风控组件,为什么要写?你想重新发明轮子吗?要回答这个问题,需要先解释一下风控(简称业务风控)和普通开源风控(简称普通风控)有什么区别:风控类型目的对象规则业务风控实现了一些产品定义的限制,达到限制后,有具体的业务流程,比如充值vip比较复杂多变,比如对用户的风控,对用户+等级的风控。自然日、自然时间等常用风控保护服务或数据,拦截异常请求等接口,部分可添加简单参数。滑动窗口的使用频率更高。因此,直接使用开源的通用风控一般无法满足需求。3.其他要求支持实时调整限额:很多限额值在第一次设置的时候基本就确定了。的值,后续调整的可能性比较大,所以需要能够实时调整生效。2.思路实现一个简单的业务风控组件,需要做哪些工作?1、风险控制规则的实现需要执行的规则:自然日计自然时计自然日+自然时计自然日+自然时计这里不能简单的把两个判断连起来,因为如果自然日判断通过,但是自然时判断不通过pass需要回滚的时候,自然天数和自然小时数都不能包含在这个调用中!b.统计方式的选择:目前有:mysql+db事务持久化,可追溯记录,实现起来比较麻烦。稍“重”的redis+lua实现起来比较容易,redis的可执行lua脚本也能满足“事务”的要求。mysql/redis+分布式事务需要加锁,实现起来比较复杂,可以实现更准确的计数。也就是说,代码块执行成功后,目前对计数操作没有精确的技术要求,成本太高,也没有持久化的必要,所以选择redis+lua。2.调用方法的实现a.Common方法先定义一个common入口,推荐一个开源免费的SpringBoot最全教程:https://github.com/javastacks/spring-boot-best-practice//简化代码@ComponentclassDetectManager{funmatchExceptionally(eventId:String,content:String){//调用规则匹配valrt=ruleService.match(eventId,content)if(!rt){throwBaseException(ErrorCode.OPERATION_TOO_FREQUENT)}}}在服务中调用此方法//简化代码@ServiceclassOcrServiceImpl:OcrService{@AutowiredprivatelateinitvardetectManager:DetectManager/***提交ocr任务*需要根据用户id号进行oftimelimit*/overridefunsubmitOcrTask(userId:String,imageUrl:String):String{detectManager.matchExceptionally("ocr",userId)//doocr}}有更优雅的方式吗?使用注解可能会更好一点(也是有争议的,其实这里先支持实现)由于传入的内容与业务相关,所以需要用Spel将参数形成对应的内容.三、具体实施情况1、风险控制计数规则的实施情况a.NaturalDay/naturalhourNaturalday/naturalhour可以共享一套lua脚本,因为它们只是key不同而已。脚本如下://luascriptlocalcurrentValue=redis.call('get',KEYS[1]);ifcurrentValue~=falsetheniftonumber(currentValue)"arg${index+1}"toany}.toMap()//构建上文valcontext=StandardEvaluationContext().apply{if(argMap.isNotEmpty())this.setVariables(argMap)}//获取结果valcontent=expression.getValue(context)detectManager.matchExceptionally(detect.eventId,content)returnjoinPoint.proceed()}}需要将参数放入context中,命名为arg1,arg2。...4。测试一下1.使用注解后的写法://简化代码@ServiceclassOcrServiceImpl:OcrService{@AutowiredprivatelateinitvardetectManager:DetectManager/***提交ocr任务*需要根据用户id限制次数*/@Detect(eventId="ocr",contentSpel="#arg1")overridefunsubmitOcrTask(userId:String,imageUrl:String):String{//做ocr}}2.调试看注释值获取成功表达式parsingSuccess近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.精彩!Java协程来了。.3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!