本文首發於 Nebula Graph 公衆號 NebulaGraphCommunity,Follow 看大廠圖數據庫技術實踐。前端
【做者介紹】算法
【公司簡介】數據庫
快手是一家全球領先的內容社區和社交平臺,旨在經過短視頻的方式幫助人們發現所需、發揮所長,持續提高每一個人獨特的幸福感。小程序
傳統的關係型數據庫,在處理複雜數據關係運算上表現不好,隨着數據量和深度的增長,關係型數據庫沒法在有效的時間內計算出結果。安全
因此,爲了更好的體現數據間的鏈接,企業須要一種將關係信息存儲爲實體、靈活拓展數據模型的數據庫技術,這項技術就是圖數據庫(Graph Database)。markdown
相比於傳統關係型數據庫,圖數據庫具備如下兩個優勢:網絡
第一點,圖數據庫能很好地體現
數據之間的關聯關係session
從上面的圖模型能夠看出,圖數據庫的目標就是基於圖模型以一種直觀的方式來展現這些關係,其基於事物關係的模型表達,使圖數據庫自然具備可解釋性。數據結構
第二點,圖數據庫能很好地處理
數據之間的關聯關係:架構
基於以上兩個優勢,圖數據庫在金融反欺詐、公安刑偵、社交網絡、知識圖譜、數據血緣、IT 資產及運維、威脅情報等領域有巨大需求。
而快手安全情報則是經過整合移動端、PC Web 端、雲端、聯盟及小程序等全鏈條的安全數據,最終造成統一的基礎安全能力賦能公司業務。
因爲安全情報自己具備數據實體多樣性、關聯關係複雜性、數據標籤豐富性等特色,所以採用圖數據庫來作是最爲合適的。
經過收集需求及前期調研,快手安全情報在圖數據庫上最終選擇了Nebula Graph
做爲生產環境的圖數據庫。
對於圖數據庫的選型來講,其主要需求是在數據寫入與數據查詢兩個方面:
綜上所述,這次選型的適用於大數據架構的圖數據庫主要須要提供 3 種基本能力:實時和離線數據寫入、在線圖數據基本查詢、基於圖數據庫的簡單 OLAP 分析,其對應定位是:在線、高併發、低時延 OLTP 類圖查詢服務及簡單 OLAP 類圖查詢能力。
基於以上的肯定性需求,在進行圖數據庫的選型上,咱們主要考慮瞭如下幾點:
正是基於Nebula Graph
的以上特色以及對咱們使用場景和需求的剛好知足,所以最終選擇Nebula Graph
做爲咱們生產環境的圖數據庫來使用。
以下圖所示,從情報的角度來看,安全的分層對抗與防守,從下到上,其對抗難度是逐漸增長的:
每個平面上,以前攻擊方與防守方都是單獨的對抗,如今利用圖數據庫以後,能夠將每個層次的實體ID經過關聯關係串聯起來,造成一張立體層次的網,經過這張立體層次的網可以使企業快速掌握攻擊者的攻擊方式、做弊工具、團伙特徵等較全貌的信息。
所以基於安全數據的圖結構數據建模,能夠將原來的平面識別層次變成立體網狀識別層次,能幫助企業更清晰準確的識別攻擊與風險。
安全情報的圖建模主要目的是但願判斷任何一個維度風險的時候,不僅僅侷限於該維度自己的狀態與屬性去看它的風險,而是將維度從個體擴展爲網絡層面,經過圖結構的數據關係,經過上下層次(異構圖)及同級層次(同構圖)立體去觀察該維度的風險。
以設備風險舉例:對一個設備而言,總體分爲網絡層、設備層、帳號層和用戶層這四個層面,每一個層面都由其表明性的實體 ID 來表達。經過圖數據庫,能夠作到對一個設備進行立體的三維層次的風險認知,這對於風險的識別會很是有幫助。
如上圖所示,這是安全情報的基本圖結構建模,以上構成了一個基於安全情報的知識圖譜。
在基本圖結構之上,還須要考慮的是,每一種關聯關係的存在都是有時效性的,A 時間段內關聯關係存在,B 時間段內該關聯關係則未必存在,所以咱們但願安全情報能在圖數據庫上真實反映客觀現實的這種不一樣時間段內的關聯關係。
這意味着須要隨着查詢時間區間的不一樣,而呈現出不一樣的圖結構模型的數據,咱們稱之爲動態圖結構
。
在動態圖結構的設計上,涉及到的一個問題是:在被查詢的區間上,什麼樣的邊關係應該被返回?
如上圖所示,當查詢時間區間爲 B、C、D 時,這條邊應該要被返回,當查詢時間區間爲A、E時,這條邊不該該被返回。
在面對黑灰產或者真人做惡時,每每會出現這種狀況:就是一個設備上面會對應很是多的帳號,有些帳號是不法壞人本身的經常使用帳號,而有些帳號則是他們買來作特定不法直播的帳號。爲配合公安或法務的打擊,咱們須要從這批帳號裏面精準區分出哪些帳號是真實壞人本身的經常使用帳號,而哪些帳號只是他們買來用於做惡的帳號。
所以這裏面會涉及到帳號與設備關聯關係邊的權重問題:若是是該設備經常使用的帳號,那麼代表這個帳號與這個設備的關係是較強的關係,則這條邊的權重就會高;若是僅僅是做惡/開直播的時候纔會使用的帳號,那麼帳號與設備的關係則會比較弱,相應權重就會低一些。
所以咱們在邊的屬性上,除了有時間維度外,還增長了權重維度。
綜上所述,最終在安全情報上所創建的圖模型是:帶權重的動態時區圖結構
。
總體安全情報服務架構圖以下所示:
安全情報服務總體架構圖
其中,基於圖數據庫的情報綜合查詢平臺,軟件架構以下圖所示:
情報綜合查詢平臺軟件架構圖
注:AccessProxy 支持辦公網到 IDC 的訪問,kngx 支持 IDC 內的直接調用
針對所構建的關聯關係數據,天天更新的量在數十億級別,如何保證這數十億級別的數據能在小時級內寫入、感知數據異常且不丟失數據,這也是一項很是有挑戰性的工做。
對這部分的優化主要是:失敗重試、髒數據發現及導入失敗報警策略。
數據導入過程當中會因爲髒數據、服務端抖動、數據庫進程掛掉、寫入太快等各類因素致使寫 batch 數據失敗,咱們經過用同步 client API、多層級的重試機制及失敗退出策略,解決了因爲服務端抖動重啓等狀況形成的寫失敗或寫 batch 不徹底成功等問題。
在圖數據庫部分,快手部署了在線與離線兩套圖數據庫集羣,兩個集羣的數據採用同步雙寫,在線集羣承擔在線 RPC 類的服務,離線集羣承擔 CASE 分析及 WEB 查詢的服務,這兩個集羣互不影響。
同時集羣的狀態監控與動態配置下發模塊是打通的,當某一個集羣出現慢查詢或發生故障時,經過動態配置下發模塊來進行自動切換,作到上層業務無感知。
數據架構團隊對開源版本的 Nebula Graph 進行了總體的調研、維護與改進。
Nebula 的集羣採用計算存儲分離的模式,從總體架構看,分爲 Meta,Graph,Storage 三個角色,分別負責元數據管理,計算和存儲:
Nebula 總體架構圖
Nebula 的存儲層做爲圖數據庫引擎的底座,支持多種存儲類型,咱們使用 Nebula 時選擇了經典模式,即用經典的 C++ 實現的 RocksdDB 做爲底層 KV 存儲,並利用 Raft 算法解決一致性的問題,使整個集羣支持水平動態擴容。
存儲層架構圖
咱們對存儲層進行了充分的測試、代碼改進與參數優化。其中包括:優化 Raft 心跳邏輯、改進 leader選舉和 log offset 的邏輯以及對 Raft 參數進行調優等,來提高單集羣的故障恢復時間;再結合客戶端重試機制的優化,使得 Nebula 引擎在用戶體驗上從最初的故障直接掉線改善爲故障毫秒級恢復。
在監控報警體系上,咱們構建了對集羣多個層面的監控,其總體監控架構以下圖所示:
集羣監控架構圖
包括以下幾個方面:
因爲現實圖網絡結構中點的出度每每符合冪律分佈特徵,圖遍歷遇到超級點(出度百萬/千萬)將致使數據庫層面明顯的慢查詢,如何保證在線服務查詢耗時的平穩性,避免極端耗時的發生是咱們須要解決的問題。
圖遍歷超級點問題在工程上的解決思路是:在業務可接受的前提下縮小查詢規模。具體方法有:
下面分別描述具體的優化策略:
【前提條件】
業務層面可接受每一跳作 limit 截斷,例如以下兩個查詢:
# 最終作limit截斷
go from hash('x.x.x.x') over GID_IP REVERSELY where (GID_IP.update_time >= xxx and GID_IP.create_time <= xxx) yield GID_IP.create_time as create_time, GID_IP.update_time as update_time, $^.IP.ip as ip, $$.GID.gid | limit 100
# 在中間查詢結果已經作了截斷,而後再進行下一步
go from hash('x.x.x.x') over GID_IP REVERSELY where (GID_IP.update_time >= xxx and GID_IP.create_time <= xxx) yield GID_IP._dst as dst | limit 100 | go from $-.dst ..... | limit 100
複製代碼
【優化前】
對第二個查詢語句,在優化前,storage會遍歷點的全部出度,graph 層在最終返回 client 前才作 limit n 的截斷,這種沒法避免大量耗時的操做。
另外 Nebula 雖然支持 storage 配置集羣(進程)級別參數max_edge_returned_per_vertex
(每一個 vertex 掃描最大出度),但沒法知足查詢語句級別靈活指定 limit 而且對於多跳多點出度查詢也沒法作到語句級別精確限制。
【優化思路】
一跳 go 遍歷查詢分兩步:
那麼 go 多跳遍歷中每跳的執行分兩種狀況:
而 step2 是耗時大頭(查每一個 destVertex 屬性即一次 rocksdb iterator,不命中 cache 狀況下耗時 500us),對於出度大的點將「limit 截斷」提早到 step2 以前是關鍵,另外 limit 能下推到 step1 storage 掃邊出度階段對於超級點也有較大的收益。
這裏咱們總結下什麼條件下能執行「limit 截斷優化」及其收益:
表註釋: N 表示 vertex 出度,n 表示 limit n,scan 表示掃邊出度消耗,get 表示獲取 vertex 屬性的消耗
【測試效果】
對於以上 case1 和 case2 可執行「limit 截斷優化」且收益明顯,其中安全業務查詢屬於 case2,如下是在 3 臺機器集羣,單機單盤 900 GB 數據存儲量上針對 case2 limit 100 作的測試結果(不命中 rocksdb cache 的條件):
以上測試結果代表,通過咱們的優化後,在圖超級點查詢耗時上,取得了很是優異的表現。
針對不能簡單作「limit 截斷優化」的場景,咱們能夠採起「邊採樣優化」的方式來解決。在 Nebula 社區原生支持的「storage 進程級別可配置每一個 vertex 最大返回出度邊和開啓邊採樣功能」基礎上,咱們優化後,能夠進一步支持以下功能:
max_iter_edge_for_sample
數量的邊而非掃全部邊(默認)go
每跳出度採樣功能enable_reservoir_sampling
」和「每一個 vertex 最大返回出度 max_edge_returned_per_vertex
」都支持 session 級別參數可配經過以上功能的支持,業務能夠更靈活地調整查詢採樣比例,控制遍歷查詢規模,以達到在線服務的平滑性。
開源的 Nebula Graph 有本身的一套客戶端,而如何將這套客戶端與快手的工程相結合,這裏咱們也作了一些相應的改造與優化。主要解決了下面兩個問題:
針對固定關係的查詢(寫死 nGQL),前端根據返回結果,進行定製化的圖形界面展現,以下圖所示:
這裏前端採用ECharts
的關係圖,在前端的圖結構數據加載及展現這裏也作了一些優化。
問題一:關係圖須要能展現每一個節點的詳情信息,而 ECharts 提供的圖裏只能作簡單的 value 值的展現。
解決方案:在原代碼上進行改造,每一個節點添加點擊事件,彈出模態框展現更多的詳情信息。
問題二:關係圖在點擊事件觸發後,圖會有較長時間的轉動,沒法辨認點擊了哪一個節點。
解決方案:獲取初次渲染圖形時每一個節點的窗口位置,在點擊事件觸發後,給每一個節點位置固定下來。
問題三:當圖的節點衆多時候,關係圖展現的比較擁擠。
解決方案:開啓鼠標縮放和評議漫遊功能。
針對靈活關係的查詢(靈活 nGQL),根據部署的Nebula Graph Studio
進行可視化的呈現,以下圖所示:
基於以上圖數據庫的結構與優化,咱們提供了 Web 查詢和 RPC 查詢兩種接入方式,主要支持了快手的以下業務:
例如,羣控設備與正常設備在圖數據上的表現存在明顯區別:
對於羣控設備的識別:
感謝開源社區Nebula Graph
對快手的支持。
交流圖數據庫技術?加入 Nebula 交流羣請先填寫下你的 Nebulae 名片,Nebula 小助手會拉你進羣~~