項目地址
代碼已開源, https://github.com/sunpeak/riskcontrol
背景
當前互聯(lián)網(wǎng)企業(yè)存在很多業(yè)務風險,有些風險(比如薅羊毛)雖然沒有sql注入漏洞利用來的直接,但是一直被羊毛黨、刷單黨光顧的企業(yè)長期生存下來的幾率會很低!
賬號:垃圾注冊、撞庫、盜號等
交易:盜刷、惡意占用資源、篡改交易金額等
活動:薅羊毛
短信:短信轟炸
項目介紹
實時業(yè)務風控系統(tǒng)是分析風險事件,根據(jù)場景動態(tài)調(diào)整規(guī)則,實現(xiàn)自動精準預警風險的系統(tǒng)。
本項目只提供實時風控系統(tǒng)框架基礎(chǔ)和代碼模板。
需要解決的問題
哪些是風險事件,注冊、登錄、交易、活動等事件,需要業(yè)務埋點配合提供實時數(shù)據(jù)接入
什么樣的事件是有風險的,風險分析需要用到統(tǒng)計學,對異常用戶的歷史數(shù)據(jù)做統(tǒng)計分析,找出異于正常用戶的特征
實時性,風險事件的分析必須毫秒級響應,有些場景下需要盡快攔截,能夠給用戶止損挽回損失
低誤報,這需要人工風控經(jīng)驗,對各種場景風險閾值和評分的設置,需要長期不斷的調(diào)整,所以靈活的規(guī)則引擎是很重要的
支持對歷史數(shù)據(jù)的回溯,能夠發(fā)現(xiàn)以前的風險,或許能夠找到一些特征供參考
項目標簽
輕量級,可擴展,高性能的Java實時業(yè)務風控系統(tǒng)
基于Spring boot構(gòu)建,配置文件能少則少
使用drools規(guī)則引擎管理風控規(guī)則,原則上可以動態(tài)配置規(guī)則
使用redis、mongodb做風控計算和事件儲存,歷史事件支持水平擴展
原理
統(tǒng)計學
次數(shù)統(tǒng)計,比如1分鐘內(nèi)某賬號的登錄次數(shù),可以用來分析盜號等
頻數(shù)統(tǒng)計,比如1小時內(nèi)某ip上出現(xiàn)的賬號,可以用來分析黃牛黨等
最大統(tǒng)計,比如用戶交易金額比歷史交易都大,可能有風險
最近統(tǒng)計,比如最近一次交易才過數(shù)秒,可能機器下單
行為習慣,比如用戶常用登錄地址,用戶經(jīng)常登錄時間段,可以用來分析盜號等
通用公式:某時間段,在條件維度(可以是多個維度復合)下,利用統(tǒng)計方法統(tǒng)計結(jié)果維度的值,充分發(fā)揮你的想象吧!
實時計算
要將任意維度的歷史數(shù)據(jù)(可能半年或更久)實時統(tǒng)計出結(jié)果,需要將數(shù)據(jù)提前安裝特殊結(jié)果準備好(由于事件的維度數(shù)量不固定的,選取統(tǒng)計的維度也是隨意的,所以不是在關(guān)系數(shù)據(jù)庫中建幾個索引就能搞定的),需要利用空間換時間,來降低時間復雜度。
redis
redis中數(shù)據(jù)結(jié)構(gòu)sortedset,是個有序的集合,集合中只會出現(xiàn)最新的唯一的值。利用sortedset的天然優(yōu)勢,做頻數(shù)統(tǒng)計非常有利。
比如1小時內(nèi)某ip上出現(xiàn)的賬號數(shù)量統(tǒng)計:
-
保存維度
ZADD key score member(時間復雜度:O(M*log(N)), N 是有序集的基數(shù), M 為成功添加的新成員的數(shù)量),key=ip,score=時間(比如20160807121314),member=賬號。存儲時略耗性能。
結(jié)構(gòu)如下:
1.1.1.1
|--賬號1 20160807121314
|--賬號2 20160807121315
|--賬號n 20160807121316
2.2.2.2
|--賬號3 20160807121314
|--賬號4 20160807121315
|--賬號m 20160807121316
-
計算頻數(shù)
ZCOUNT key min max(時間復雜度:O(1)),key=ip,min=起始時間,max=截止時間。計算的性能消耗極少,優(yōu)勢明顯
-
redis lua
把保存維度,計算頻數(shù),過期維度數(shù)據(jù)等操作,使用lua腳本結(jié)合在一起,可以減少網(wǎng)絡IO,提供性能
mongodb
mongodb本身的聚合函數(shù)統(tǒng)計維度,支持很多比如:max,min,sum,avg,first,last,標準差,采樣標準差,復雜的統(tǒng)計方法可以在基礎(chǔ)聚合函數(shù)上建立,比如行為習慣:
getDB().getCollection(collectionName).aggregate(
Arrays.asList(
match(match) --匹配條件維度
, group("$" + field, Accumulators.sum("_count", 1)) --求值維度的次數(shù)
, match(new Document("_count", new Document("$gte", minCount))) --過濾,超過minCount才統(tǒng)計
, sort(new Document("_count", -1)) --對次數(shù)進行倒敘排列
)
);
建議在mongodb聚合的維度上建立索引,這樣可以使用內(nèi)存計算,速度較快。
redis性能優(yōu)于mongodb,所以使用場景較多的頻數(shù)計算默認在redis中運行,參考代碼DimensionService.distinctCountWithRedis方法。但是redis為了性能犧牲了很多空間,數(shù)據(jù)重復存儲,會占用很多內(nèi)存。
環(huán)境準備
mysql,數(shù)據(jù)結(jié)構(gòu)在import.sql中定義了
redis
mongodb,建議使用分片集群
項目配置
應用配置:application.properties
日志配置:logback.xml
規(guī)則配置:rules/*.drl,規(guī)則都是用java語言編寫。默認配置了登錄事件的部分規(guī)則
單個規(guī)則文件說明:
package rules; --規(guī)則包路徑
import com.example.riskcontrol.model.LoginEvent --引入類
import com.example.riskcontrol.service.DimensionService
import com.example.riskcontrol.model.EnumTimePeriod
global DimensionService dimensionService --引入外部服務
rule "98_login_ip" --規(guī)則名稱,全局唯一
salience 98 --規(guī)則優(yōu)先級,值越大越先執(zhí)行
lock-on-active true --事件不重復執(zhí)行該規(guī)則
when --條件判斷,是否需要進入action
event:LoginEvent() --判斷事件對象是否是LoginEvent類
then --action
int count = dimensionService.distinctCount(event,new String[]{LoginEvent.OPERATEIP},EnumTimePeriod.LASTHOUR,LoginEvent.MOBILE); --近1小時內(nèi)該事件ip上出現(xiàn)的mobile數(shù)量統(tǒng)計
if(event.addScore(count,20,10,1)){ --如果統(tǒng)計結(jié)果超過20個,則記10分,并且結(jié)果每超1個,再多記1分
dimensionService.insertRiskEvent(event,"近1小時內(nèi)同ip出現(xiàn)多個mobile,count="+count); --記錄風險事件日志
}
end --結(jié)束規(guī)則
drools的詳細文檔,請參考官方http://docs.jboss.org/drools/release/6.4.0.Final/drools-docs/html_single/index.html
部署
系統(tǒng)默認采用jar打包和運行,建議集群方式部署,然后使用反向代理做負載均衡。
打包
mvn clean install
運行
建議jdk 8
java -jar riskcontrol-*.jar
war包部署
如果需要tomcat等容器部署,也可將配置打包方式修改成war包方式,修改pom.xml
<packaging>war</packaging>
風控分析入口
請求:http://domain/riskcontrol/req?json=JSON.toJsonString(LoginEvent)
響應:score字段代碼該事件的風險值(超過100分預警)
TODO
擴展黑白名單,ip,手機號,設備指紋等;
擴展維度信息,比如手機號地域運營商,ip地域運營商,ip出口類型,設備指紋,Referer,ua,密碼hash,征信等,維度越多,可以建立規(guī)則越多,風控越精準;
擴展風控規(guī)則,針對需要解決的場景問題,添加特定規(guī)則,分值也應根據(jù)自身場景來調(diào)整。
將用戶的行為軌跡綜合考慮,建立復合場景的規(guī)則條件。比如:登錄->活動->訂單->支付,將事件關(guān)聯(lián)分析綜合考慮;
減少漏報和誤報。當然,這將是個漫長的過程;