圖解Janusgraph系列-分散式id生成策略分析
阿新 • • 發佈:2020-09-01
# JanusGraph - 分散式id的生成策略
大家好,我是洋仔,JanusGraph圖解系列文章,`實時更新`~
>本次更新時間:2020-9-1
>文章為作者跟蹤原始碼和檢視官方文件整理,如有任何問題,請聯絡我或在評論區指出,感激不盡!
**`圖資料庫網上資源太少,評論區評論 or 私信我,邀你加入“相簿交流微信群”,一起交流學習!`**
**原始碼分析相關:**
[原始碼相簿-一文搞定janusgraph圖資料庫的本地原始碼編譯(janusgraph source code compile)](https://liyangyang.blog.csdn.net/article/details/106674499)
圖解相簿JanusGraph系列-一文知曉匯入資料流程(待發布)
圖解相簿JanusGraph系列-簡要分析查詢讀資料流程(待發布)
圖解相簿JanusGraph系列-一文知曉鎖機制(本地鎖+分散式鎖)(待發布)
[圖解相簿JanusGraph系列-一文知曉分散式id生成策略](https://mp.weixin.qq.com/s?__biz=MzAwODkwMDk4OQ==&mid=2247483936&idx=1&sn=1b0ebe5699ee267d4b0360c90c937492&chksm=9b669a32ac111324e66af490a24478b81ad5221a88af61897353a6f4d80ff6005b60fbbb8490&scene=126&sessionid=1598925790&key=4598b5ee8f6c495005e73b5167cd30412733226c9d6ce3657d87cabb5291569908596536a55cce3dd7a6aea5825a3376ea9164400735c8294ba829b5fe929c554a15390fbc2cde275c4a553c77f55ee95eda0ccbc57348e1982181a8d10974962f967b290f0cfd7665a5c03e4c9637ce95166cf387b34bbb11239469172c253b&ascene=1&uin=MjMwNTU3MjU4MQ%3D%3D&devicetype=Windows+10+x64&version=62090529&lang=zh_CN&exportkey=AU6RYjWx80jN1DKuoVRSczA%3D&pass_ticket=tfgSbQAaIYvDoARCTj0WD5fc96MDzkEkABiBJf%2FX0t532Z7kIWU5Z3x5qVTyNpkY)
圖解相簿JanusGraph系列-一文知曉相簿儲存分割槽策略(待發布)
**儲存結構相關:**
[圖解相簿JanusGraph系列-一文知曉圖資料底層儲存結構](https://mp.weixin.qq.com/s?__biz=MzAwODkwMDk4OQ==&mid=2247483894&idx=1&sn=0d7b98d8d7abf86bfacf8c86b694651d&chksm=9b6699e4ac1110f2626789d78aaf617dc02b7a9cdad320c5273172a6fa3a21d8f40d63958461&token=2053731774&lang=zh_CN#rd)
**其他:**
[解惑圖資料庫!你知道什麼是圖資料庫嗎?](https://mp.weixin.qq.com/s?__biz=MzAwODkwMDk4OQ==&mid=2247483830&idx=1&sn=71ad0d9e0d5868ae15011b7744c0fe8f&chksm=9b6699a4ac1110b294487a6987be5392a5093405a7a40f58d4bca697a18d64000db1aeda0a6f&token=1631136587&lang=zh_CN#rd)
圖解相簿JanusGraph系列-官方測試圖:諸神之圖分析(待發布)
> **`原始碼分析相關可檢視github(求star~~)`**: [https://github.com/YYDreamer/janusgraph](https://github.com/YYDreamer/janusgraph)
> 下述流程高清大圖地址:[https://www.processon.com/view/link/5f471b2e7d9c086b9903b629](https://www.processon.com/view/link/5f471b2e7d9c086b9903b629)
> 版本:JanusGraph-0.5.2
**轉載文章請保留以下宣告:**
>作者:洋仔聊程式設計
>微信公眾號:匠心Java
## 正文
在介紹JanusGraph的分散式ID生成策略之前,我們來簡單分析一下`分散式ID`應該滿足哪些特徵?
* **全域性唯一**:必須保證ID是分散式環境中全域性性唯一的,這是基本要求
* **高效能**:高可用低延時,ID生成響應快;否則可能會成為業務瓶頸
* **高可用**:提供分散式id的生成的服務要保證高可用,不能隨隨便便就掛掉了,會對業務產生影響
* **趨勢遞增**:主要看業務場景,類似於圖儲存中節點的唯一id就儘量保持趨勢遞增;但是如果類似於電商訂單就儘量不要趨勢遞增,因為趨勢遞增會被惡意估算出當天的訂單量和成交量,洩漏公司資訊
* **接入方便**:如果是中介軟體,要秉著拿來即用的設計原則,在系統設計和實現上要儘可能的簡單
## 一:常用分散式id生成策略
當前`常用的`分散式id的生成策略主要分為以下四種:
* UUID
* 資料庫+號段模式(優化:資料庫+號段+雙buffer)
* 基於Redis實現
* 雪花演算法(SnowFlake)
還有一些其他的比如:基於資料庫自增id、資料庫多主模式等,這些在小併發的情況下可以使用,大併發的情況下就不太ok了
市面上有一些生成分散式id的開源元件,包括滴滴基於`資料庫+號段`實現的`TinyID` 、百度基於`SnowFlake`的`Uidgenerator`、美團支援`號段`和`SnowFlake`的`Leaf`等
那麼,在JanusGraph中分散式id的生成是採用的什麼方式呢?
## 二:JanusGraph的分散式id策略
在JanusGraph中,分散式id的生成採用的是`資料庫+號段+雙buffer優化`的模式; 下面我們來具體分析一下:
分散式id生成使用的資料庫就是JanusGraph當前使用的第三方儲存後端,這裡我們以使用的儲存後端`Hbase`為例;
**JanusGraph分散式id生成所需元資料儲存位置:**
在Hbase中有`column family 列族`的概念; JanusGraph在初始化Hbase表時預設建立了9大列族,用於儲存不同的資料, 具體看《圖解相簿JanusGraph系列-一文知曉圖資料底層儲存結構》;
其中有一個列族`janusgraph_ids`簡寫為`i`這個列族,主要儲存的就是JanusGraph分散式id生成所需要的元資料!
**JanusGraph的分散式id的組成結構:**
```java
// 原始碼中有一句話體現
/* --- JanusGraphElement id bit format ---
* [ 0 | count | partition | ID padding (if any) ]
*/
```
主要分為4部分:`0、count、partition、ID padding(每個型別是固定值)`;
其實這4部分的順序在序列化為二進位制資料時,順序會有所改變;這裡只是標明瞭id的組成部分!
上述部分的`partition` + `count`來保證分散式節點的唯一性;
* partition id:分割槽id值,JanusGraph預設分了32個邏輯分割槽;節點分到哪個分割槽採用的是`隨機分配`;
* count:每個partition都有對應的一個count範圍:0-2的55次冪;JanusGraph每次拉取一部分的範圍作為節點的count取值;JanusGraph保證了針對相同的partition,不會重複獲取同一個count值!
保證count在partition維度保持全域性唯一性,就保證了生成的最終id的全域性唯一性!!
*則分散式id的唯一性保證,就在於`count`基於`partition`維度的唯一性!下面我們的分析也是著重在`count`的獲取!*
**JanusGraph分散式id生成的主要邏輯流程如下圖所示:(推薦結合原始碼分析觀看!)**
> 分析過程中有一個概念為`id block`:指當前獲取的號段範圍
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200814111515476.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NTRE5fX19MWVk=,size_16,color_FFFFFF,t_70#pic_center)
JanusGraph主要使用``PartitionIDPool `類來儲存不同型別的`StandardIDPool`; 在`StandardIDPool`中主要包含兩個id Block:
* current block:當前生成id使用的block
* next block:double buffer中的另一個已經準備好的block
**為什麼要有兩個block呢?**
主要是如果只有一個block的話,當我們在使用完當前的block時,需要阻塞等待區獲取下一個block,這樣便會導致分散式id生成較長時間的阻塞等待block的獲取;
怎麼優化上述問題呢? `double buffer`;
除了當前使用的block,我們再儲存一個`next block`;當正在使用的block假設已經使用了50%,觸發`next block`的非同步獲取,如上圖的藍色部分所示;
這樣當`current block`使用完成後可以直接無延遲的切換到`next block`如上圖中綠色部分所示;
**在執行過程中可能會因為一些異常導致節點id獲取失敗,則會進行重試;重試次數預設為1000次;**
```java
private static final int MAX_PARTITION_RENEW_ATTEMPTS = 1000;
for (int attempt = 0; attempt < MAX_PARTITION_RENEW_ATTEMPTS; attempt++) {
// 獲取id的過程
}
```
> ps:上述所說的IDPool和block是基於當前`圖例項`維度共用的!
## 三:原始碼分析
在JanusGraph的原始碼中,主要包含兩大部分和其他的一些元件:
* Graph相關類:用於對節點、屬性、邊的操作
* Transaction相關類:用於在對資料或者Schema進行CURD時,進行事務處理
* 其他一些:分散式節點id生成類;序列化類;第三方索引操作類等等
Graph和Transaction相關類的類圖如下所示:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200814111528298.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NTRE5fX19MWVk=,size_16,color_FFFFFF,t_70#pic_center)
分散式id涉及到id生成的類圖如下所示:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200814111541787.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NTRE5fX19MWVk=,size_16,color_FFFFFF,t_70#pic_center)
**初始資料:**
```java
@Test
public void addVertexTest(){