php实现雪花算法(ID递增)

发布时间:2022-04-30 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了php实现雪花算法(ID递增)脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

雪花算法简单描述:

最高位是符号位,始终为0,不可用。
41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个重要的作用是可以根据时间进行排序。
10位的机器标识,10位的长度最多支持部署1024个节点。
12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。
看的出来,这个算法很简洁也很简单,但依旧是一个很好的ID生成策略。其中,10位器标识符一般是5位IDC+5位machine编号,唯一确定一台机器。

<?PHP

namespace app\helPErs;

/**
 * 雪花算法类
 * @package app\helpers
 */
class SNowFlake
{
    const EPOCH_OFFSET = 0;  //偏移时间戳,该时间一定要小于第一个id生成的时间,且尽量大(影响算法的有效可用时间)

    const SIGN_BITS = 1;        //最高位(符号位)位数,始终为0,不可用
    const TIMESTamP_BITS = 41;  //时间戳位数(算法认41位,可以使用69年)
    const DATA_center_BITS = 5;  //IDC(数据中心)编号位数(算法认5位,最多支持部署32个节点)
    const MACHINE_ID_BITS = 5;  //机器编号位数(算法认5位,最多支持部署32个节点)
    const SEQUENCE_BITS = 12;   //计数序列号位数,即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号(算法认12位,支持每个节点每毫秒产生4096个ID序号)。

    /**
     * @VAR integer 数据中心编号
     */
    PRotected $data_center_id;

    /**
     * @var integer 机器编号
     */
    protected $machine_id;

    /**
     * @var null|integer 上一次生成id使用的时间戳(毫秒级别)
     */
    protected $lastTimestamp = null;

    /**
     * @var int
     */
    protected $sequence = 1;    //序列号
    protected $signLeftShift = self::TIMESTAMP_BITS + self::DATA_CENTER_BITS + self::MACHINE_ID_BITS + self::SEQUENCE_BITS;  //符号位左位移位数
    protected $timestampLeftShift = self::DATA_CENTER_BITS + self::MACHINE_ID_BITS + self::SEQUENCE_BITS;    //时间戳左位移位数
    protected $dataCenterLeftShift = self::MACHINE_ID_BITS + self::SEQUENCE_BITS;   //IDC左位移位数
    protected $machineLeftShift = self::SEQUENCE_BITS;  //机器编号左位移位数
    protected $maxSequenceid = -1 ^ (-1 << self::SEQUENCE_BITS);    //最大序列号
    protected $maXMachineId = -1 ^ (-1 << self::MACHINE_ID_BITS);   //最大机器编号
    protected $maxDataCenterId = -1 ^ (-1 << self::DATA_CENTER_BITS);   //最大数据中心编号

    /**
     * @param integer $dataCenter_id 数据中心的唯一ID(如果使用多个数据中心,需要设置此ID用以区分)
     * @param integer $machine_id 机器的唯一ID (如果使用多台机器,需要设置此ID用以区分)
     * @throws \Exception
     */
    public function __construct($dataCenter_id = 0,$machine_id = 0)
    {
        if ($dataCenter_id > $this->;maxDataCenterId) {
            throw new \Exception('数据中心编号取值范围为:0-' . $this->maxDataCenterId);
        }
        if ($machine_id > $this->maxMachineId) {
            throw new \Exception('机器编号编号取值范围为:0-' . $this->maxMachineId);
        }
        $this->data_center_id = $dataCenter_id;
        $this->machine_id = $machine_id;
    }

    /**
     * 使用雪花算法生成一个唯一ID
     * @return string 生成的ID
     * @throws \Exception
     */
    public function generateID()
    {
        $sign = 0; //符号位,值始终为0
        $timestamp = $this->getUnixTimestamp();
        if ($timestamp < $this->lastTimestamp) {
            throw new \Exception('时间倒退了!');
        }

        //与上次时间戳相等,需要生成序列号.不相等则重置序列号
        if ($timestamp == $this->lastTimestamp) {
            $sequence = ++$this->sequence;
            if ($sequence == $this->maxSequenceId) { //如果序列号超限,则需要重新获取时间
                $timestamp = $this->getUnixTimestamp();
                while ($timestamp <= $this->lastTimestamp) {    //时间相同则阻塞
                    $timestamp = $this->getUnixTimestamp();
                }
                $this->sequence = 0;
                $sequence = ++$this->sequence;
            }
        } else {
            $this->sequence = 0;
            $sequence = ++$this->sequence;
        }

        $this->lastTimestamp = $timestamp;
        $time = (int)($timestamp - self::EPOCH_OFFSET);
        $id = ($sign << $this->signLeftShift) | ($time << $this->timestampLeftShift) | ($this->data_center_id << $this->dataCenterLeftShift) | ($this->machine_id << $this->machineLeftShift) | $sequence;

        return (string)$id;
    }

    /**
     * 获取去当前时间戳
     *
     * @return integer 毫秒级别的时间戳
     */
    private function getUnixTimestamp()
    {
        return floor(microtime(true) * 1000);
    }
}

脚本宝典总结

以上是脚本宝典为你收集整理的php实现雪花算法(ID递增)全部内容,希望文章能够帮你解决php实现雪花算法(ID递增)所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。