導讀:作弊是網際網路應用最常碰見的問題之一。有作弊就有反作弊,如果高效的對作弊內容進行識別,識別後又該如何處理作弊內容,每家公司都有自己的獨門絕技。本文作者對知乎反作弊系統的演進進行了介紹,深入剖析了該系統的架構設計和演進歷程,十分耐讀。
Hi there! 距離 2015 年 4 月「悟空」正式與大家見面,已經整整三個年頭了。隨著知乎的不斷發展壯大,過去的一段時間,「悟空」不斷面臨著新的考驗,並持續地在最佳化升級。接下來跟大家系統分享一下這幾年「悟空」的架構演進和構建過程中積累的經驗與教訓。
業務現狀
截止2018年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)、技術(Hacker’s log )專欄中和大家介紹知乎反作弊的相關資訊,歡迎關註。
參考文獻:
[1] Facebook Immune System https://css.csail.mit.edu/6.858/2012/readings/facebook-immune.pdf
[2] Fighting spam with BotMaker https://blog.twitter.com/engineering/en_us/a/2014/fighting-spam-with-botmaker.html
[3] Fighting Abuse @Scale 2018 https://atscaleconference.com/events/fighting-abuse-scale/#
[4] Spam Fighting @scale 2016 https://code.fb.com/security/spam-fighting-scale-2016/
[5] 美團點評業務風控系統構建經驗 https://tech.meituan.com/risk_control_system_experience_sharing.html
更多關於wukong的資訊:
– 反作弊基於左右資訊熵和互資訊的新詞挖掘 https://zhuanlan.zhihu.com/p/25499358
– WuKong 反作弊系統快取的最佳化 https://zhuanlan.zhihu.com/p/23509238
– Spark 在反作弊聚類場景的實踐 https://zhuanlan.zhihu.com/p/23385044
– 知乎反作弊系統「悟空」演變 http://www.infoq.com/cn/presentations/zhihu-anti-cheat-system-evolution
– 「悟空」和大家見面啦 https://zhuanlan.zhihu.com/p/19998740?refer=zhihu-product
相關閱讀:
高可用架構
改變網際網路的構建方式
長按二維碼 關註「高可用架構」公眾號