金融監控實踐

前言

從電商轉金融 2 年多了,由於兩者商業模式,流量的不同,期間踩了很多坑,尤其是在監控這一塊,我們喫過不少苦頭,前期由於監控缺失,造成了多起線上事故,經過一番摸索,我們實現了一些相對可行的監控方法,有效地保證了大盤及業務的穩定,在此總結出來分享給大家,希望能爲大家提供一些金融場景下的監控思路,如果大家如有更好的思路,也歡迎共同探討。

本文主要從以下幾個方面來闡述:

  1. 電商場景下的常用監控方式

  2. 金融監控的難點

  3. 金融場景下監控的幾種可靠手段

電商場景下的常用監控方式

電商場景下的監控主要有兩種,一種是流量監控(接口請求),一種是關鍵節點(如註冊,下單)的監控

對於這兩者監控來說,我們常用的手法就是打點,接口每請求一次或關鍵節點每生成一次打個點,這樣我們就可以通過比較今天和昨天的打點數據來監控,以下爲我們針對某一關鍵事件的打點數據

如圖示:綠色代表今天打點數據,黃色代表昨天

有了昨天和今天的打點數據我們要做監控就很簡單了,可以對比同一時間段兩者的打點數據,如果今天的打點數據相對於昨天下跌超過比如 50%,那麼這個關鍵節點的路徑可能是有問題的,就可以觸發告警,如下圖示

這兩種監控之所以在電商場景下可行主要有兩個原因:

一是因爲電商場景下的流量比較大,流量大,那麼每分鐘的打點數據就比較大, 這樣通過下跌百分比來觸發告警誤差相對較小,所以可行,另外流量大所以意味着有任何的風吹草動,比如因爲頁面不可用造成的投訴短時間內會暴增,或打點數據短時間的急劇下降,都能在較短的時候內提早預警,讓我們及時發現問題所在。

二是因爲電商下的關鍵節點相對比較少,主要無非就是「添加購物車」與「下單」等關鍵節點,關鍵節點少意味着只要關鍵節點出了問題了,通過上文所述的下跌百分比告警排查關鍵節點的路徑是否出問題即可,由於關鍵節點少,整個需要關注的核心鏈路相對比較短,所以排查起來相對比較容易一些。

金融監控的難點

上節介紹的電商場景下的兩種方案在金融場景上都不適用,原因主要是因爲金融是一個低頻操作,且電商場景下的日活通常能達到幾十上百萬,但金融場景下的日活要少個幾十倍,這就意味着每個關鍵節點的打點每小時可能只有幾十不到,可能在長達幾十分鐘內關鍵節點對應的打點都爲 0,所以也就無法用這種下跌百分比的形式進行告警。爲了更好地向大家介紹金融業務監控的痛點,還是先簡單介紹一下金融業務。

金融業務簡介

目前我們主要從事的是現金貸業務,屬於助貸業務,所謂助貸,即平臺方並不直接發放貸款,只是平臺方利用自身的獲客,貸後管理等優勢爲借款人撮合匹配資金方,以實現資金的融通,平臺方收取相當的手續費。主要業務流程如下

我們平臺會爲每一個用戶挑選其中與之匹配的資金方進行授信,這些資金方的風控策略不同,所以授信通過率,借款通過率這些核心指標自然有較大的差異,像一些頭部資金方如馬上消金或 360 借錢等通過率比較高,我們會給予更多的流量,而一些不太知名的資金方這些關鍵指標表現不太如人意,給之分配的流量自然較少。

爲每一個用戶匹配申請資金方後,通常都要經歷以下週期:

  1. 貸前:授信環節,資金方要給你額度,你總要提供身份證以及相關的學歷等個人信息吧,這樣資金方通過這些信息就可以評估你的信用,決定是否給你額度

  2. 貸中:即借款環節,授信通過之後,用戶就可以借款了

  3. 貸後:即還款環節

