知乎反作弊系統「悟空」架構演進

知乎反作弊系統「悟空」架構演進

來自專欄 Hackers log296 人贊了文章

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 的策略:

 action == "ANSWER\_CREATE" and  len(user(same\_register\_ip(register\_time(same\_topics(same\_type\_events(10)),register\_interval=3600)))) >= 3

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

最近 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 等等,一般基礎的策略需求通過前三者就能實現。

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

action == ANSWER\_CREATE and same\_type\_events(10)\.filter(same\_register\_ip).filter(register\_time,register\_interval=3600)\.filter(same\_topics,mtype=AcceptID).mapper(userid).reducer(diff).length >= 3

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

策略自助配置

完成了策略結構的優化,下一步需要解決的,是策略上線流程研發和產品雙重角色交替的問題,「悟空 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。詳細的內容過往的技術文章已經有了比較詳細的介紹,感興趣的同學們可以去看:Wukong 反作弊系統緩存的優化

圖片識別能力增強

隨著文本內容檢測能力的增強,不少 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 實現了文本聚類,通過把相似的文本聚類,實現對批量行為的一網打盡。詳細的內容可以參見:Spark 在反作弊聚類場景的實踐

未登錄熱詞發現

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

導流詞識別

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

通用垃圾內容分類

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

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

  • Gateway: 負責異常用戶狀態攔截,業務同步攔截,反爬攔截。
  • 業務層:對接的各個業務方。
  • 數據接入層:數據接入層有兩種方式,一種通過 RPC 透傳,一種通過 kafka 消息,實現業務與反作弊系統的解耦。
  • 策略決策層:策略決策層,分為事前同步決策和事中事後非同步決策,橫向對應的還有策略管理服務,一系列風險分析和運營工具。根據決策結果的可疑程度不同,要麼送審要麼進行不同程度的處理,確認是 Spam 的行為會進入風險庫,回饋到策略再次使用。
  • 數據存儲層:數據存儲層包括基礎的基礎的事件庫,風險庫,離線 HDFS 的數據落地等等, 這一塊的數據不僅僅面向反作弊系統開放使用,並且會提供給外部進行模型訓練使用和在線業務使用。
  • 數據計算層:這一層包括一些離線的機器學習模型,每日定時計算模型結果,並將數據落地。
  • 數據服務層:因為反作弊不僅僅要依賴自己內部的數據,還會涉及到從業務取相關的數據,所以這一層會涉及到與業務數據,環境數據以及模型演算法服務的交互。

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

作者:周奧特 陳磊 張春榮 翟峰

Reference:

[1] Facebook Immune System

[2] Fighting spam with BotMaker

[3] Fighting Abuse @Scale 2018

[4] Spam Fighting @scale 2016

更多關於 wukong:

- 反作弊基於左右信息熵和互信息的新詞挖掘

- WuKong 反作弊系統緩存的優化

- Spark 在反作弊聚類場景的實踐

- 知乎反作弊系統「悟空」演變

- 「悟空」和大家見面啦


推薦閱讀:

處置非法集資徵求意見,或成史上最嚴標準
2017年度十大互聯網傳銷案例(上)
悟*問答你*死了
知乎上的30條神回復,針針見血,看完整個人通透多了

TAG:反作弊 | 反垃圾AntiSpam | 知乎 |