詳解:知乎反作弊系統「悟空」架構演進!

趙鈺瑩發表於2018-07-12

Hi there! 距離 2015 年 4 月「悟空」正式與大家見面,已經整整三個年頭了。隨著知乎的不斷髮展壯大,過去的一段時間,「悟空」不斷面臨著新的考驗,並持續地在最佳化升級。接下來跟大家系統分享一下這幾年「悟空」的架構演進和構建過程中積累的經驗與教訓。


業務現狀


截止今年 5 月,知乎已擁有 1.6 億註冊使用者,近幾年在問答,專欄文章之外,社群衍生出了一些新的產品線和產品形態。因此「悟空」對接的業務形態也得到了擴充套件,從最初重點控制的內容類 Spam ,擴充套件到行為類 Spam,交易風險等等。目前「悟空」已經覆蓋了知乎 10 個業務線,近 100 個功能點。


總的來說,在知乎長期存在,且比較典型的 Spam 有這麼幾類:

  • 內容作弊 Spam:這類 Spam 的核心獲益點一方面是面向站內的傳播,另一方面,面向搜尋引擎,達到 SEO 的目的。內容類的 Spam 是社群內主流的 Spam 型別,目前主要包括四種形式:

    • 導流內容:這類 Spam 大概能佔到社群中 Spam 的 70% - 80%,比較典型的包括培訓機構, 美容,保險,代購相關的 Spam。導流內容會涉及到 QQ,手機號,微信,url 甚至座機,在一些特殊時間節點還會出現各類的專項 Spam,比如說世界盃,雙十一,雙十二,都是黑產大賺一筆的好時機。

    • 品牌內容:這類內容會具有比較典型的 SEO 特色,一般內容中不會有明顯的導流標識,作弊形式以一問一答的方式出現,比如提問中問什麼牌子怎麼樣?哪裡的培訓學校怎麼樣?然後在對應的回答裡面進行推薦。

    • 詐騙內容:一般以冒充名人,機構的方式出現,比如單車退款類 Spam,在內容中提供虛假的客服電話進行詐騙。

    • 騷擾內容:比如一些誘導類,調查類的批次內容, 非常嚴重影響知友體驗。


行為作弊 spam:主要包括刷贊,刷粉,刷感謝,刷分享,刷瀏覽等等,一方面為了達到養號的目的,躲過反作弊系統的檢測,另一方面透過刷量行為協助內容在站內的傳播。


治理經驗


治理上述問題的核心點在於如何敏捷、持續地發現和控制風險,並保證處理成本和收益動態平衡,從 Spam 的獲益點入手,進行立體防禦。所謂立體防禦,就是透過多種控制手段和多個控制環節增強發現和控制風險的能力。


三種控制方式


策略反作弊:在反作弊的初期,Spam 特徵比較簡單的時候,策略是簡單粗暴又有用的方式,能夠快速的解決問題,所以策略在反作弊解決方案裡是一個解決頭部問題的利器。

  • 產品反作弊:一方面透過改變產品形態來有效控制風險的發生,另一方面透過產品方案,對使用者和 Spammer 痛點趨於一致的需求進行疏導,有時候我們面對 Spam 問題,對於誤傷和準確會遇到一個瓶頸,發現很難去區分正常使用者和 Spammer,這種情況下反而透過產品方案,可能會有比較好的解決方案。

  • 模型反作弊:機器學習模型可以充分提高反作弊系統的泛化能力,降低策略定製的成本。模型應用需要酌情考慮加入人工稽核來保證效果,直接處理內容或使用者的模型演算法,要千萬注意模型的可解釋性。我們過去的使用經驗來說,初期一些無監督的聚類演算法能夠在比較短時間內達到較好的效果。而有監督的分類演算法,在時間上和人力上的耗費會更多,樣本的完整程度,特徵工程做的好壞,都會影響演算法的效果。

三個控制環節


