百億節(jié)點(diǎn)希痴、毫秒級(jí)延遲,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

干貨 | 百億節(jié)點(diǎn)春感,毫秒級(jí)延遲砌创,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

作者:霖霧,攜程數(shù)據(jù)開發(fā)工程師鲫懒,關(guān)注圖數(shù)據(jù)庫等領(lǐng)域嫩实。

0. 背景

2017 年 9 月攜程金融成立,在金融和風(fēng)控業(yè)務(wù)中窥岩,有多種場(chǎng)景需要對(duì)圖關(guān)系網(wǎng)絡(luò)進(jìn)行分析和實(shí)時(shí)查詢甲献,傳統(tǒng)關(guān)系型數(shù)據(jù)庫難以保證此類場(chǎng)景下的關(guān)聯(lián)性能,且實(shí)現(xiàn)復(fù)雜性高颂翼,離線關(guān)聯(lián)耗時(shí)過長(zhǎng)晃洒,因此對(duì)圖數(shù)據(jù)庫的需求日益增加。攜程金融從 2020 年開始引入大規(guī)模圖存儲(chǔ)和圖計(jì)算技術(shù)朦乏,基于 NebulaGraph 構(gòu)建了千億級(jí)節(jié)點(diǎn)的圖存儲(chǔ)和分析平臺(tái)球及,并取得了一些實(shí)際應(yīng)用成果。

本文主要分享 NebulaGraph 在攜程金融的實(shí)踐呻疹,希望能帶給大家一些實(shí)踐啟發(fā)吃引。

本文主要從以下幾個(gè)部分進(jìn)行分析:

  • 圖基礎(chǔ)介紹
  • 圖平臺(tái)建設(shè)
  • 內(nèi)部應(yīng)用案例分析
  • 痛點(diǎn)與優(yōu)化
  • 總結(jié)規(guī)劃

1. 圖基礎(chǔ)

首先我們來簡(jiǎn)單介紹下圖相關(guān)的概念:

1.1 什么是圖

在計(jì)算機(jī)科學(xué)中,圖就是一些頂點(diǎn)的集合,這些頂點(diǎn)通過一系列邊結(jié)對(duì)(連接)镊尺。比如我們用一個(gè)圖表示社交網(wǎng)絡(luò)朦佩,每一個(gè)人就是一個(gè)頂點(diǎn),互相認(rèn)識(shí)的人之間通過邊聯(lián)系庐氮。

在圖數(shù)據(jù)庫中吕粗,我們使用(起點(diǎn),邊類型,rank,終點(diǎn))表示一條邊。起點(diǎn)和終點(diǎn)比較好理解旭愧,表示一條邊兩個(gè)頂點(diǎn)的出入方向颅筋。邊類型則是用于區(qū)分異構(gòu)圖的不同邊,如我關(guān)注了你输枯,我向你轉(zhuǎn)賬议泵,關(guān)注和轉(zhuǎn)賬就是兩種不同種類的邊。而 rank 是用來區(qū)分同起始點(diǎn)同終點(diǎn)的不同邊桃熄,如 A 對(duì) B 的多次轉(zhuǎn)賬記錄先口,起點(diǎn)、終點(diǎn)瞳收、邊類型是完全相同的碉京,因此就需要如時(shí)間戳作為 rank 來區(qū)分不同的邊。

同時(shí)螟深,點(diǎn)邊均可具有屬性谐宙,如:A 的手機(jī)號(hào)、銀行卡界弧、身份證號(hào)凡蜻、籍貫等信息均可作為 A 的點(diǎn)屬性存在,A 對(duì) B 轉(zhuǎn)賬這條邊垢箕,也可以具有屬性划栓,如轉(zhuǎn)賬金額,轉(zhuǎn)賬地點(diǎn)等邊屬性条获。

干貨 | 百億節(jié)點(diǎn)忠荞,毫秒級(jí)延遲,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

1.2 什么時(shí)候用圖

(信息收集于開源社區(qū)帅掘、公開技術(shù)博客委煤、文章、視頻)

1.2.1 金融風(fēng)控

  • 詐騙電話的特征提取锄开,如不在三步社交鄰居圈內(nèi)素标,被大量拒接等特征。實(shí)時(shí)識(shí)別攔截萍悴。(銀行 / 網(wǎng)警等)
  • 轉(zhuǎn)賬實(shí)時(shí)攔截(銀行 / 支付寶等)
  • 實(shí)時(shí)欺詐檢測(cè)头遭,羊毛黨的識(shí)別(電商)
  • 黑產(chǎn)群體識(shí)別寓免,借貸記錄良好用戶關(guān)聯(lián),為用戶提供更高額貸款计维、增加營(yíng)收

