ZooKeeper 實現分散式 ID

1。 前言

在我們使用資料庫進行資料儲存時,會給資料加上唯一標識,也就是我們常說的 ID,透過唯一的 ID, 我們可以精確的定位到每一條資料,設定 ID 常用的方式有 MySQL 的主鍵自增,UUID,雪花演算法等。

除了資料庫的資料需要進行唯一標識的設定之外,在分散式環境中,叢集中的每一個服務或者分散式服務的地址列表,我們都可以為它們設定唯一標識 ID,透過這個 ID 我們可以更方便的獲取它們的服務提供者的資訊和地址列表等資料。

本節我們就來學習如何使用 Zookeeper 來生成分散式的全域性唯一 ID。

2。 分散式 ID

在使用 Zookeeper 生成分散式的全域性唯一 ID 之前,我們先來了解什麼是分散式 ID,為什麼要使用分散式 ID ,以及分散式 ID 的實現方式有哪些。

分散式 ID,也就是在分散式的環境下,全域性的唯一的 ID 。那麼我們為什麼要使用分散式 ID 呢?

在單體結構的應用中,我們可以使用 MySQL 資料庫的主鍵自增來為我們的資料設定唯一標識 ID,但是在分散式環境中,單個數據庫的吞吐量成為整個應用的效能瓶頸,我們就可以搭建資料庫叢集來提升資料庫的效能,此時如果還使用 MySQL 的主鍵自增來設定資料 ID 的話,就會出現重複的 ID,這樣就會出現主鍵衝突的情況。

如果使用分散式的全域性唯一 ID 就不用擔心會出現這個問題了。那麼分散式 ID 的實現方式有哪些呢?接下來我們就對分散式 ID 的實現方式進行介紹。

2。1 分散式 ID 的實現方式

本小節我們來簡單介紹一下常用的分散式 ID 的實現方式,例如:UUID,Redis,雪花演算法等。

UUID

Universally Unique Identifier 通用唯一識別符號,由 32 個字元組成,採用 16 進位制進行編碼,定義了在時間和空間都完全唯一的系統資訊。在 Java 中可以使用 java。util。UUID 的 randomUUID() 方法來獲得:

java

util

UUID

randomUUID

()。

toString

();

程式碼塊

1

UUID 可以在本地生成,生成速度快,不依賴網路和其它服務,但是 UUID 沒有可以識別的特點,也沒有順序性。

Redis 實現分散式 ID

我們都知道 Redis 的效能非常高,而且還可以搭建叢集。我們可以使用 Redis 的 Incr 命令來把 中 key 的數值加 1 並返回,如果這個 key 不存在,則 key 值會被初始化為 0,再執行 Incr 命令來進行加 1 操作。

// 使用 incr(key) 來讓 key 加 1

long id

=

jedis

incr

“id”

);

程式碼塊

12

使用 Redis 的方式生成分散式 ID 需要依賴 Redis 服務,還要保證 Redis 的高可用,否則 Redis 服務宕機會影響整個應用。

雪花演算法

SnowFlake 雪花演算法是 Twitter 公司推出的⼀個⽤於⽣成分散式 ID 的策略,基於這個演算法可以生成 64 位 Long 型的 ID,它是由 1 位符號位,41 位的時間戳毫秒數,10 位的機器 ID,12 位的序列號這 4 種元素來組成的。理論上,雪花演算法每秒可以生成 400 多萬個 ID,完全可以支撐住分散式環境下高併發的場景。一些公司在雪花演算法的基礎上實現了自己的分散式 ID 的演算法,比如:滴滴的 Tinyid,百度的 UidGenerator,美團的 Leaf 等。

簡單介紹了一些分散式 ID 的實現方式,接下來我們就使用 Zookeeper 來實現分散式 ID 。

3。 Zookeeper 實現分散式 ID

在 Zookeeper 中,我們可以使用 Zookeeper 的 順序節點來完成分散式 ID 的生成。這裡我們來回顧一下順序節點的特性。

順序節點,在 Zookeeper 客戶端建立順序節點時,Zookeeper 會根據建立的時間順序,在節點名稱後新增 10 位的順序編號。

這裡我們使用在 Zookeeper Curator 一節建立的 Spring Boot 測試專案來進行測試:

@SpringBootTestclass CuratorDemoApplicationTests { @Autowired private CuratorService curatorService; @Test void contextLoads() throws Exception { // 獲取客戶端 CuratorFramework client = curatorService。getCuratorClient(); // 開啟會話 client。start(); // 第一次建立 /wiki- String s = client。create()。 creatingParentsIfNeeded()。 withMode(CreateMode。PERSISTENT_SEQUENTIAL)。 forPath(“/wiki-”); // 輸出第一次建立的 /wiki- System。out。println(s); // 第二次建立 /wiki- String s1 = client。create()。 creatingParentsIfNeeded()。 withMode(CreateMode。PERSISTENT_SEQUENTIAL)。 forPath(“/wiki-”); // 輸出第二次建立的 /wiki- System。out。println(s1); // 第三次建立 /wiki- String s2 = client。create()。 creatingParentsIfNeeded()。 withMode(CreateMode。PERSISTENT_SEQUENTIAL)。 forPath(“/wiki-”); // 輸出第三次建立的 /wiki- System。out。println(s2); // 關閉客戶端 client。close(); }}

執行測試方法。控制檯輸出:

/wiki-0000000000/wiki-0000000001/wiki-0000000002

我們可以觀察到,每個

/wiki-

節點後都增加了 10 位的順序編號,而且都是按照新增順序來進行編號的。

再加上我們在建立 Curator 客戶端時設定的名稱空間

imooc

,就可以形成完整的節點路徑

/imooc/wiki-0000000000

,這個完整的路徑就可以當作我們的分散式 ID 了,而且這樣我們也能根據名稱空間來區別不同的業務模組,還可以新增不同的名稱空間來擴充套件不同的業務模組。

ZooKeeper 實現分散式 ID

4。 總結

在本節內容中,我們學習了什麼是分散式 ID ,在分散式環境下為什麼要使用分散式 ID,我們還介紹了幾種常用的分散式 ID 實現方式,以及它們的優缺點,最後我們回顧了 Zookeeper 順序節點, 並使用 Zookeeper 的順序節點的特性實現了分散式 ID 的生成。以下是本節內容的總結:

為什麼要使用分散式 ID 。

分散式 ID 實現方式。

使用 Zookeeper 的順序節點實現分散式 ID