事前:事前涉及到的幾個環節包括風險教育、業務決策參與、監控報警以及同步攔截。反作弊需要提升業務的風險意識,明確告知反作弊可以提供的服務;並在早期參與到業務決策,避免產品方案上出現比較大的風險;業務接入後,針對業務新增量、處理量、舉報量,誤傷量進行監控,便於及時發現風險;在策略層面,在事前需要針對頭部明顯的作弊行為進行頻率和資源黑名單的攔截,減輕事中檢測的壓力。

  • 事中:面向長尾曲線的中部,主要針對那些頻率較低,且規律沒有那麼明顯的作弊行為,針對不同嫌疑程度的行為與帳號,進行不同層級的處理,要麼送審,要麼限制行為,要麼對內容和帳號進行處罰。

  • 事後:面向長尾曲線最尾部的行為,即那些非常低頻,或者影響沒那麼大,但是計算量相對大的作弊行為。由一些離線的演算法模型和策略負責檢測與控制,另外事後部分還涉及到策略的效果跟蹤和規則的最佳化,結合使用者反饋與舉報,形成一個檢測閉環。

悟空V1


初期 「悟空」主要由事前模組和事中模組構成。


事前模組與業務序列執行,適用於做一些耗時短的頻率檢測,關鍵詞和黑白名單攔截。由於是同步介面,為了儘量少的減少對業務的影響,大部分複雜的檢測邏輯由事中模組去處理。


事中模組在業務旁路進行檢測,適合做一些相對複雜,耗時長的檢測。事中主要由 Parser 和一系列 Checker 構成,Parser 負責將業務資料解析成固定格式落地到基礎事件庫,Checker 負責從基礎事件庫裡取最近一段時間的行為進行策略檢測。


事件接入


在反作弊的場景資料落地一般會涉及到這幾個維度:誰,在什麼時間,什麼環境,對誰,做了什麼事情。對應到具體的欄位的話就是誰 (UserID) 在什麼時間 (Created) 什麼環境 (UserAgent UserIP DeviceID Referer) 對誰 (AcceptID) 做了什麼事情 (ActionType ObjID Content)。有了這些資訊之後,策略便可以基於維度進行篩選,另外也可以獲取這些維度的擴充套件資料(e.g. 使用者的獲贊數)進行策略檢測。


策略引擎


「悟空」的策略引擎設計,充分考慮了策略的可擴充套件性。一方面支援橫向擴充套件,即支援從基礎維度獲取更多的業務資料作為擴充套件維度,例如使用者相關的資訊,裝置相關的資訊,IP 相關的資訊等等。另一方面縱向擴充套件也被考慮在內,支援了時間維度上的回溯,透過檢測最近一段時間內關聯維度 (e.g. 同一個使用者,同一個 IP) 上的行為,更高效地發現和打擊 Spam。


下面是一條典型的 V1 的策略:

這條策略主要實現了這樣的邏輯:


最近 10 分鐘在同一話題下建立的回答,與當前使用者,註冊時間在一小時之內,同一 IP 下注冊的使用者數大於等於 3 個。


基本上這樣的模式足夠滿足日常的 Spam 檢測需求,但是我們可以發現這種巢狀結構對於書寫與閱讀來說還是不太友好,這個部分的最佳化會在 V2 作詳細描述。

考慮到策略變更會遠大於基礎模組,在 V1 的架構中,我們特別將策略維護的邏輯單獨拆分成服務,一方面,可以實現平滑上下線,另一方面,減少策略變更對穩定性帶來的影響。


儲存選型


儲存上,我們選擇了 MongoDB 作為我們的基礎事件儲存,Redis 作為關鍵 RPC 的快取。選擇 MongoDB 的原因一方面是因為我們基礎事件庫的業務場景比較簡單,不需要事務的支援;另一方面,我們面對的是讀遠大於寫的場景,並且 90% 都是對最近一段時間熱資料的查詢,隨機讀寫較少, 這種場景下 MongoDB 非常適合。另外,初期由於需求不穩定,schema-free 也是 MongoDB 吸引我們的一個優點。由於我們策略檢測需要呼叫非常多的業務介面,對於一些介面實時性要求相對沒那麼高的特徵項,我們使用 Redis 作為函式快取,相對減少業務方的呼叫壓力。