1.2.2 股權(quán)穿透

影子集團(tuán)袜香、集團(tuán)客戶多層交叉持股、股權(quán)層層嵌套復(fù)雜關(guān)系的識(shí)別(天眼查 / 企查查)

1.2.3 數(shù)據(jù)血緣

在數(shù)據(jù)倉庫開發(fā)過程中鲫惶, 會(huì)因?yàn)閿?shù)據(jù)跨表關(guān)聯(lián)產(chǎn)生大量的中間表蜈首,使用圖可直接根據(jù)關(guān)系模型表示出數(shù)據(jù)加工過程和數(shù)據(jù)流向,以及在依賴任務(wù)問題時(shí)快速定位上下游欠母。

1.2.4 知識(shí)圖譜

構(gòu)建行業(yè)知識(shí)圖譜欢策。

1.2.5 泛安全

IP 關(guān)系等黑客攻擊場(chǎng)景,計(jì)算機(jī)進(jìn)程與線程等安全管理赏淌。

1.2.6 社交推薦

  • 好友推薦踩寇,行為相似性,咨詢傳播路徑六水,可能認(rèn)識(shí)的人俺孙,大V 粉絲共同關(guān)注,共同閱讀文章等掷贾,商品相似性睛榄,實(shí)現(xiàn)好友商品或者咨詢的精準(zhǔn)推薦;
  • 通過對(duì)用戶畫像想帅、好友關(guān)系等场靴,進(jìn)行用戶分群、實(shí)現(xiàn)用戶群體精準(zhǔn)管理博脑;

1.2.7 代碼依賴分析

分析代碼依賴關(guān)系憎乙。

1.2.8 供應(yīng)鏈上下游分析

如:汽車供應(yīng)鏈上下游可涉及上萬零件及供應(yīng)商,分析某些零件成本上漲 / 供應(yīng)商單一 / 庫存少等多維度的影響叉趣。(捷豹)

1.3 誰在研發(fā)圖,誰在使用圖

(信息收集于開源社區(qū)该押、公開技術(shù)博客疗杉、文章、視頻)

目前國(guó)內(nèi)幾家大公司都有各自研發(fā)的圖數(shù)據(jù)庫蚕礼,主要滿足內(nèi)部應(yīng)用的需求烟具,大多數(shù)都是閉源的,開源的僅有百度的 HugeGraph奠蹬。其他比較優(yōu)秀的開源產(chǎn)品有 Google Dgraph朝聋,vesoft 的 NebulaGraph 等,其中 NebulaGraph 在國(guó)內(nèi)互聯(lián)網(wǎng)公司應(yīng)用非常廣泛囤躁。結(jié)合我們的應(yīng)用場(chǎng)景冀痕,以及外部公開的測(cè)試和內(nèi)部壓測(cè)荔睹,我們最終選擇 NebulaGraph 構(gòu)建金融圖平臺(tái)。

干貨 | 百億節(jié)點(diǎn)言蛇,毫秒級(jí)延遲僻他,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

2. 圖平臺(tái)建設(shè)

干貨 | 百億節(jié)點(diǎn),毫秒級(jí)延遲腊尚,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

2.1 圖平臺(tái)建設(shè)

我們的圖平臺(tái)早期只有 1 個(gè) 3 節(jié)點(diǎn)的 Nebula 集群吨拗。隨著圖應(yīng)用場(chǎng)景的不斷擴(kuò)充,需要滿足實(shí)時(shí)檢索婿斥、離線分析劝篷、數(shù)據(jù)同步與校驗(yàn)等功能,最終演化成上述架構(gòu)圖民宿。

2.1.1 離線圖

主要用于圖構(gòu)建階段(建模娇妓、圖算法分析),通過 spark-connector 同集團(tuán)的大數(shù)據(jù)平臺(tái)打通勘高,此外我們還將 NebulaGraph 提供的數(shù) 10 種常用圖算法進(jìn)行工具化包裝峡蟋,方便圖分析人員在 Spark 集群提交圖算法作業(yè)。

2.1.2 線上圖

