美團 leaf:分散式 ID 解決方案

一、背景介紹

在分散式系統中,很多場景都需要生成唯一的 ID,比如訂單號、用戶 ID 等。由於多個節點並發生成 ID,因此需要保證生成的 ID 具有全局唯一性。傳統的解決方式是使用資料庫生成自增 ID 或者使用 Redis 生成類似自增 ID 的方式,但這種方式在高並發場景下性能會下降。

美團 Leaf 是一個開源的分散式 ID 生成系統,由美團點評公司推出,其默認使用 Snowflake 演算法生成唯一 ID,而且提供了多種 ID 生成方式滿足各種場景需求。同時,Leaf 支持多語言、跨語言調用,並提供了簡單易用的介面。

二、ID 生成演算法

美團 Leaf 默認使用 Snowflake 演算法生成唯一 ID。這種方式的具體實現是:

  1. 使用 64 位長的二進位數據結構存放生成的 ID,其中第 1 個 bit 為不採用,剩下的 63 個 bit 中,第 2-41 個 bit 存放毫秒級時間戳,第 42-51 個 bit 存放數據中心 ID,第 52-63 個 bit 存放機器 ID。
  2. 為每個數據中心和機器分配唯一的 ID。
  3. 使用機器 ID 和數據中心 ID 拼接 10 位長度的二進位數據,將這個數據轉換為 10 位長度的整型數據,作為 Leaf 伺服器在一個數據中心內的唯一標識。
  4. 每次生成 ID 前,根據設定初始時間戳(由管理員配置)計算出當前時間戳,並與上一次計算出來的時間戳之間的時間差(毫秒級)。
  5. 每個 Leaf 伺服器在一個數據中心內,可以保證每個時間戳下生成的 ID 不重複。

三、ID 的生成方式

美團 Leaf 提供了多種 ID 生成方式,可以根據業務需求選擇適合的方式。

1. Snowflake ID 生成方式

這是默認的 ID 生成方式,它使用 Snowflake 演算法生成 ID。

(1)代碼示例:

@IdLeaf("order_leaf")
public class OrderService {
    @Autowired
    private IdGenerator idGenerator;

    public long saveOrder(Order order) {
        long orderId = idGenerator.getId();
        order.setOrderId(orderId);
        orderMapper.save(order);
        return orderId;
    }
}

(2)代碼解釋:

@IdLeaf("order_leaf") 標識了當前業務生成 ID 時使用的 Leaf 實例名為 “order_leaf”。這個實例名在 Leaf 伺服器中需要做單獨配置。

idGenerator.getId() 調用 IdGenerator 介面的方法生成唯一 ID。

2. Snowflake ID 單機版生成方式

這種方式不需要遠程調用 Leaf 伺服器,適合單機使用,首先需要在本地啟動一個 Leaf 服務。在工程中加入 Leaf 的 client 和 protocol 兩個 Jar 包,並添加以下配置:

leaf:
  zkAddress: localhost:2181
  port: 20010

(1)代碼示例:

@Bean
public IdGenerator idGenerator() throws Exception {
    IdGenerator idGenerator = new LeafSegmentIdGenerator();
    Properties properties = new Properties();
    properties.setProperty("leaf.name", "order");
    idGenerator.init(properties);
    return idGenerator;
}

public long saveOrder(Order order) throws Exception {
    long orderId = idGenerator.getId();
    order.setOrderId(orderId);
    orderMapper.save(order);
    return orderId;
}

(2)代碼解釋:

使用了 LeafSegmentIdGenerator 類,這種方式不需要發起遠程請求,可以提高性能。需要指定 Leaf 實例的 name,這個 name 在該 Leaf 服務中需要額外配置。

3. Snowflake ID 跨語言生成方式

由於 Leaf 使用 Thrift 作為 RPC 框架,因此支持多語言調用,同時使用 Thrift 也保證了 Leaf 的高性能。

(1)代碼示例:

Leaf 提供了多種語言的客戶端 API,下面是 Java 和 Python 的客戶端 API 代碼示例。

Java 客戶端:

TTransport transport = new TSocket("localhost", 8080);
transport.open();

TProtocol protocol = new TBinaryProtocol(transport);
SegmentService.Client client = new SegmentService.Client(protocol);

SegmentIdRequest request = new SegmentIdRequest();
request.setBizType("test");
request.setSize(100);
List<SegmentIdResult> resList = client.getId(request);

System.out.println(resList);

Python 客戶端:

from leaf import SegmentIdReq, SegmentService
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

transport = TSocket.TSocket("localhost", 8080)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = SegmentService.Client(protocol)

transport.open()

req = SegmentIdReq(bizType="order", size=5)
result = client.getId(req)

print(result)

(2)代碼解釋:

客戶端通過 RPC 方式請求 Leaf 伺服器,獲取 ID。

4. 派發全局唯一 ID 的方式

除了使用 Snowflake 演算法之外,美團 Leaf 也支持其他方式生成全局唯一 ID,如基於 Redis 實現的全局唯一 ID 生成競賽方案。下面是使用 Redis 方式生成全局唯一 ID 的代碼示例。

(1)代碼示例:

@Autowired
private IdGenerator idGenerator;

public long saveOrder(Order order) {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        String key = "order_id";
        long orderId = jedis.incr(key);
        order.setOrderId(orderId);
        orderMapper.save(order);
        return orderId;
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }
}

(2)代碼解釋:

通過 Redis 原子性操作 incr 自增來實現全局唯一 ID 的生成。

四、使用場景

美團 Leaf 適用於分散式系統中需要生成唯一 ID 的場景。例如:

  • 訂單系統,生成唯一的訂單號
  • 用戶系統,生成唯一的用戶 ID
  • 消息系統,生成唯一的消息 ID

五、總結

美團 Leaf 分散式 ID 解決方案使用簡單,性能高,適用於分散式系統中唯一 ID 的生成,是一種不錯的解決方案。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/227789.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-09 21:21
下一篇 2024-12-09 21:21

相關推薦

發表回復

登錄後才能評論