悟空V2


「悟空 V1」已經滿足了日常的策略需求,但是在使用過程我們也發現了不少的痛點:


策略學習曲線陡峭, 書寫成本高:上面提到的策略採用巢狀結構,一方面對於產品運營的同學來說學習成本有點高,另一方面書寫過程中也非常容易出現括號缺失的錯誤。

  • 策略制定週期長:在「悟空 V1」上線一條策略的流程大概會經過這幾步, 產品制定策略 - 研發實現策略 - 研發上線策略召回 - 產品等待召回 - 產品確認策略效果 - 上線處理。整個環節涉及人力與環境複雜,策略驗證麻煩,耗時長,因此策略試錯的成本也會很高。

鑑於此,「悟空 V2」著重提升了策略自助配置和上線的體驗,下面是「悟空 V2」的架構圖:


策略結構最佳化


參考函式式語言,新的策略結構引入了類 spark 的運算元:filter, mapper, reducer, flatMap, groupBy 等等,一般基礎的策略需求透過前三者就能實現。


舉個例子,上面提到的策略在最佳化之後,會變成下面這種格式:



結構上變得更清晰了,可擴充套件性也更強了,工程上只需要實現可複用的運算元即可滿足日常策略需求,不管是機器學習模型還是業務相關的資料,都可以作為一個運算元進行使用。


策略自助配置


完成了策略結構的最佳化,下一步需要解決的,是策略上線流程研發和產品雙重角色交替的問題,「悟空 V2」支援了策略自助配置,將研發同學徹底從策略配置中解放出去,進一步提升了策略上線的效率。



策略上線流程最佳化


如何使策略上線變得更敏捷?這是我們一直在思考的問題。每一條上線的策略我們都需要在準確率和召回率之間權衡,在儘量高準確的情況下打擊儘量多的 Spam,因此每條要上線的策略都需要經過長時間的召回測試,這是一個非常耗時並且亟待最佳化的流程。「悟空 V2」策略上線的流程最佳化成了:建立策略 - 策略測試 - 策略試執行 - 策略上線處理 - 策略監控。


策略測試主要用於對策略進行初步的驗證,避免策略有明顯的語法錯誤。


策略試執行可以理解成快照重放,透過跑過去幾天的資料,快速驗證策略效果,一切都可以在分鐘級別完成。這部分的實現我們將策略執行依賴的資源複製了一份,與生產環境隔離,實現一個 coordinator 將歷史的事件從 MongoDB 讀出並打入佇列。值得注意的是,入隊速度需要控制,避免佇列被瞬間打爆。


透過試執行的驗證之後,策略就可以上線了。上線之後,策略監控模組提供了完善的指標,包括策略執行時間、策略錯誤數、策略命中及處理量等等,資料有所體現,方能所向披靡。


悟空V3


2016 年中旬,知乎主站各業務開始垂直拆分,相應的,「悟空」業務接入成本的簡化開始提上日程。


Gateway


Gateway 負責與 Nginx 互動,作為通用元件對線上流量進行風險的阻斷。目前 Gateway 承擔了所有反作弊和帳號安全使用者異常狀態攔截、反作弊功能攔截和反爬蟲攔截。這樣一來,這部分邏輯就從業務剝離了出來,尤其是在業務獨立拆分的情況下,可以大大減少業務的重複工作。作為通用元件,也可以提升攔截邏輯的穩定性。Gateway 當前的架構如下圖所示:



由於是序列元件,所有請求要求必須在 10ms 內完成,因此所有的狀態都快取在 Redis。Gateway 對外暴露 RPC 介面(Robot),相關服務呼叫 Robot 更新使用者,IP,裝置等相關的狀態到 Redis。 當使用者請求到達時,Nginx 請求 Gateway,Gateway 獲取請求中的 IP,使用者 ID等資訊, 查詢 Redis 返回給 Nginx。當返回異常狀態時 Nginx 會阻斷請求,返回錯誤碼給前端和客戶端。


TSP - Trust & Safety Platform



TSP 主要為反爬蟲和反作弊提供服務,一方面解析旁路映象流量,透過 Spark 完成流量清洗和基礎計數,再透過 Kafka 將計數資料打給反爬蟲策略引擎,進行檢測和處理,從而實現業務零成本接入。另一方面,由於反作弊依賴較多業務資料,難以從流量中獲取,故以 kafka 接入替代 RPC 接入,實現與業務進一步解耦,減少對業務的影響。


隨著「悟空」策略上線效率的提升,線上的策略逐漸增多,我們開始著手最佳化「悟空」的檢測效能與檢測能力。


策略充分並行化


「悟空 V2」策略檢測以行為為單位分發,帶來的問題是策略增多之後,單行為檢測時長會大大增強。在 V3 我們最佳化了這部分邏輯,將策略檢測分發縮小到以策略為粒度,進一步提升策略執行的並行度,並實現了業務級別的容器隔離。最佳化後,事中檢測模組演化成了三級佇列的架構。第一級是事件佇列,下游的策略分發 worker 將資料落地,並按照事件的業務型別進行策略分發。策略執行 worker,從二級佇列獲取任務,進行策略檢測,並將命中的事件分級處理,分發到對應的第三級佇列。第三級佇列即處理佇列,負責對命中規則的內容或者使用者進行處理。



快取最佳化


因為每個策略檢測都會涉及到歷史資料的回溯,自然會帶來較多的重複查詢,儲存的壓力也會比較大,所以儲存上我們又增加了多級儲存,除了 MongoDB,在上層對於近期的業務資料,儲存在 Redis 和 localcache。詳細的內容過往的技術文章已經有了比較詳細的介紹,感興趣的同學們可以去看:


圖片識別能力增強


隨著文字內容檢測能力的增強,不少 spam 開始使用圖片的方式進行作弊。在「悟空 V3」我們增強了圖片相關的檢測能力:圖片 OCR,廣告圖片識別,色情圖片識別,違法違規圖片識別,政治敏感圖片識別。針對圖片類的廣告 Spam 的檢測一直是我們的空缺,需要投入大量的人力進行模型訓練,所以這一塊我們藉助第三方快速提升這一塊的空缺。目前接入之後,著實提升了我們解決站內廣告和詐騙圖片 Spam 的能力。


風險資料進一步積累


早期由於系統還未成熟,我們很多的工作時間都花在 Spam 問題的應急響應上,很少去做各維度的風險資料累積。在「悟空 V3」我們分別在內容、帳號、IP、裝置維度開始累積相關的風險資料,供策略回溯和模型訓練使用。 目前我們有三個資料來源:策略、第三方介面和人工標註。鑑於離線人工標註效率低,並且抽取資料項繁雜的問題,我們專門搭建了一個標註後臺,提升運營同學標註資料的效率,使標註資料可複用,可追溯。以下是一些我們比較常用的風險維度:

  • 內容維度:e.g. 導流類廣告,品牌類廣告,違反法律法規

  • 帳號維度:e.g. 批次行為(批次註冊,刷贊,刷粉等),風險帳號(社工庫洩露等), 垃圾手機號,風險號段

  • IP 維度: e.g. 風險 IP ,代理 IP

  • 裝置維度:e.g. 模擬器,無頭瀏覽器

回溯能力增強


在「悟空 V3」,我們還增強了策略的回溯能力。一方面,搭建失信庫覆蓋新增內容中與失信內容相似的 Spam 內容,相似度的演算法目前我們使用的是 consine-similarity 和 jaccard。另一方面,基於 Redis,我們支援了基於導流詞、標籤、社群的快速回溯。這樣的話相關的行為更容易被聚集到一起,使得我們可以突破時間的限制,對相似的 Spam 一網打盡。


