本篇導讀
HBaseCon Asia2019 活動於 2019 年 7 月 20 日於北京金隅喜來登酒店舉辦,應主辦方邀請,Nebula Graph 技術總監-陳恆在活動中發表演講 “Nebula: A Graph DB based on HBase” 。本篇文章是根據此次演講所整理出的技術乾貨,全文閱讀需要 30 分鐘。
大家下午好,我是陳恆,來自 VESoft,是開源圖資料庫 Nebula Graph 的開發者。同時,我也是 HBase 的 Commiter(剛才在後面和各位大佬談笑風生),今天和大家分享的,是我們最近剛開源的分散式圖資料庫 Nebula Graph。
Nebula Graph 簡要介紹
首先,介紹一下我們公司:歐若數網科技有限公司(英文名:VESoft),是 2018 年 10 月份成立的。我們的核心產品是分散式圖資料庫 Nebula Graph,這個專案從開始到現在,大概做了半年多時間。目前已經 release alpha 版本,還有可以試用的 docker,正式的 release 預計會在 10 月份。
NebulaGraph 是完全開源的,可以在 GitHub 上訪問 https://github.com/vesoft-inc/nebula
NoSQL 類資料庫的發展趨勢
下面我們看一張圖,是 DB-Engine 的統計,反映了從 2013 年到今年所有的 NoSQL 類資料庫的發展趨勢。橫軸代表的是時間,縱軸可以認為是受眾程度,或者社群裡的討論熱烈程度。大家可以看到綠色的線就是圖資料庫。這些年一共翻了十倍,增長還是非常迅猛的。
圖資料庫的簡要介紹
在座的同事是 HBase 專家,部分可能對於圖資料庫有些不太瞭解,我這裡簡單介紹一下圖資料庫。它的主要應用場景其實是針對於各種各樣的點和邊組成的資料集合。
圖資料庫典型應用場景
舉幾個例子來講,典型圖資料庫的應用場景有以下幾個。
社交場景
社交場景是一個我們常見的社交場景,就是好友之間的關係。這個自然而然構成了一張圖。比如說:在社交場景裡面,做推薦演算法。為某個人推薦他的好友。現在典型的方法都是去找好友的好友,然後看好友的好友有沒有可能成為新的好友。這裡面可能會有各種親密度關係,以及各種各樣的排序。傳統來講,我們可能會利用 MySQL 或者是 HBase 存各種各樣的好友關係,然後通過多個 序列的 Key Value 訪問來查 。但是真正線上上場景裡面的話,是很難滿足效能要求的。所以,另外一種做法是利用 離線計算 。把可能的好友關聯和推薦都離線計算好。然後,查的時候直接去讀已經準備好的資料,但這個問題就在於時效性比較差。對於有一些對於時效性要求比較高的場景,這樣是不可以接受的。後面我有一些 case 可以來談這個事情。
商業關係網路
商業關係網路:資料庫的使用場景除了社交網路外,還有商業關係網路也很常見。在金融和風控領域,商業關係其實是很典型的一張圖,多個公司之間有貿易往來,公司和銀行之間也有往來。比如說一個公司去銀行申請貸null款的時候,銀行在審查這家公司可能本身沒有什麼問題,但是這家公司可能控制或者被控制的其他公司,或者整個集團的其他子公司,早已經進入了黑名單,甚至要控制一組相互擔保的公司之間的總體貸款額度。這個時候就需要構成一些風控的功能來拒掉這筆貸款。商業關係裡面還有人與人之間的轉賬關係,比如去查一個信用卡反套null現的網路。很典型的一個網路社群就是:A 轉賬到 B,B 轉賬到 C,C 又轉讓回 A 就是一個很典型的一個環。更多的黑產可能會是一個很大的黑產社群。對於這樣的閉環,這類查詢在圖資料庫大規模應用之前,大部分都是採用離線計算的方式去找。但是離線場景很難去控制當前發生的這筆交易。例如一個信用卡交易或者線上貸null款,整個作業流程很長,在反套null現這塊的稽核時間可能只有秒級。這也是圖資料庫非常大的一個應用場景。
知識圖譜
知識圖譜:除了商業關係還有一個就是知識圖譜。知識圖譜這個概念提出來已經很早了,大概是在 2004,2005 年的時候,Google 把自己的 search engine 慢慢的從倒排轉到知識圖譜上。這樣在 search 的時候可以回答一些問題,比如說今天的天氣怎麼樣?比如說現在誰的老婆的外甥的二大爺是誰。根據一些類似於問題式的知識,而不是基於關鍵字進行 search。知識圖譜這幾年非常的火,主要的原因就是一些垂直領域,慢慢的發現知識圖譜非常的有價值。比如說:在金融領域上會有自己金融領域的知識圖譜,結合一些 NLP 技術做大量的財報自動分析,或者像 Kensho 這樣的新聞事件驅動自動生成分析報表和投資建議;還可以做一些投資組合,發現一二級市場公司內的關聯關係,財務造假或者地方債暴雷造成的風險傳播。再比如很多做線上教育的同事可能知道,線上教育的領域裡面也有不少知識圖譜。比如說有哪些考點,這個題是屬於哪些考點,考點之間是怎麼關聯起來的,做錯的考點附近的知識點都需要加強,這樣也是一張關係網路。也是圖資料庫一個廣泛應用的場景。
IoT 物聯網(Internet of Things)
IoT 物聯網(Internet of Things)是目前非常火的。以前,每一個裝置都是單純的 Device,裝置和裝置之間是沒有關係的。但是,物聯網的出現打通了這些裝置之間的關係。比如:賬號和裝置都是有繫結關係的,賬號和賬號之間又有一定的關係,通過這樣裝置之間也可以建立出一張網路來。
一般來說,圖資料庫並不是簡單的關聯關係查詢,在圖遍歷的過程,通常要根據屬性做一些計算。所以一個單單的圖關聯是完全不能滿足要求的。舉個例子,這是一個股票新聞實時推薦的場景。
大家知道一般散戶炒股並不是高頻這樣事件驅動的,但是他們也會邊看新聞邊盯著 K線。所以在這個時候要給他們推薦一些什麼新聞呢。一般常見的辦法是爬蟲獲得新聞,清洗完畢後,NLP 分詞,提取出關鍵詞後,然後跟股票程式碼關聯上。一般根據監管,可能還要加上一些編輯稽核和推送。但大家知道中國股市好的時候,是線下口口相傳的。所以有個思路是通過好友圈來推薦新聞:首先會去找使用者的好友,然後這些好友可能瀏覽過一些文章,那麼根據駐留時間等,好友對這個文章可能會有一個評分,這個評分用 WL 來表示。好友和好友之間也有一定的親密度,用 WC 表示。這個親密度可以來源於之前的聊天次數、轉賬次數等。同一個人到一篇文章之間可能會有多條路徑。比如說到第二篇文章,可能會有幾十條路徑。所以說這麼多條路徑的權值之和代表了我和這篇文章的之間的評分。最終給使用者推薦文章的時候,希望是把所有的計算結果做 Top N。從線上的結果來看,轉化效率比其他幾種都要高。
圖資料庫面臨的挑戰
再回到技術底層,圖資料庫面臨的技術挑戰。
低延時高吞吐
一個挑戰就是極低的 latency 和極高的 throughput。比如說查尋好友的好友這樣的兩跳場景,我們的 Nebula Graph 能在十毫秒以內返回,同時能做到單機 10 萬的 pps。
大資料量
另外一個挑戰就是資料量。一個典型的銀行金融圖譜,資料量已經可以達到百 T 規模,大概是幾十億個點和千億條邊的規模。當然,如果圖本身只是存點 ID 和點 ID 之間的關聯關係,這樣的資料量千億級別其實單機也能儲存。但是實際上就像剛才說的,光純點和邊是不夠的,還需要有很多圖屬性做分析,這樣單機是肯定不夠的。另外就是資料量增長的速度相當快,即使今天單機做個 POC 能存下,可能幾個月之後又要擴容了。
複雜的商業邏輯
還有一個挑戰就是現在越來越複雜的商業邏輯,用傳統的資料庫去分析,基本上每一個邏輯都要寫 Java 程式碼來完成查詢資料。我們希望不要那麼依賴於開發人員,分析人員可以像寫 SQL 一樣,自己可以搞定。
高可用
最後一個挑戰就是關於高可用要求。圖資料庫剛開始出現的時候,基本上就是一個二級索引。相當於只快取了點和邊之間的關係,真正的屬性可能是在別的地方(比如 HBase 或者 MySQL 裡面)。Data 本身的正確性和高可用都是都是依賴於這些元件的。但隨著使用場景越來越多,這樣分離的儲存方式效能跟不上,自然就希望資料直接放在圖資料庫裡面。那麼各種傳統資料庫和分散式系統要面臨的技術問題也要解決。比如資料多副本的強一致性問題,ACID。對於圖資料庫的要求越來越多,客戶更希望作為一個資料庫,而不是作為一個索引或者關係 cache。
Nebula Graph 的特點
儲存計算分離
對於 Nebula Graph 來講,有這麼幾個技術特點:第一個就是採用了儲存計算分離的架構。這樣架構主要的考慮其實前面幾個 Talk大家都已經討論了很多,主要好處就是為了上雲或者說 彈性
, 方便單獨擴容
。上午的 Talk:HBase on Cloud 也有提到,業務水位總是很難預測的,一段時間儲存不夠了,有些時候計算不夠了。在雲上或者使用容器技術,計算儲存分離的架構運維起來會比較方便,成本也更好控制。大家使用 HBase 那麼久,這方面的感觸肯定很多。
查詢語言 nGQL
Nebula Graph 的第二個技術特點是它的查詢語言,我們稱為 nGQL,比較接近 SQL。唯一大一點的語法差異就是 不用巢狀
(embedding)。大家都知道巢狀的 SQL,讀起來是非常痛苦的,要從裡向外讀。
支援多種後端儲存
第三個特點就是 Nebula Graph 支援多種後端儲存,除了原生的引擎外,也支援 HBase。因為很多使用者,對 HBase 已經相當熟悉了,並不希望多一套儲存架構。從架構上來說,Nebula Graph 是完全對等的分散式系統。
計算下推
和 HBase 的 CoProcessor 一樣,Nebula Graph 支援資料計算下推。資料過濾,包括一些簡單的聚合運算,能夠在儲存層就做掉,這樣對於效能來講能提升會非常大。
多租戶
多租戶,Nebula Graph是通過多 Space 來實現的。Space 是物理隔離。
索引
除了圖查詢外,還有很常見的一種場景是全域性的屬性查詢。這個和 MySQL 一樣,要提升效能的主要辦法是為 屬性建立索引
,這個也是 Nebula Graph 原生支援的功能。
圖演算法
最後的技術特點就是關於圖演算法方面。這裡的演算法和全圖計算不太一樣,更多是一個子圖的計算,比如最短路徑。大家知道資料庫通常有 OLTP 和 OLAP 兩種差異很大的場景,當然現在有很多 HTAP 方面的努力。那對於圖資料庫來說也是類似,我們在設計 Nebula Graph 的時候,做了一些權衡。我們認為全圖的計算,比如 Page Rank,LPA,它的技術挑戰和 OLTP 的挑戰和對應的設計相差很大。我們希望 Nebula Graph 能夠在 OLTP 這塊提供最好的表現。
Nebula Graph 的架構圖
下面為大家介紹 Nebula Graph 的架構圖:下圖(圖1)是基於原生儲存的,圖3 是基於 HBase 的,有一些不同。
基於原生儲存的架構圖
這條虛線上面是計算層,下面是儲存層。
圖 1:基於原生儲存的架構圖
我們先看下計算層,計算層可以理解為把一個 query 翻譯成真正需要的執行計劃,產生執行計劃之後,到下面儲存層拿需要的資料。這和傳統資料庫非常類似,查詢語言也很類似。這裡面比較重要的事情是查詢優化,除了前面提到的計算下推到儲存層外,目前一個主要的實現是併發執行。
查詢服務架構圖
圖 2:Query Service
舉個例子,查好友的大於 18 歲的好友,可能好友有很多,沒有必要等一度好友都返回後,再去查二度好友。當然應該非同步來做,一度好友部分返回後,就立刻開始二度查詢。有點類似圖計算裡面的 BSP 和 ASP。這個優化對提升效能有非常大作用。對於 Storage 層來說,又分為上面的 Storage Engine 和 KV Store。因為 Nebula Graph 是分散式系統,資料是分片的。目前的分片方法是靜態雜湊,和 HBase 不一樣。主要是因為圖查詢基本都是特定 Prefix 的 Scan,Get 很少。比如一個人的好友這樣,就是同一個 prefix 的 scan。每一個資料分片會通過 RAFT 協議來保證資料的強一致。這和 HBase 寫到底層 HDFS 也不一樣。3 臺機器上的 Partition1 組成一個 Raft Group。Storage Engine 做的事情比較簡單,就是把圖語義的查詢請求翻譯成 KV 的查詢請求。關於圖右邊的 Meta Service,它的主要作用是 schema 管理和叢集管理。Nebula Graph 中的點和邊都是有屬性和版本的,那每個屬性的型別和版本在 MetaService 中統一管理。叢集管理主要用於運維和鑑權目的,負責機器上下線和對使用者做 ACL。
Nebula Graph 基於 HBase 的架構圖
圖 3:基於 HBase 的架構圖
Nebula Graph 的 HBase 版本略微有些不一樣,可以看到虛線往下挪了,Storage Service 嵌入到 Query Engine 裡面,這是因為 HBase 是獨立的服務,Storage Service 程式可以和 Query Engine 放同一臺機器上,直接一對一服務了。另外,因為 HBase 自己有 partition,就沒必要再分一次了。
Nebula Graph 的資料模型和 Schema
下面介紹下 Nebula Graph 的資料模型和 Schema(每種標籤有一組相對應的屬性,我們稱之為 schema)。前面說到 Nebula Graph 是有向屬性圖,點和邊都有各自屬性。點有點屬性,Nebula Graph 裡面稱為 Tag(型別),點可以有多種型別,或者叫多種 Tag。比如一個點既可以是 Tag Person,有屬性姓名、年齡;也是 Tag developer,屬性是擅長的語言。Tag 是可以像類一樣繼承的,一個 Tag 繼承自另外一個 Tag。邊和點略微有點不一樣,一條邊只能有一種型別。但是兩個點之間可以有多種型別的邊。另外,像 TTL 這種功能,Nebula Graph 也是支援的。Nebula Graph 的資料模型和 Schema
這裡需要提一下,對於 HBase 和 Nebula Graph 原生儲存來說,Schema Version 處理上是不一樣的。HBase 是沒有 Schema 的。
強 Schema 最大的好處,是知道這條資料什麼時候結束的,一行有多少屬性是知道的。所以在根據某個版本號取資料的時候,從某一行跳到下一行,不需要對每個屬性都掃描一遍。但如果像 HBase 這樣弱 Schema 系統,效能消耗是非常大。但相應的,問題就來了,如果要支援強 Schema,要變更 Schema 怎麼辦?更改 Schema 在 MySQL 裡面,往往要鎖表的。對於 Nebula Graph 來說,當更改 Schema 時,並不是在原來的資料上進行更改,而是先插入一個新的 Schema,當然這要求寫入資料的時候就要記錄版本號。這樣的話在讀的時候,才能知道要用版本。
再解釋一下關於 Key 的設計,點和邊的 Key 設計是像上面兩行這樣,一個點是一個 Key,一條邊是兩個 Key,這樣的目的是把起點和出邊存在一起,對端的終點和入邊儲存在一起。這樣在查詢的時候,可以減少一次網路。另外,對於 Nebula Graph 原生儲存和 HBase 儲存,屬性採用的儲存方式也是不一樣的。在 HBase 裡面,一個屬性放在一個 Column 裡面。在原生儲存裡面,所有屬性放在一個 Column 裡面。這樣設計的主要原因是,如果使用者使用 HBase 作為底層儲存,其實他更期望 HBase 這張表在別的系統裡面也可以用,所以說我們考慮把它打散開了。
Nebula Graph 查詢語言 nGQL
最後講一下我們的 Query Language:nGQL
我們說它比較類似 SQL,比如說看這個例子,從某一個點開始向外擴充,用 nGQL 來寫就是,GO FROM $id,起始點,然後 OVER edge,沿著某條邊,還可以設定一些過濾條件,比如說,從這個點出發,沿著我的好友邊,然後去拿,裡面年齡大於十八歲的。那要返回哪些屬性?可以用 YIELD,比如說年齡,家庭住址。前面提到,不希望巢狀,巢狀太難讀了,所以作為替代, Nebula Graph 用 PIPE 管道。前一條子查詢的結果,PIPE 給第二條,然後第二條可以 PIPE 給第三條。這樣從前往後讀起來,和我們人的思考順序是一樣的。但是管道只解決了一個輸入源的問題。多個輸入源的時候怎麼辦?Nebula Graph 還支援定義某個變數,這個和儲存過程有點像。像上面這樣,把 $var 定義成一個子查詢的結果,再把這個結果拿去給其他子查詢使用。還有種很常見的查詢是全域性匹配,這個和 SQL 裡面的 SELECT … FROM … WHERE 一樣,它要找到所有滿足條件的點或者邊。我們這裡暫時取名叫做 FIND。大家要是覺得其他名字好也可以在 GitHub 上給我們提 issue。最後就是一些 UDF,使用者自己寫的函式,有些複雜的邏輯用 SQL 可能不好描述,Nebula Graph 也希望支援讓使用者自己寫一些程式碼。因為我們程式碼是 C++ 寫的,再考慮到使用者群體,做資料分析用 Python 比較多,我們考慮先支援 C++ 和 Python。
Q&A
現場參會者提問:你們這個架構是 TinkerPop 的實現嘛?區別在哪裡?
陳恆的回覆如下:
不是的。我們是完全自研的。首先我們查詢語法並不是 Gremlin 那樣命令式的,而是更接近 SQL 這種描述式的。可以說下我們的思考,我們主要考慮了查詢優化的問題。你知道像 Gremlin 那樣的命令式語言,query 是 .in() .out() 這樣一步步組成的,所以查詢引擎只能按照給定的命令一步步把資料撈上來,每次序列化速度都很慢的,像 Titan 那樣。我們的測試結果應該有幾十倍的效能差距。另外既然使用者每步指令是明確的,查詢引擎要做優化很難,要非常智慧推測出使用者整一串指令的最終期望才能優化,這樣難度比較高。這個有點像編譯器的優化,優化錯就很麻煩了。我們希望像 SQL 這樣描述式的,使用者說明最終目的就行,怎麼處理交給執行引擎來優化,這樣做優化比較容易完善,可借鑑的演算法也比較多。當然也和我們以 C++ 做開發語言有關。我們也有想過做 Gremlin 和 nGQL 之間的 driver,主要看社群,歡迎給我們提 issue
上面就是本次 Nebula Graph 參會 HBaseCon Asia2019 的全部內容,最後和大家再說下 Nebula Graph 是完全開源的專案,對於圖資料庫比較感興趣的同學可以加 wechat 討論群,或者在 GitHub 上提 Issue,也歡迎大家給我們支援 star 專案。
Nebula Graph:一個分散式,可擴充套件,快速的圖形資料庫,目前已開源。
GitHub:https://github.com/vesoft-inc/nebula
知乎:https://www.zhihu.com/org/nebulagraph/posts
微博:http://weibo.com/nebulagraph