經(jīng)過離線圖分析確定最終建模后华望,會(huì)通過 spark-connector 將數(shù)據(jù)導(dǎo)入線上圖蕊蝗。通過對(duì)接 qmq 消息(集團(tuán)內(nèi)部的消息框架)實(shí)時(shí)更新,對(duì)外提供實(shí)時(shí)檢索服務(wù)赖舟。同時(shí)也會(huì)有 T+1 的 HIVE 增量數(shù)據(jù)通過 spark-connector 按天寫入蓬戚。

2.1.3 全量校驗(yàn)

雖然 NebulaGraph 通過 TOSS 保證了正反邊的插入一致性,但仍不支持事務(wù)宾抓,隨著數(shù)據(jù)持續(xù)更新子漩,實(shí)時(shí)圖和離線(HIVE 數(shù)據(jù))可能會(huì)存在不一致的情況,因此我們需要定期進(jìn)行全量數(shù)據(jù)的校驗(yàn)(把圖讀取到 Hive石洗,和 Hive 表存儲(chǔ)的圖數(shù)據(jù)進(jìn)行比對(duì)幢泼,找出差異、修復(fù))讲衫,保證數(shù)據(jù)的最終一致性缕棵。

2.1.4 集群規(guī)模

為了滿足千億節(jié)點(diǎn)的圖業(yè)務(wù)需求,實(shí)時(shí)集群采用三臺(tái)獨(dú)立部署的高性能機(jī)器涉兽,每臺(tái)機(jī)器 64 core / 320 GB / 12 TB SSD 招驴,版本為 Nebula v2.5,跨機(jī)房部署枷畏。離線集群 64 core / 320 GB / 3.6 TB SSD * 12 别厘,測(cè)試集群 48 core / 188 GB / 5T HDD * 4.

2.2 遇到的問題

在 NebulaGraph 應(yīng)用過程中,也發(fā)現(xiàn)一些問題拥诡,期待逐步完善:

  1. 資源隔離問題触趴,目前 Nebula 沒有資源分組隔離功能氮发,不同業(yè)務(wù)會(huì)相互影響;如業(yè)務(wù)圖 A 在導(dǎo)數(shù)據(jù)雕蔽,業(yè)務(wù)圖 B 線上延遲就非常高折柠。
  2. 版本升級(jí)問題:
    1. NebulaGraph 在版本升級(jí)過程中需要停止服務(wù),無法實(shí)現(xiàn)熱更新批狐;對(duì)于類似實(shí)時(shí)風(fēng)控等對(duì)可靠性要求非常高的場(chǎng)景非常不友好扇售。此種情況下如需保證在線升級(jí),就需要配備主備集群嚣艇,每個(gè)集群切量后挨個(gè)升級(jí)承冰,增加服務(wù)復(fù)雜性和運(yùn)維成本。
    2. 客戶端不兼容食零,客戶端需要跟著服務(wù)端一起升級(jí)版本困乒。對(duì)于已有多個(gè)應(yīng)用使用的 Nebula 集群,想要協(xié)調(diào)各應(yīng)用方同時(shí)升級(jí)客戶端是比較困難的贰谣。

3. 內(nèi)部應(yīng)用案例分析

3.1 數(shù)據(jù)血緣圖

數(shù)據(jù)治理是近年來比較熱的一個(gè)話題娜搂,他是解決數(shù)倉無序膨脹的有效手段,其中數(shù)據(jù)血緣是數(shù)據(jù)有效治理的重要依據(jù)吱抚,攜程金融借助 NebulaGraph 構(gòu)建了數(shù)據(jù)血緣圖百宇,以支撐數(shù)據(jù)治理的系統(tǒng)建設(shè)。

干貨 | 百億節(jié)點(diǎn)秘豹,毫秒級(jí)延遲携御,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐
干貨 | 百億節(jié)點(diǎn),毫秒級(jí)延遲既绕,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

數(shù)據(jù)血緣就是數(shù)據(jù)產(chǎn)生的鏈路啄刹,記錄數(shù)據(jù)加工的流向,經(jīng)過了哪些過程和階段凄贩;主要解決 ETL 過程中可能產(chǎn)出幾十甚至幾百個(gè)中間表導(dǎo)致的復(fù)雜表關(guān)系誓军,借用數(shù)據(jù)血緣可以清晰地記錄數(shù)據(jù)源頭到最終數(shù)據(jù)的生成過程。

圖 a 是數(shù)據(jù)血緣的關(guān)系圖疲扎,采用庫名 + 表名作為圖的頂點(diǎn)來保證點(diǎn)的唯一性谭企,點(diǎn)屬性則是分開的庫名和表名,以便通過庫名或者表名進(jìn)行屬性查詢评肆。在兩張表之間會(huì)建立一條邊,邊的屬性主要存放任務(wù)的產(chǎn)生運(yùn)行情況非区,比如說:任務(wù)開始時(shí)間瓜挽,結(jié)束時(shí)間、用戶 ID 等等同任務(wù)相關(guān)的信息征绸。