可以看到對於每一步,尤其是貸前和貸中,核心流程的關鍵節點都非常多,關鍵節點多就意味着漏斗大,用戶的轉化就越低,關鍵節點的打點(如提交授信,提交借款)可能一天只有幾千,平均到每分鐘也就幾次甚至沒有,而且由於金融本身是個非常低頻的操作,用戶的行爲具有很大的不確定性,可能今天 8~9 點提交授信人數有 50,但第二天 8~9 點提交授信人數又降到個位數了,這些在電商裏肯定會觸發告警的現象在金融裏卻再正常不過,所以初期常常出現這樣一種現象:我們在監控圖表上發現兩天同一時間段某些資金方關鍵節點的打點(如提交授信,放款成功單數)相差巨大,但排查後發現鏈路卻沒有問題,搞得我們焦頭爛額。

通過以上簡介,相信大家不難理解電商場景下的監控不能照搬到金融場景中,我們必須要結合金融場景低頻的特點來設計一套相應的監控體系。

金融場景下監控的幾種可靠手段

1、針對每個資金方每個流程(貸前貸中貸後)成功數或成功率進行監控

針對以上所述金融低頻的特點,我們設計了一套相對有效的監控系統,思路如下:雖然貸前,貸中,貸後每個流程的關鍵節點都很多,但其實我們沒必要對所有的關鍵節點都進行監控,我們只需要對每個資金方的關鍵流程的成功結果(授信成功,借款成功,授信通過率,借款通過率)進行打點監控,因爲如果授信或借款成功了,說明貸前和貸中的流程都沒有問題了

注意我們需要分別對每個資金方的授信成功和借款成功都進行打點監控,因爲統計總數成功沒有意義,每個資金的風控策略和流量分配是不一樣的,以成功總數來判斷流程是否正常很可能導致一些資金方某天風控策略調整(或其他 bug)導致授信或借款全部失敗而未被發現。

當然上文也說了,每個資金方授信成功或借款成功的總數很可能在幾十分鐘內都爲 0,那我們可以以小時的成功總數來告警。我們記錄下每天每小時的成功總數,每半小時比較今天和過去一週同一時間段(平均值)近 X 小時內的成功數,如果低於過去一週平均成功數的一半,說明可能鏈路出問題了,就告警,這個 X 怎麼選擇呢,如果最近一小時成功總數小於 20(這個閾值需要根據實際情況選取),那我們就選今天和過去一週同一時間段最近兩小時的成功總數進行比較,如果還是小於 20 ,那就選最近三小時的成功總數進行比較。。。,直到最近 X 小時的成功總數達到 20,這樣誤差就比較小了,通過這種方式的告警有效率目前爲止 100%! 也發現了線上多起問題,釘釘告警展示如下:

優質資金方由於通過率高,分配的流量大,所以對應的每小時的成功數相對來說比較多,用這種與過去一週同一時間段平均值比較的方式來進行告警確實可行,但對於那些通過率較差的資金方呢,這些資金方可能一天總共纔有幾個成功數,用上面的告警方式誤差較大,那我們就拉長一下時間線,統計近 8 個小時此資金方的成功數,如果爲 0 ,說明可能有問題:

通過這種方式我們也發現了多起因爲資金方風控調整導致授信/放款成功數降低導致的問題,及時通知資金方解決了問題。

2、巧用切面及時發現解決資金方異常

迄今爲止,我們總共接入了二十幾家資金方,每個資金方都有自己的一套接口規範,每個資金方的接口都不一樣,總共可能接入了幾百上千個接口,這就帶來了一些隱患,如果由於我們代碼的 bug 或資金方內部問題導致接口請求失敗(通常是接口返回的狀態碼爲失敗的狀態碼),我們很難發現,有人說這不簡單嗎,如果接口返回的是失敗的狀態碼,針對此時的請求錯誤告警不就行了。

這裏有兩個問題:

一是這種告警代碼應該寫在哪裏,有人說就寫在每個資金方的請求底層啊,如果是這樣的話,監控代碼與業務代碼緊藕合,而且我們接入了二十幾家資金方,每一家的底層請求對應的文件裏都要一個個的寫告警代碼,工作量巨大,且之後如果新接資金方很容易忘記把告警代碼給加上。

二是並不是所有返回失敗狀態碼的接口我們都要告警,有些是正常的請求失敗,如「賬戶永久凍結」,「放款日當天不允許還款」,這些失敗的請求並不是 bug 導致的失敗,所以我們並不關心,就算給我們告警也沒有意義,我們只對「姓名不能爲空」這種會明顯是 bug 導致的請求失敗感興趣,我們需要過濾過正常失敗的告警。

