首頁(yè)常見問題正文

集群高并發(fā)環(huán)境下如何保證分布式唯一全局ID生成?

更新時(shí)間:2023-05-22 來源:黑馬程序員 瀏覽量:

IT培訓(xùn)班

  在集群高并發(fā)環(huán)境下保證分布式唯一全局ID生成,可以使用雪花算法(Snowflake)來實(shí)現(xiàn)。雪花算法是Twitter提出的一種分布式ID生成算法,可以在分布式系統(tǒng)中生成唯一的、遞增的ID。接下來我們通過一段Python代碼來演示一下:

import time

class SnowflakeIDGenerator:
    def __init__(self, worker_id, datacenter_id, sequence_bits=12):
        self.worker_id = worker_id
        self.datacenter_id = datacenter_id
        self.sequence_bits = sequence_bits
        
        self.worker_id_bits = 5
        self.datacenter_id_bits = 5
        
        self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
        self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
        self.max_sequence = -1 ^ (-1 << self.sequence_bits)
        
        self.worker_id_shift = self.sequence_bits
        self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
        self.timestamp_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
        
        self.sequence = 0
        self.last_timestamp = -1
        
        if self.worker_id > self.max_worker_id or self.worker_id < 0:
            raise ValueError("Worker ID must be between 0 and {}".format(self.max_worker_id))
        if self.datacenter_id > self.max_datacenter_id or self.datacenter_id < 0:
            raise ValueError("Datacenter ID must be between 0 and {}".format(self.max_datacenter_id))
    
    def generate_id(self):
        timestamp = self._get_timestamp()
        
        if timestamp < self.last_timestamp:
            raise ValueError("Invalid system clock. Clock moved backwards.")
        
        if timestamp == self.last_timestamp:
            self.sequence = (self.sequence + 1) & self.max_sequence
            if self.sequence == 0:
                timestamp = self._wait_next_millisecond(self.last_timestamp)
        else:
            self.sequence = 0
        
        self.last_timestamp = timestamp
        
        generated_id = (
            (timestamp << self.timestamp_shift) |
            (self.datacenter_id << self.datacenter_id_shift) |
            (self.worker_id << self.worker_id_shift) |
            self.sequence
        )
        
        return generated_id
    
    def _get_timestamp(self):
        return int(time.time() * 1000)
    
    def _wait_next_millisecond(self, last_timestamp):
        timestamp = self._get_timestamp()
        while timestamp <= last_timestamp:
            timestamp = self._get_timestamp()
        return timestamp

  使用示例:

generator = SnowflakeIDGenerator(worker_id=1, datacenter_id=1)

for _ in range(10):
    generated_id = generator.generate_id()
    print(generated_id)

  這段示例代碼演示了使用雪花算法生成唯一全局ID的過程。在創(chuàng)建SnowflakeIDGenerator對(duì)象時(shí),需要指定worker_id和datacenter_id,它們分別用于標(biāo)識(shí)工作節(jié)點(diǎn)和數(shù)據(jù)中心。然后,通過調(diào)用generate_id()方法即可生成一個(gè)唯一的ID。

  請(qǐng)注意,這只是一個(gè)基本示例代碼,并沒有包含高并發(fā)環(huán)境下的分布式鎖機(jī)制。在實(shí)際的生產(chǎn)環(huán)境中,我們可能需要使用分布式鎖來確保在高并發(fā)環(huán)境下確保分布式唯一全局ID生成,我們可以結(jié)合雪花算法和分布式鎖機(jī)制來實(shí)現(xiàn)。以下是一個(gè)使用Redis作為分布式鎖的示例代碼:

import time
import redis

class SnowflakeIDGenerator:
    def __init__(self, worker_id, datacenter_id, sequence_bits=12):
        # 初始化雪花算法相關(guān)參數(shù)
        
        # 初始化Redis連接
        self.redis_client = redis.Redis(host='localhost', port=6379)
        
        # 其他參數(shù)...
    
    def generate_id(self):
        lock_key = 'id_generator_lock'
        
        # 獲取分布式鎖
        acquired_lock = self.redis_client.set(lock_key, 'lock', nx=True, ex=10)
        if not acquired_lock:
            raise ValueError("Failed to acquire the distributed lock.")
        
        try:
            # 生成ID邏輯...
            generated_id = ...
            
            return generated_id
        finally:
            # 釋放分布式鎖
            self.redis_client.delete(lock_key)

  在示例代碼中,我們使用了Redis作為分布式鎖的實(shí)現(xiàn)。在generate_id()方法中,首先嘗試獲取分布式鎖,即在Redis中設(shè)置一個(gè)特定的鍵(lock_key),并指定nx=True參數(shù)以確保只有一個(gè)線程能夠成功設(shè)置該鍵。如果獲取鎖成功,就可以執(zhí)行生成ID的邏輯;否則,拋出異?;蜻M(jìn)行相應(yīng)的處理。

  在生成ID的邏輯中,我們可以繼續(xù)使用雪花算法的代碼邏輯,生成唯一的全局ID。在方法最后,無論是否生成成功,都需要釋放分布式鎖,即從Redis中刪除相應(yīng)的鍵。

  需要注意的是,示例中使用了Redis作為分布式鎖的實(shí)現(xiàn),我們可以根據(jù)自己的實(shí)際情況選擇合適的分布式鎖實(shí)現(xiàn)方式,如ZooKeeper、etcd等。另外,示例代碼中省略了部分參數(shù)和細(xì)節(jié)實(shí)現(xiàn),我們可以根據(jù)自己的需求進(jìn)行適當(dāng)?shù)男薷暮脱a(bǔ)充。

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!