圖 b 是實(shí)際查詢中的一張關(guān)系圖久橙,箭頭的方向表示了表的加工方向俄占,通過上游或者下游表我們可以快速地找到它的依賴,清晰明了地顯示從上游到下游的每一個(gè)鏈路淆衷。

如果要表達(dá)復(fù)雜的血緣依賴關(guān)系圖缸榄,通過傳統(tǒng)的關(guān)系型數(shù)據(jù)庫需要復(fù)雜的 SQL 實(shí)現(xiàn)(循環(huán)嵌套),性能也比較差祝拯,而通過圖數(shù)據(jù)庫實(shí)現(xiàn)甚带,則可直接按數(shù)據(jù)依賴關(guān)系存儲(chǔ),讀取也快于傳統(tǒng) DB佳头,非常簡(jiǎn)潔鹰贵。目前,數(shù)據(jù)血緣也是攜程金融在圖數(shù)據(jù)庫上的一個(gè)經(jīng)典應(yīng)用康嘉。

3.2 風(fēng)控關(guān)系人圖

關(guān)系人圖常用于欺詐識(shí)別等場(chǎng)景碉输,它是通過 ID、設(shè)備亭珍、手機(jī)標(biāo)識(shí)以及其他介質(zhì)信息關(guān)聯(lián)不同用戶的關(guān)系網(wǎng)絡(luò)敷钾。比如說,用戶 A 和用戶 B 共享一個(gè) Wi-Fi肄梨,他們便是局域網(wǎng)下的關(guān)系人阻荒;用戶 C 和用戶 D 相互下過單,他們便是下單關(guān)系人峭范。簡(jiǎn)言之财松,系統(tǒng)通過多種維度的數(shù)據(jù)關(guān)聯(lián)不同的用戶,這便是關(guān)系人圖纱控。

構(gòu)建模型時(shí)辆毡,通常要查詢某個(gè)時(shí)點(diǎn)(比如欺詐事件發(fā)生前)的關(guān)系圖,對(duì)當(dāng)時(shí)的圖進(jìn)行模型抽取和特征構(gòu)建甜害,我們稱這個(gè)過程為圖回溯舶掖。隨著回溯時(shí)間點(diǎn)的不同,返回的圖數(shù)據(jù)也是動(dòng)態(tài)變化的尔店;比如某人上午眨攘,下午各自打了一通電話,需要回溯此人中午時(shí)間點(diǎn)時(shí)的圖關(guān)系嚣州,只會(huì)出現(xiàn)上午的電話記錄鲫售,具體到圖,則每類邊都具有此類時(shí)間特性该肴,每一次查詢都需要對(duì)時(shí)間進(jìn)行限制情竹。

對(duì)于圖回溯場(chǎng)景,最初我們嘗試通過 HIVE SQL 實(shí)現(xiàn)匀哄,發(fā)現(xiàn)對(duì)于二階及以上的圖回溯秦效,SQL 表達(dá)會(huì)非常復(fù)雜雏蛮,而且性能不可接受(比如二階回溯 Hive 需要跑數(shù)小時(shí),三階回溯 Hive 幾乎不能實(shí)現(xiàn))阱州;因此嘗試借助圖數(shù)據(jù)庫來實(shí)現(xiàn)挑秉,把時(shí)間作為邊 rank 進(jìn)行建模,再根據(jù)邊關(guān)系進(jìn)行篩選來實(shí)現(xiàn)回溯苔货。這種回溯方式更直觀犀概、簡(jiǎn)潔,使用簡(jiǎn)單的 API 即可完成蒲赂,在性能上相比 Hive 也有 1 個(gè)數(shù)量級(jí)以上的提升(二階回溯阱冶,圖節(jié)點(diǎn):百億級(jí),待回溯節(jié)點(diǎn):10 萬級(jí))滥嘴。

干貨 | 百億節(jié)點(diǎn)木蹬,毫秒級(jí)延遲,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

