1、為什么需要圖數據庫
我們假設這樣一種特殊的查詢場景:找出開發商是XXX,小區綠化率大於30%,周邊200米有大型超市,500米有地鐵,1000米有三甲醫院,2000米有升學率超過60%的高中,房價在800W以內,最近被經紀人帶看次數最多的房子。
這可能是一個客戶想要的房子,但是各位覺得有哪個產品可以支持么?
如果說我們用傳統的關系型數據庫,MySQL或者Oracle可以嗎?那是不是我們要關聯房源表、客戶表、經紀人表、開發商表等等,一次關聯幾十張表才可能得到想要的結果?但明顯這是不現實的;
那ES ( Elasticsearch ) 可以嗎?ES在搜索領域非常火,它可以解決嗎?其實ES也是解決不了的,ES要搜這樣的房源,肯定是需要有一張很寬的房源表
那怎么搜索這套房源周邊200米有大型超市?難道要建距離周邊超市的距離這樣一個字段嗎?顯然也是不現實的;
HBase更不用說了。
所以顯而易見這種行業圖譜的數據只能使用圖數據庫,比如Neo4j這樣的存儲引擎才可以支持。
2、圖數據庫
什么事圖數據庫
- 不是存儲圖片的數據庫
- 存儲節點和關系,以圖結構存儲和查詢
應用場景很廣,包括:
- 社交網絡、計算機網絡、道路網絡、電信網絡
- 關聯查詢、搜索推薦
- 風險預測、風控管理
- 業務流程、生物流程
- 公司或市場結構
- 事件及其之間的因果關系或其他聯系
3、圖數據庫技術選型
主要關注一下幾個方面:
- 開源
- 成熟度
- 可擴展
- 文檔豐富度
- 性能
- 穩定性
- 運維成本
- 易用性
前面看到圖數據庫雖然有很多種,但實際上開源的、流行的圖數據庫就只有以下幾種:
- Neo4j
- OrientDB
- ArangoDB
- JanusGraph
- Dgraph
Neo4j實際上是用來做對比的
OrientDB和ArangoDB都是老牌的圖數據庫了,發展比較早,從2012、2013年就開始做了
JanusGraph和Dgraph是比較新的,從2016、2017年才開始做。
3.1 主流圖數據庫對比
Neo4j歷史悠久,且長期處於圖數據庫領域的龍頭地位,那為什么不考慮它呢?原因很簡單,因為它開源的社區版本只支持單機,不支持分布式。
OrientDB和ArangoDB它們起步比較早,最初的時候都是一個單機的圖數據庫,然后隨着用戶數據量的不斷增加,后期增加了分布式模式,支持集群和副本,但是經過調研發現,可能是由於后加的功能,他們的分布式支持的不是很好。
所以主要注意力放到了JanusGraph和Dgraph上,他們發展的比較晚,從設計之初就考慮了分布式和擴展性,所以對分布式支持的非常好,也都是完全的開源免費,存儲數據模型也都是專為圖數據而設計。
他們有一個比較大的區別就是,JanusGraph的存儲需要依賴於其他存儲系統,而Dgraph使用自身的存儲系統,這就造成了前面提到的運維成本的問題。
例如:JanusGraph多數使用HBase作為底層存儲系統,而HBase又依賴於Zookeeper和HDFS,另外JanusGraph的索引又依賴於ES,所以想要搭建一套完整的JanusGraph,需要同時搭建維護好幾套系統,維護成本非常大;而Dgraph這些都是原生支持的,所以相對來說,Dgraph維護成本低很多。
3.2 JanusGraph架構
JanusGraph的存儲系統依賴於像Cassandra、HBase、BerkelyDB等等這樣的存儲系統,索引系統依賴於Elasticsearch、Solr、Lucene等等;
基於這些原因,它和大數據生態結合的非常好,可以很好地和Spark結合做一些大型的圖計算
缺點:就是它的維護成本會非常高,依賴於這么多的外部系統,搭建一套JanusGraph系統的同時需要搭建好幾套依賴系統
另一方面就是穩定性,根據經驗來看,系統越復雜,依賴系統越多,整體可控性就越差,穩定性風險就越大
3.3 Dgraph架構
- zero:集群大腦,用於控制集群,將服務器分配到一個組,並均衡數據。通過raft選主;相當於hadoop的namenode或者Elasticsearch的master。
- alpha:存儲數據並處理查詢,托管謂詞和索引,即datanode。
- group:多個alpha組成一個group,數據分片存儲到不同group,每個group內數據通過raft保證強一致性。
- ratel:可視化界面,用戶可通過界面來執行查詢,更新或修改schema。
- 同時Dgraph還支持gRPC或者HTTP來連接alpha進行寫入或查詢。
Dgraph只有一個可執行文件,通過指定不同的參數在不同的機器上啟動,就能自動組成集群,無需搭建維護其他任何第三方系統,這是它的優勢。
那是不是就能通過這樣的架構對比,因Dgraph運維簡單就直接選擇它呢?
肯定不行,我們還需要做一些性能壓測來對比,如果說JanusGraph的性能是Dgraph的好幾倍,那維護成本高些也是可以接受的。所以基於這個目的,我們對這兩個圖數據庫做了詳細的性能對比測試。
3.4 JanusGraph和Dgraph性能對比
可以看出Dgraph相對JanusGraph的查詢性能的優勢是非常大的。
3.5 JanusGraph vs Dgraph
4、Dgraph原理
- 存儲引擎
Dgraph的存儲引擎是自研的Badger,完全由Go語言開發。
最初Dgraph存儲也是使用RocksDB,但是后來上層通過GO調用,出現內存溢出問題,於是Dgraph團隊就用Go實現了一個高效的、持久化的,基於LSM的鍵值數據庫,並且號稱隨機讀比RocksDb快3.5倍
- 存儲結構(因為存儲引擎是KV,所以存儲結構也是KV)
(Predicate, Subject) --> [sorted list of ValueId],Key是由謂詞和主語組成的,Value是一個有序的數組。
例如:
(friend, me)-->[person1, person2, person3, person4, person5],
Key是friend和me,friend是關系,me是主語,這樣組成的一個Key;
Value是有序的,me的所有friend,從person1、person2到person5這些ID組成的一個有序的數組
基於這樣的底層存儲結構設計,Dgraph同一個謂詞下的所有數據都存儲在同一個數據結點甚至同一個數據塊中,所以這樣查詢一個謂詞數據時候,只需要一次RPC調用就可以拿到這個謂詞下面全部需要的數據,對於后面的一度、二度、多度的關聯查詢有非常大的性能提升,這是它核心的優勢。
- 數據分片(作為一個分布式系統,要想平滑的擴展,必須要支持數據分片)
根據謂詞分片,相同謂詞的數據按序存儲在同一個節點,減少RPC,提升查詢性能,不同謂詞可能是在不同的節點
定期數據均衡(rebalance-interal),zero節點會定期的檢測各個節點的數據是否均衡,如果某個節點數據過大或者過小,會導致查詢的性能下降,因此zero節點會盡量在保證每個節點的數據均衡
group根據replicas和alpha啟動順序確定,因為Dgraph的副本一致性是依賴Raft協議,所以要保證至少三個節點,才能保證數據的強一致性
- 高可用
每個group至少3個alpha,互為副本,raft協議保證強一致性;每個group中的alpha的數據保持一致,這樣某個alpha節點掛了,可以通過其他的alpha進行數據恢復
write-ahead logs,預寫日志;分布式很常見的WAL機制,為了提升寫入性能,一定是先寫緩存后刷磁盤的,不會直接寫磁盤的,那樣性能會非常低,但先寫內存后寫磁盤會帶來一個問題,一旦機器掛掉了,內存數據沒有刷到磁盤中,那這部分數據就會丟失。因此大部分分布式系統,
比如:HBase、Elasticsearch、Dgraph等都是數據寫內存之前,先預寫日志,日志會實時刷到磁盤上,然后再將數據寫內存,一旦內存中數據丟失了,可以通過磁盤上的日志回放這些數據,從而保證高可用性
5、Bulk Loader優化
其實我們對於Dgraph的研究也僅僅只有幾個月而已,所以目前只是做了一些小的優化:480億的行業圖譜如何快速的導入到集群中?
最開始使用Java客戶端寫入,發現這種方法性能非常低,完全寫完可能需要整整一周的時間;
然后使用Dgraph的Bulk Loader寫入,先生成索引數據,再通過alpha節點加載,最后啟動集群來提供服務,這種方式需要48小時才能全部寫入完成,時間也有點長,是否還能進一步優化提升速度呢?
於是我們研究了一下Bulk Loader的源碼,發現只是一個簡單的Map Reduce過程,但他是在單機上執行的,使用單機執行是因為它要分配一個全局唯一的UID,為了保證UID的唯一性和順序性而選擇單機執行,使用單機多線程,啟動多個Map和Reduce線程,然后每個線程生成Shard文件,最后通過Dgraph的alpha加載數據。於是基於對源碼的理解,我們發現是可以優化的,Dgraph原本作為分布式系統,各種查詢寫入都是可以做線性擴展的,不能說最初的批量導入只能是一個單機的模塊。
所以我們對源碼進行了一定的優化,將原來的單機多線程改為了多機多線程模式,首先通過Partition模塊,為原來的每條數據分配一個UID,這塊還是單機執行的,把相同group的數據分到一個數據塊中;然后把這些數據塊分發到不同機器上,每台機器上都可以啟動原來的Map進程和Reduce進程,每台機器都可以生成Dgraph需要的數據文件,再在每台機器上啟動alpha進程加載這些數據文件,直至整個集群啟動成功為止。這樣把480億三元組的數據初始化導入從48小時提升到了15小時,提升了三倍性能。
6、Dgraph不足
那Dgraph性能這么好,運維又簡單,是不是就可以說Dgraph是一個完美的圖數據庫呢?是不是所有的場景都可以用Dgraph來支持呢?顯然不是的,沒有最完美的系統,只有最適合你業務的系統;就像沒有最完美的人,只有最適合你的人一樣。Dgraph也是有它的缺陷和不足的:
- 不支持多重邊
就是說任意一對頂點,相同標簽類型的邊只允許存在一條;在JanusGraph中,兩個頂點確定之后,是允許存在多重邊的。比如:Dgraph中,我和你是同學關系,那只能有一條叫同學關系的邊;但在JanusGraph中,我和你可以同時是小學同學、中學同學、大學同學,有三條同學關系的邊。
- 一個集群只支持一個圖
目前Dgraph一個集群只支持一個圖,支持多圖這個功能官方正在開發中,后期會支持;目前對貝殼的影響還不大,貝殼的圖譜都是比較大的、隔離的,比如行業圖譜480億本身就是需要一個單獨的集群的,不會和其他圖譜共用,目前還夠不成太大的問題。后期自然是希望官方可以盡快的支持了。
- 大數據生態兼容不夠
不像JanusGraph和大數據生態兼容的那么好,因為JanusGraph本身就是基於HBase存儲的;Dgraph本身使用Go開發,使用Spark對它進行大並發寫的時候,會出現overload的狀態。
- 不是很成熟
Dgraph從2016年開始做,總結下來並不是很成熟,有很多小問題,但是更新也比較快,很多問題很快就修復了。
總結一下,就是沒有最完美的系統,只有最合適的系統