雪花算法snoflake

开发的大多数项目并未接触到百万级并发,但是一直以来有个id生成的纠结。我一般就是年月日+随机数生成唯一id,一般来说生成一个备用随机数据,不重复每次一次取值隔天重新从第一个开始取。虽然是可以解决,总感觉这个有点繁琐,仔细查查资料研究了一下,在这里有提到uuid、Vesta、Twitter-Snowflake等。从文章中uuid在php中已经有专门的扩展或者写法生成唯一字符串在大并发数据中处理效率还是不够好。其他几中方法有用到数据库……
这对雪花算法我查了查资料发现还是值得操作一番。

雪花算法的基本描述

1.最高位是符号位,始终为0,不可用。 
2.41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
3.10位的机器标识,10位的长度最多支持部署1024个节点。
4.12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。

根据以上描述及参考雪花算法及运用PHP、基于php的雪花算法等内容我的本地测试
代码如下:

 $this->max_data_center) {
        throw new Exception('数据中心编号取值错误,取值范围为:0-' . $this->max_data_center);
    }
    if ($unix_id > $this->max_unix) {
        throw new Exception('机器编号取值错误,取值范围为:0-' . $this->max_unix);
    }
    $this->data_center_id = $data_center_id;
    $this->unix_id = $unix_id;
}

public function generateId()
{
    $sign = 0;
    $unix_time = $this->getUnixTime();
    //判断时间戳
    if ($unix_time < $this->last_time) {
        throw new Exception('当前时间不能小于最后一次时间!');
    }
    if ($unix_time == $this->last_time) {
        $serial = ++$this->serial;
        if ($serial == $this->max_serial) {
            $unix_time = $this->getUnixTime();
            while ($unix_time <= $this->last_time) {
                $unix_time = $this->getUnixTime();
            }
            $this->serial = 0;
            $serial = ++$this->serial;
        }
    } else {
        $this->serial = 0;
        $serial = ++$this->serial;
    }
    $this->last_time = $unix_time;
    $time = (int)($unix_time - self::EPOCH_OFFSET);
    $id = ($sign << $this->sign_left_shift) | ($time << $this->time_left_shift)
        | ($this->data_center_id << $this->data_center_left_shift)
        | ($this->unix_id << $this->unix_left_shift) | $serial;
    return $id;
}

public function getUnixTime()
{
    return floor(microtime(true) * 1000);
}
}

$data=new snowflake(1,1);
$get_id=$data->generateId();

echo $get_id.PHP_EOL;

谢谢你支持我!

支付宝
微信

你可能感兴趣的:(雪花算法snoflake)