下面用一個(gè)例子說明:如圖(a)若皱,點(diǎn) A 分別在 t0镊叁、t1、t2 時(shí)刻建立了一條邊走触,t0晦譬、t1、t2為邊 rank 值互广,需要返回 tx 時(shí)的的圖關(guān)系數(shù)據(jù)敛腌,只能返回 t0、t1 對(duì)應(yīng)的點(diǎn) B惫皱、C像樊,因?yàn)楫?dāng)回溯到 tx 時(shí)間點(diǎn)時(shí)候,t2 還沒有發(fā)生旅敷;最終返回的圖關(guān)系為 t0 和 t1 時(shí)候生棍,VertexA ->VertexBVertexA -> VertexC(見圖(c))媳谁。這個(gè)例子是用一種邊進(jìn)行回溯涂滴,實(shí)際查詢中可能會(huì)涉及到 2~3 跳,且存在異構(gòu)邊(打電話是一種邊晴音,點(diǎn)外賣又是一種邊柔纵,下單酒店機(jī)票是一種邊,都是不同類型的邊)锤躁,而這種異構(gòu)圖的數(shù)據(jù)都具有回溯特征首量,因此實(shí)際的關(guān)系人圖回溯查詢也會(huì)變得復(fù)雜。

3.3 實(shí)時(shí)反欺詐圖

干貨 | 百億節(jié)點(diǎn),毫秒級(jí)延遲加缘,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

用戶下單時(shí),會(huì)進(jìn)入一個(gè)快速風(fēng)控的階段:通過基于關(guān)系型數(shù)據(jù)庫和圖數(shù)據(jù)庫的規(guī)則進(jìn)行模型特征計(jì)算觉啊,來判斷這個(gè)用戶是不是風(fēng)險(xiǎn)用戶拣宏,要不要對(duì)該用戶進(jìn)行下單攔截(實(shí)時(shí)反欺詐)。

我們可以根據(jù)圖關(guān)系配合模型規(guī)則杠人,用來挖掘欺詐團(tuán)伙勋乾。比如說,已知某個(gè) uid 是犯欺團(tuán)伙的一員嗡善,根據(jù)圖關(guān)聯(lián)來判斷跟他關(guān)系緊密的用戶是不是存在欺詐行為辑莫。為了避免影響正常用戶的下單流程,風(fēng)控階段需要快速響應(yīng)罩引,因此對(duì)圖查詢的性能要求非常高(P95 < 15 ms)各吨。我們基于 NebulaGraph 構(gòu)建了百億級(jí)的反欺詐圖,在查詢性能的優(yōu)化方面進(jìn)行了較多思考袁铐。

干貨 | 百億節(jié)點(diǎn)揭蜒,毫秒級(jí)延遲,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

此圖 Schema 為脫敏過后的部分圖模型剔桨,當(dāng)中隱藏很多建模信息屉更。這里簡(jiǎn)單講解下部分的查詢流程和關(guān)聯(lián)信息。

如上圖為一次圖查詢流程洒缀,每一次圖查詢由多個(gè)起始點(diǎn)如用戶 uid瑰谜、用戶 mobile 等用戶信息同時(shí)開始,每條線為一次關(guān)聯(lián)查詢树绩,因此一次圖查詢由幾十次點(diǎn)邊查詢組成萨脑,由起始點(diǎn)經(jīng)過一跳查詢和 2 跳查詢,最終將結(jié)果集返回給風(fēng)控引擎葱峡。

系統(tǒng)會(huì)將用戶的信息砚哗,轉(zhuǎn)化為該用戶的標(biāo)簽。在圖查詢的時(shí)候砰奕,根據(jù)這些標(biāo)簽蛛芥,如 uid、mobile 進(jìn)行獨(dú)立查詢军援。舉個(gè)例子仅淑,根據(jù)某個(gè) uid 進(jìn)行一跳查詢,查詢出它關(guān)聯(lián)的 5 個(gè)手機(jī)號(hào)胸哥。再根據(jù)這 5 個(gè)手機(jī)號(hào)進(jìn)行獨(dú)立的 2 跳查詢涯竟,可能會(huì)出來 25 個(gè) uid,查詢會(huì)存在數(shù)據(jù)膨脹的情況。因此庐船,系統(tǒng)會(huì)做一個(gè)查詢限制银酬。去查看這 5 個(gè)手機(jī)號(hào)關(guān)聯(lián)的 uid 是不是超過了系統(tǒng)設(shè)定的熱點(diǎn)值。如果說通過 mobile 查詢出來關(guān)聯(lián)的手機(jī)號(hào)筐钟、uid 過多的話揩瞪,系統(tǒng)就會(huì)判斷其為熱點(diǎn)數(shù)據(jù),不進(jìn)行邊結(jié)果返回篓冲。(二階/三階回溯李破,圖點(diǎn)邊:百億級(jí))。