先看第一個問題,每個資金方的底層接口請求僞代碼如下

// 接口調用
String result = httpPost();
Response response = JSON.parseObject(result, Response.class);
// 如果請求的狀態碼是失敗的狀態碼 
if (!response.getCode().equals(SUCCESS_CODE)) {
    // 拋出異常,異常裏帶有爲資金方返回的失敗信息
    throw new Exception(ErrorCodeEnum.ERROR_REQUEST_EXCEPTION, response.getMessage());
}

很顯然如果能用切面攔截所有這些資金方拋出的異常,那我們就能把針對這些異常的告警統一寫在切面裏,不會對現有代碼有任何入侵,且方便統一管理所有資金方的告警,也就完美解決了問題一。

切面實現的僞代碼如下:


@Aspect
public class LoggingAspect {
    //只捕獲所有資金方請求文件所在的包
    @AfterThrowing ("execution(* com.howtodoinjava.app.service.impl.*(..))", throwing = "ex")
    public void logAfterThrowingAllMethods(CustomException ex) throws Throwable {
           //發送拋出的錯誤信息至釘釘告警
           sendDingWarning(ex.getMessage()); 
      }
}

再來看第二個問題,如何過濾過我們不關心的正常失敗請求拋出的異常呢。思路也很簡單,設置一個白名單機制,如果我們發現失敗的請求是正常的失敗,把這個失敗的信息加入白名單裏即可,這樣如果某個資金方請求失敗拋出異常了,我們只要看一下這個這個失敗信息是否在白名單裏即可,如果在,說明是正常的失敗,不需要觸發告警,如果不在白名單裏,則觸發告警。經過改造, 我們的告警流程變成了如下這樣:

這裏有一個小問題需要注意一下,這個白名單該怎麼配置呢,一開始我們並不知道哪些失敗的請求是正常的失敗請求,所以一開始只能把所有失敗的請求都告警,每發現一個正常的失敗請求,就把此失敗信息加到白名單裏,所以這個白名單是不斷動態變化的,而且也是需要實時生效的,我們選擇了 360 開源的 QConf 來配置我們的白名單。

QConf 是一種基於 Zookeeper 的分佈式管理服務,致力於將配置內容從代碼中完全分離出來,及時可靠高效地提供配置訪問和更新服務,使用 QConf 進行配置後,白名單的管理問題也解決了。

3、針對資金方實現熔斷降級

在我們的業務場景中,一個用戶請求很可能會請求多個資金方的接口,如果某個資金方的服務出現問題,依賴於這個資金方接口的用戶請求也就掛了,實際上在我們的業務場景中幾乎每個請求都要請求資金方的接口,這也意味着只要某個資金方的服務不可用,我們業務也就不可用了,顯然這是不能接受的。

如圖示:某次用戶請求要請求多個資金方,如果資金方 B 的接口服務掛了,很可能導致此次用戶請求也掛!甚至導致整個業務不可用!

所以我們必須引入熔斷降級機制,當某個資金方服務出現異常時(如調用超時或其他異常比例升高),接下來的降級時間窗口內,對該資源的調用都自動熔斷,快速失敗,這樣就避免了業務不可用的巨大隱患。

我們使用阿里的 Sentinel 來實現熔斷降級,Sentinel 提供了幾種方式來實現熔斷,我們使用了 1 分鐘內異常數超過閾值後進行熔斷的這種方式,一旦觸發了熔斷,請求資金方接口就會拋出「DegradeException」,同樣的也是在切面中捕獲此異常,然後告警。

總結

本文總結分享了在金融這種低頻業務場景下設計監控的幾種方式,通過以上幾種方式基本保證了大盤的穩定,不過其實第一種監控(針對成功數,成功率)如果換成機器學習中的行爲預測效率應該會更高,也會更及時一些,不過團隊裏面沒有這方面經驗的人才,所以暫時用針對成功數/成功率的監控來替代,後續如果有機會引入機器學習的嘗試,相信會有不錯的效果。如果你有更好的監控方法可以分享,歡迎提出哦。

文章的最後分享一位優秀的知識創造者,樂於分享者的公衆號,建議大家關注一波,或許會有意想不到的收穫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章