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