4.1 痛點(diǎn)及優(yōu)化

在上述應(yīng)用場(chǎng)景中壹将,對(duì)于風(fēng)控關(guān)系人圖和反欺詐圖嗤攻,由于圖規(guī)模比較大(百億點(diǎn)邊),查詢較多诽俯,且對(duì)時(shí)延要求較高妇菱,遇到了一些典型問題,接下來簡(jiǎn)單介紹一下惊畏。

4.1.1 查詢性能問題

為了滿足實(shí)時(shí)場(chǎng)景 2 跳查詢 P95 15 ms 需求恶耽,我們針對(duì)圖 Schema 和連接池以及查詢端做了一些優(yōu)化:

4.1.2 犧牲寫性能換取讀性能

干貨 | 百億節(jié)點(diǎn),毫秒級(jí)延遲颜启,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

首先偷俭,我們來看看這樣的一個(gè)需求:查詢 ID 關(guān)聯(lián)的手機(jī)號(hào),需要滿足對(duì)于這個(gè)手機(jī)號(hào)關(guān)聯(lián)邊不超過 3 個(gè)缰盏。這里解釋下為什么要限制關(guān)聯(lián)邊數(shù)量涌萤,因?yàn)槲覀冋€(gè)體關(guān)聯(lián)邊數(shù)量是有限的,會(huì)有一個(gè)對(duì)于大多數(shù)人的 P95 這樣的閾值邊數(shù)量口猜,超過這個(gè)閾值就是臟數(shù)據(jù)负溪。為了這個(gè)閾值校驗(yàn), 就需要對(duì)每次查詢的結(jié)果再多查詢一跳济炎。

如圖(a)所示川抡,我們需要進(jìn)行 2 次查詢,第一跳查詢是為了查詢用戶 ID 關(guān)聯(lián)的手機(jī)號(hào)须尚,第二跳查詢是為了保證我們的結(jié)果值是合法的(閾值內(nèi))崖堤,這樣每跳查詢最終需要進(jìn)行 2 跳查詢來滿足。如圖給出了圖查詢的 nGQL 2 步偽碼耐床,這種情況下無法滿足我們的高時(shí)效性密幔。如何優(yōu)化呢?看下圖(b) :

干貨 | 百億節(jié)點(diǎn)撩轰,毫秒級(jí)延遲胯甩,攜程金融基于 NebulaGraph 的大規(guī)模圖應(yīng)用實(shí)踐

我們可以將熱點(diǎn)查詢固定在點(diǎn)屬性上昧廷,這樣一跳查詢時(shí)就可以知道該點(diǎn)有多少關(guān)聯(lián)邊,避免進(jìn)行圖 a 中(2)語句驗(yàn)證偎箫。還是以圖 (a)為例木柬,從一個(gè)用戶 ID 開始查詢,查詢他的手機(jī)號(hào)關(guān)聯(lián)镜廉,此時(shí)因?yàn)槭謾C(jī)號(hào)關(guān)聯(lián)的邊已經(jīng)變成了點(diǎn)屬性(修改了 schema)弄诲,圖(a) 2 條查詢語句實(shí)現(xiàn)的功能就可以變成一條查詢 go from $id over $edgeName where $手機(jī)號(hào).用戶id邊數(shù)據(jù) <5 | limit 5

這種設(shè)計(jì)的好處就是娇唯,在讀的時(shí)候可以加速驗(yàn)證過程,節(jié)約了一跳查詢寂玲。帶來的成本是:每寫一條邊塔插,同時(shí)需要更新 2 個(gè)點(diǎn)屬性來記錄點(diǎn)的關(guān)聯(lián)邊情況,而且需要保證冪等(保證重復(fù)提交不會(huì)疊加屬性 +1)拓哟。當(dāng)插入一條邊的時(shí)想许,先去圖里面查詢邊是否存在,不存在才會(huì)進(jìn)行寫邊以及點(diǎn)屬性 +1 的操作断序。也就是我們犧牲了寫性能流纹,來換取讀性能,并通過定期 check 保證數(shù)據(jù)一致违诗。

4.1.3 池化連接降低時(shí)延

