Loading

【雪花算法】原理及php案例

雪花算法(Snowflake Algorithm)是一种高效的分布式唯一 ID 生成算法,由 Twitter 开源。以下是 PHP 中雪花算法的实现及原理详解:

雪花算法原理

64 位 ID 组成 :雪花算法生成的 ID 是一个 64 位的整数,从高位到低位依次为 1 位符号位(固定为 0,表示正数)、41 位时间戳(记录创建 ID 的时间,精确到毫秒,可确保 69 年内的唯一性)、10 位数据中心 ID(标识不同的数据中心,范围 0-1023)、10 位机器 ID(标识同一数据中心内的不同机器,范围 0-1023)、12 位序列号(确保同一毫秒内生成的 ID 唯一,范围 0-4095)。

PHP 实现代码

class SnowflakeID
{
    private $twepoch = 1288834974657L;
    private $datacenterIdBits = 5;
    private $machineIdBits = 5;
    private $maxDatacenterId = -1 ^ (-1 << $datacenterIdBits);
    private $maxMachineId = -1 ^ (-1 << $machineIdBits);
    private $sequenceBits = 12;
    private $machineIdShift = 12;
    private $datacenterIdShift = 22;
    private $timestampLeftShift = 32;
    private $sequenceMask = -1 ^ (-1 << $sequenceBits);
    private $lastTimestamp = -1L;
    private $sequence = 0L;
    private $datacenterId = 0L;
    private $machineId = 0L;
 
    public function __construct($datacenterId, $machineId)
    {
        if ($datacenterId > $this->maxDatacenterId || $datacenterId < 0) {
            throw new Exception('Datacenter ID can\'t be greater than ' . $this->maxDatacenterId . ' or less than 0');
        }
        if ($machineId > $this->maxMachineId || $machineId < 0) {
            throw new Exception('Machine ID can\'t be greater than ' . $this->maxMachineId . ' or less than 0');
        }
        $this->datacenterId = $datacenterId;
        $this->machineId = $machineId;
    }
 
    public function nextId()
    {
        $timestamp = $this->timeGen();
 
        if ($timestamp < $this->lastTimestamp) {
            throw new Exception('Clock moved backwards. Refusing to generate id.');
        }
 
        if ($this->lastTimestamp == $timestamp) {
            $this->sequence = ($this->sequence + 1) & $this->sequenceMask;
            if ($this->sequence == 0) {
                $timestamp = $this->tilNextMillis($this->lastTimestamp);
            }
        } else {
            $this->sequence = 0L;
        }
 
        $this->lastTimestamp = $timestamp;
 
        return (($timestamp - $this->twepoch) << $this->timestampLeftShift) |
               ($this->datacenterId << $this->datacenterIdShift) |
               ($this->machineId << $this->machineIdShift) |
               $this->sequence;
    }
 
    private function tilNextMillis($lastTimestamp)
    {
        $timestamp = $this->timeGen();
        while ($timestamp <= $lastTimestamp) {
            $timestamp = $this->timeGen();
        }
        return $timestamp;
    }
 
    private function timeGen()
    {
        return round(microtime(true) * 1000);
    }
}

使用示例

// 创建雪花算法实例
$datacenterId = 1; // 数据中心 ID
$machineId = 1;    // 机器 ID
$snowflake = new SnowflakeID($datacenterId, $machineId);
 
// 生成 ID
for ($i = 0; $i < 10; $i++) {
    $userId = $snowflake->nextId();
    echo "生成的用户 ID: $userId" . "<br/>";
}


关键点说明

时间戳处理 :通过 timeGen 方法获取当前时间戳(毫秒级),并与上一次生成 ID 的时间戳比较。如果时间戳未变,则序列号加 1;若序列号达到上限(4095),则等待下一个毫秒。

唯一性保证 :时间戳、数据中心 ID、机器 ID 和序列号的组合确保了生成的 ID 在分布式环境下的唯一性。时间戳的 41 位可保证 ID 的趋势递增。

异常处理 :如果检测到系统时钟回拨,会抛出异常,避免生成重复 ID。

posted @ 2025-06-17 17:36  Carvers  阅读(133)  评论(0)    收藏  举报