此外,我們工程和演算法團隊在演算法模型引入做了諸多嘗試。


「結網 - ZNAP (Zhihu Network Analysis Platform)」



過去做反作弊的很長一段時間,我們花了很多功夫在行為和內容層面去解決 Spam 問題。但換個角度,我們會發現,黑產團伙固然手上的資源巨多,但是也得考慮投入產出比,不管怎麼樣,資源都會存在被重複使用的情況,那用什麼方式去表示這種資源的使用情況呢?我們想到了圖,也成為了我們做「結網」這個專案的出發點。我們將這個專案分成了幾個階段:


第一階段,實現基於圖的分析能力:這個階段旨在提供一種透過網路圖譜分析問題的渠道,提升運營和產品的效率,快速進行社群(裝置,IP..)識別,團伙行為識別以及傳播分析。幫助我們養成從圖的角度去挖掘問題的習慣,並幫助我們在日常分析的過程中,總結一些經驗,輸出一些策略。圖譜分析平臺的資料基於使用者的寫行為,將使用者,裝置,IP, Objects (提問,回答..) 作為節點,具體行為作為邊。當行為發生時,將使用者與裝置,使用者與 IP, 使用者與對應的 object 關聯, 而每個節點的度就代表發生關聯的數量。 圖資料儲存的部分我們當時調研了 Titan, Neo4j 和 TinkerPop,三者之中最終選擇了 TinkerPop 作為儲存框架,底層用 HBase 作為儲存。TinkerPop 是 Apache 的頂級專案之一,是面向 OLTP 及 OLAP 的圖計算框架,其擴充套件性非常之強,只要實現了 TinkerPop 定義的 API,就能作為驅動讓儲存支援圖查詢,可以減少儲存額外維護和遷移的成本。目前 Tinkerpop 支援 HBase, Neo4j, OrientDB 等等。另外也透過 GraphComputer 支援使用 Spark 進行查詢和計算。Gremlin 是 TinkerPop 定義的 DSL,可以靈活的用於圖資料的查詢。


第二階段,基於圖實現社群發現的能力:將相似的使用者透過社群的形式化成一個圈子,便於日常分析和策略運用基於一個圈子去處理。我們採用了 modularity + fast-unfolding 實現了社群發現的演算法,拿裝置社群為例,演算法的輸入是裝置與使用者的關聯,輸出是每個裝置節點和每個使用者節點以及他們的社群號。模組度(modularity)是衡量網路劃分非常常用的維度,模組度越大,意味著比期望更多的邊落在了一個社群內,劃分效果越好。Fast-unfolding 則是一個迭代演算法,主要目標就是提升劃分社群效率,使得網路劃分的模組度不斷增大,每次迭代都會將同一社群的節點合併,所以隨著迭代的增加,計算量也在不斷減少。迭代停止的條件是社群趨於穩定或者達到迭代次數上限。


第三階段,在社群的基礎上,實現社群分類的能力:能夠有效地識別可疑和非可疑的社群,幫助日常分析和策略更好地打擊 Spam 團伙。我們使用的是可解釋性比較高的邏輯迴歸,使用了一系列社群相關的特徵和使用者相關的特徵進行訓練,作為運營輔助資料維度和線上策略使用,都有非常好的效果, 從 2017 年 6 月以來我們已經積累了 4w 的可疑社群和 170w 的正常社群。


文字相似度聚類


知乎站內的 Spammer 為了快速取得收效,往往傾向於大批次地產生相似的 Spam 內容,或者密集地產生特定的行為。針對這種大量,相似,和相對聚集的特點,我們使用 Spark 透過 jaccard 和 sim-hash 實現了文字聚類,透過把相似的文字聚類,實現對批次行為的一網打盡。詳細的內容可以參見:


未登入熱詞發現


品牌類內容也是知乎站內佔大頭的 Spam 型別。目前站內大部分的惡意營銷都是出於 SEO 的目的,利用知乎的 PageRank 來提升搜尋引擎的關鍵詞權重。因此這類內容的特點就是大量的關鍵詞(品牌相關,品類屬性相關的詞彙)會被提及。由於都是一些小眾品牌和新品牌,這類關鍵詞一般都未被切詞詞庫收錄,就是我們所謂的未登入詞 (Unknown Words), 於是我們從詞彙的左右資訊熵和互資訊入手,去挖掘未登入詞, 並取得了比較好的效果。關於我們實現的細節,可以參考我們的系列文章:。


導流詞識別


針對站內的導流內容,最開始在識別導流資訊上採用的是干擾轉換+正則匹配+匹配項回溯的方式進行異常導流資訊的識別與控制,取得了很好的效果。此外,隨著整治加強,我們發現站內導流變體的現象也在愈演愈烈,對此,我們也成功引入模型進行整治,透過 BILSTM-CRF 來識別導流變體,目前在提問和回答的識別準確率分別達到 97.1%、96.3%。想要了解的同學快去看看我們的系列文章:。


通用垃圾內容分類


對於垃圾內容的治理,雖然線上一直有策略在覆蓋,但是策略的泛化能力有限,始終會有新型的 Spam 繞過策略。我們嘗試使用深度學習構建通用垃圾文字分類模型。模型使用字向量作為輸入,多層 Dilated Convolution 提取文字特徵,透過 Attention 對卷積後的表達重新加權得到高層特徵,最後得到垃圾內容的機率。針對近期我們遇到的批次 Spam 內容單條規則召回率可以達到 98% 以上,準確率達到95.6%。對於「通用垃圾內容」定義,樣本的篩選以及模型訓練的過程,我們也積累了一些經驗和教訓。後續我們的工程師也會單獨介紹細節,敬請關注噢。


至此,「悟空」整個體系的架構演進已經跟大家介紹完了,當前的整體架構如下圖所示一共有這麼幾個部分:



  • Gateway: 負責異常使用者狀態攔截,業務同步攔截,反爬攔截。


  • 業務層:對接的各個業務方。


  • 資料接入層:資料接入層有兩種方式,一種透過 RPC 透傳,一種透過 kafka 訊息,實現業務與反作弊系統的解耦。


  • 策略決策層:策略決策層,分為事前同步決策和事中事後非同步決策,橫向對應的還有策略管理服務,一系列風險分析和運營工具。根據決策結果的可疑程度不同,要麼送審要麼進行不同程度的處理,確認是 Spam 的行為會進入風險庫,回饋到策略再次使用。


  • 資料儲存層:資料儲存層包括基礎的基礎的事件庫,風險庫,離線 HDFS 的資料落地等等, 這一塊的資料不僅僅面向反作弊系統開放使用,並且會提供給外部進行模型訓練使用和線上業務使用。


  • 資料計算層:這一層包括一些離線的機器學習模型,每日定時計算模型結果,並將資料落地。


  • 資料服務層:因為反作弊不僅僅要依賴自己內部的資料,還會涉及到從業務取相關的資料,所以這一層會涉及到與業務資料,環境資料以及模型演算法服務的互動。

經過三年的團隊的努力,「悟空」構建了一個模型 & 策略識別 - 決策 - 管控 - 評估 & 改進的閉環。未來「悟空」還會面臨更大的挑戰,我們的目標不止於處理垃圾資訊,更重要的是保護使用者的體驗,「悟空」的升級之路沒有止境。我們會持續在知乎產品()、技術( )專欄中和大家介紹知乎反作弊的相關資訊,歡迎關注。


作者:周奧特     原文連結:,轉載自周奧特的知乎賬號。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2157771/,如需轉載,請註明出處,否則將追究法律責任。

相關文章