第二個(gè)優(yōu)化手段是通過池化連接降低時(shí)延漱凝。Nebula 官方連接池每次進(jìn)行查詢均需要進(jìn)行建立初始化連接-執(zhí)行查詢?nèi)蝿?wù)-關(guān)閉連接。而在高頻(QPS 會(huì)達(dá)到幾千)的查詢場(chǎng)景中诸迟,頻繁的創(chuàng)建茸炒、關(guān)閉連接非常影響系統(tǒng)的性能和穩(wěn)定性。且建立連接過程耗時(shí)平均需要 6 ms阵苇, 比實(shí)際查詢時(shí)長(zhǎng) 1.5 ms 左右高出幾倍壁公,這是不可接受的。因此我們對(duì)官方客戶端進(jìn)行了二次封裝绅项,實(shí)現(xiàn)連接的復(fù)用和共享紊册。最后,將查詢 P95 從 20 ms 降低到了 4 ms快耿。通過合理控制并發(fā)囊陡,我們最終將 2 跳查詢性能控制在 P95 15 ms 。

這里貼下代碼供參考:

public class SessionPool {
 
    /**
     * 創(chuàng)建連接池
     *
     * @param maxCountSession 默認(rèn)創(chuàng)建連接數(shù)
     * @param minCountSession 最大創(chuàng)建連接數(shù)
     * @param hostAndPort     機(jī)器端口列表
     * @param userName        用戶名
     * @param passWord        密碼
     * @throws UnknownHostException
     * @throws NotValidConnectionException
     * @throws IOErrorException
     * @throws AuthFailedException
     */
    public SessionPool(int maxCountSession, int minCountSession, String hostAndPort, String userName, String passWord) throws UnknownHostException, NotValidConnectionException, IOErrorException, AuthFailedException {
        this.minCountSession = minCountSession;
        this.maxCountSession = maxCountSession;
        this.userName = userName;
        this.passWord = passWord;
        this.queue = new LinkedBlockingQueue<>(minCountSession);
        this.pool = this.initGraphClient(hostAndPort, maxCountSession, minCountSession);
        initSession();
    }
 
    public Session borrow() {
        Session se = queue.poll();
        if (se != null) {
            return se;
        }
        try {
            return this.pool.getSession(userName, passWord, true);
        } catch (Exception e) {
            log.error("execute borrow session fail, detail: ", e);
            throw new RuntimeException(e);
        }
    }
 
    public void release(Session se) {
        if (se != null) {
            boolean success = queue.offer(se);
            if (!success) {
                se.release();
            }
        }
    }
 
    public void close() {
        this.pool.close();
    }
 
    private void initSession() throws NotValidConnectionException, IOErrorException, AuthFailedException {
        for (int i = 0; i < minCountSession; i++) {
            queue.offer(this.pool.getSession(userName, passWord, true));
        }
    }
 
    private NebulaPool initGraphClient(String hostAndPort, int maxConnSize, int minCount) throws UnknownHostException {
        List<HostAddress> hostAndPorts = getGraphHostPort(hostAndPort);
        NebulaPool pool = new NebulaPool();
        NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig();
        nebulaPoolConfig = nebulaPoolConfig.setMaxConnSize(maxConnSize);
        nebulaPoolConfig = nebulaPoolConfig.setMinConnSize(minCount);
        nebulaPoolConfig = nebulaPoolConfig.setIdleTime(1000 * 600);
        pool.init(hostAndPorts, nebulaPoolConfig);
        return pool;
    }
 
    private List<HostAddress> getGraphHostPort(String hostAndPort) {
        String[] split = hostAndPort.split(",");
        return Arrays.stream(split).map(item -> {
            String[] splitList = item.split(":");
            return new HostAddress(splitList[0], Integer.parseInt(splitList[1]));
        }).collect(Collectors.toList());
    }
 
    private Queue<Session> queue;
 
    private String userName;
 
    private String passWord;
 
    private int minCountSession;
 
    private int maxCountSession;
 
    private NebulaPool pool;
 
}

4.1.4 查詢端優(yōu)化

對(duì)于查詢端润努,像 3.3 中的例圖关斜,每一次圖查詢由多個(gè)起始點(diǎn)開始,可拆解為幾十次點(diǎn)邊查詢铺浇,需要讓每一層的查詢盡可能地并發(fā)進(jìn)行痢畜,降低最終時(shí)延。我們可以先對(duì) 1 跳查詢并發(fā)(約十幾次查詢),再對(duì)結(jié)果進(jìn)行分類合并丁稀,進(jìn)行第二輪的迭代并發(fā)查詢(十幾到幾十次查詢)吼拥,通過合理地控制并發(fā),可將一次組合圖查詢的 P95 控制在 15 ms 以內(nèi)线衫。

4.2 邊熱點(diǎn)問題

在圖查詢過程中凿可,存在部分用戶 ID 關(guān)聯(lián)過多信息,如黃牛用戶關(guān)聯(lián)過多信息授账,這部分異常用戶會(huì)在每一次查詢時(shí)被過濾掉枯跑,不會(huì)繼續(xù)參與下一次查詢,避免結(jié)果膨脹白热。而判斷是否為異常用戶敛助,則依賴于數(shù)據(jù)本身設(shè)定的閾值,異常數(shù)據(jù)不會(huì)流入下一階段對(duì)模型計(jì)算造成干擾屋确。

4.3 一致性問題

NebulaGraph 本身是沒有事務(wù)的纳击,對(duì)于上文寫邊以及點(diǎn)屬性 +1 的操作,如何保證這些操作的一致性攻臀,上文提到過焕数,我們會(huì)定期對(duì)全量 HIVE 表數(shù)據(jù)和圖數(shù)據(jù)庫進(jìn)行 check,以 HIVE 數(shù)據(jù)為準(zhǔn)對(duì)線上圖進(jìn)行修正刨啸,來實(shí)現(xiàn)最終一致性堡赔。目前來說,圖數(shù)據(jù)庫和 HIVE 表不一致的情況還是比較少的呜投。

5. 總結(jié)與展望

基于 NebulaGraph 的圖業(yè)務(wù)應(yīng)用加匈,完成了對(duì)數(shù)據(jù)血緣、對(duì)關(guān)系人網(wǎng)絡(luò)仑荐、反欺詐等場(chǎng)景的支持雕拼,并將持續(xù)應(yīng)用在金融更多場(chǎng)景下,助力金融業(yè)務(wù)粘招。我們將持續(xù)跟進(jìn)社區(qū)啥寇,結(jié)合自身應(yīng)用場(chǎng)景推進(jìn)圖平臺(tái)建設(shè);同時(shí)也期待社區(qū)版能提供熱升級(jí)洒扎、資源隔離辑甜、更豐富易用的算法包、更強(qiáng)大的 Studio 等功能袍冷。


謝謝你讀完本文 (///▽///)

如果你想嘗鮮圖數(shù)據(jù)庫 NebulaGraph磷醋,記得去 GitHub 下載、使用胡诗、(з)-☆ star 它 -> GitHub邓线;和其他的 NebulaGraph 用戶一起交流圖數(shù)據(jù)庫技術(shù)和應(yīng)用技能淌友,留下「你的名片」一起玩耍呀~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市骇陈,隨后出現(xiàn)的幾起案子震庭,更是在濱河造成了極大的恐慌,老刑警劉巖器联,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婿崭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡氓栈,警方通過查閱死者的電腦和手機(jī)千元,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門颤绕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祟身,“玉大人奥务,你說我怎么就攤上這事⊥嗔颍” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵帚称,是天一觀的道長(zhǎng)秽澳。 經(jīng)常有香客問我担神,道長(zhǎng),這世上最難降的妖魔是什么妄讯? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任亥贸,我火速辦了婚禮,結(jié)果婚禮上荣挨,老公的妹妹穿的比我還像新娘。我一直安慰自己煌抒,他們只是感情好厕倍,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布讹弯。 她就那樣靜靜地躺著,像睡著了一般棒仍。 火紅的嫁衣襯著肌膚如雪臭胜。 梳的紋絲不亂的頭發(fā)上耸三,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音憨颠,去河邊找鬼积锅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛适篙,可吹牛的內(nèi)容都是我干的匙瘪。 我是一名探鬼主播蝶缀,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼翁都,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了柄慰?” 一聲冷哼從身側(cè)響起税娜,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤敬矩,失蹤者是張志新(化名)和其女友劉穎蠢挡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體业踏,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勤家,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了热幔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讼庇。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巫俺,死狀恐怖肿男,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹承,我是刑警寧澤如庭,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布坪它,位于F島的核電站,受9級(jí)特大地震影響蒙揣,放射性物質(zhì)發(fā)生泄漏线罕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一个扰、第九天 我趴在偏房一處隱蔽的房頂上張望递宅。 院中可真熱鬧,春花似錦恐锣、人聲如沸土榴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矢赁。三九已至撩银,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間够庙,已是汗流浹背抄邀。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工境肾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人偶宫。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓环鲤,卻偏偏與公主長(zhǎng)得像楔绞,于是被迫代替她去往敵國(guó)和親唇兑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子桦锄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容