高并发下,雪花算法id重复生成
源码上 如下解释

Snowflake 是 Twitter 内部的一个 ID 生算法,可以通过一些简单的规则保证在大规模分布式情况下生成唯一的 ID 号码。其组成为:

  • 第一个 bit 为未使用的符号位。
  • 第二部分由 41 位的时间戳(毫秒)构成,他的取值是当前时间相对于某一时间的偏移量。
  • 第三部分和第四部分的 5 个 bit 位表示数据中心和机器ID,其能表示的最大值为 2^5 -1 = 31。
  • 最后部分由 12 个 bit 组成,其表示每个工作节点每毫秒生成的序列号 ID,同一毫秒内最多可生成 2^12 -1 即 4095 个 ID。

需要注意的是:

  • 在分布式环境中,5 个 bit 位的 datacenter 和 worker 表示最多能部署 31 个数据中心,每个数据中心最多可部署 31 台节点
  • 41 位的二进制长度最多能表示 2^41 -1 毫秒即 69 年,所以雪花算法最多能正常使用 69 年,为了能最大限度的使用该算法,你应该为其指定一个开始时间。

由上可知,雪花算法生成的 ID 并不能保证唯一,如当两个不同请求同一时刻进入相同的数据中心的相同节点时,而此时该节点生成的 sequence 又是相同时,就会导致生成的 ID 重复。

*这里说明了是sequence 的原因,然后我看了下,结果发现了一个令我疑惑的问题

public function id(){$currentTime = $this->getCurrentMicrotime();while (($sequence = $this->callResolver($currentTime)) > (-1 ^ (-1 << self::MAX_SEQUENCE_LENGTH))) {usleep(1);$currentTime = $this->getCurrentMicrotime();}$workerLeftMoveLength = self::MAX_SEQUENCE_LENGTH;$datacenterLeftMoveLength = self::MAX_WORKID_LENGTH + $workerLeftMoveLength;$timestampLeftMoveLength = self::MAX_DATACENTER_LENGTH + $datacenterLeftMoveLength;return (string) ((($currentTime - $this->getStartTimeStamp()) << $timestampLeftMoveLength)| ($this->datacenter << $datacenterLeftMoveLength)| ($this->workerid << $workerLeftMoveLength)| ($sequence));}

代码里面有个usleep 函数,我查了下,是延迟1微秒 ,但是雪花算法的sequence 不是 一毫秒生成4095个吗,
就是很困惑,本人学艺不精,对算法了解不深,望指导

源码如下:

<?php/** This file is part of the godruoyi/php-snowflake.** (c) Godruoyi <g@godruoyi.com>** This source file is subject to the MIT license that is bundled.*/namespace Snowflake;class Snowflake
{const MAX_TIMESTAMP_LENGTH = 41;const MAX_DATACENTER_LENGTH = 5;const MAX_WORKID_LENGTH = 5;const MAX_SEQUENCE_LENGTH = 12;const MAX_FIRST_LENGTH = 1;/*** The data center id.** @var int*/protected $datacenter;/*** The worker id.** @var int*/protected $workerid;/*** The Sequence Resolver instance.** @var \Godruoyi\Snowflake\SequenceResolver|null*/protected $sequence;/*** The start timestamp.** @var int*/protected $startTime = 1607702400000;/*** Default sequence resolver.** @var \Godruoyi\Snowflake\SequenceResolver|null*/protected $defaultSequenceResolver;/*** Build Snowflake Instance.** @param int $datacenter* @param int $workerid*/public function __construct(int $datacenter = null, int $workerid = null){$maxDataCenter = -1 ^ (-1 << self::MAX_DATACENTER_LENGTH);$maxWorkId = -1 ^ (-1 << self::MAX_WORKID_LENGTH);// If not set datacenter or workid, we will set a default value to use.$this->datacenter = $datacenter > $maxDataCenter || $datacenter < 0 ? mt_rand(0, 31) : $datacenter;$this->workerid = $workerid > $maxWorkId || $workerid < 0 ? mt_rand(0, 31) : $workerid;}/*** Get snowflake id.** @return int*/public function id(){$currentTime = $this->getCurrentMicrotime();while (($sequence = $this->callResolver($currentTime)) > (-1 ^ (-1 << self::MAX_SEQUENCE_LENGTH))) {usleep(1);$currentTime = $this->getCurrentMicrotime();}$workerLeftMoveLength = self::MAX_SEQUENCE_LENGTH;$datacenterLeftMoveLength = self::MAX_WORKID_LENGTH + $workerLeftMoveLength;$timestampLeftMoveLength = self::MAX_DATACENTER_LENGTH + $datacenterLeftMoveLength;return (string) ((($currentTime - $this->getStartTimeStamp()) << $timestampLeftMoveLength)| ($this->datacenter << $datacenterLeftMoveLength)| ($this->workerid << $workerLeftMoveLength)| ($sequence));}/*** Parse snowflake id.** @param string $id** @return array*/public function parseId(string $id, $transform = false): array{$id = decbin($id);$data = ['timestamp' => substr($id, 0, -22),'sequence' => substr($id, -12),'workerid' => substr($id, -17, 5),'datacenter' => substr($id, -22, 5),];return $transform ? array_map(function ($value) {return bindec($value);}, $data) : $data;}/*** Get current microtime timestamp.** @return int*/public function getCurrentMicrotime(){return floor(microtime(true) * 1000) | 0;}/*** Set start time (millisecond).** @param int $startTime*/public function setStartTimeStamp(int $startTime){$missTime = $this->getCurrentMicrotime() - $startTime;if ($missTime < 0 || $missTime > ($maxTimeDiff = ((1 << self::MAX_TIMESTAMP_LENGTH) - 1))) {throw new \Exception('The starttime cannot be greater than current time and the maximum time difference is '.$maxTimeDiff);}$this->startTime = $startTime;return $this;}/*** Get start timestamp (millisecond), If not set default to 2019-08-08 08:08:08.** @return int*/public function getStartTimeStamp(){if ($this->startTime > 0) {return $this->startTime;}// We set a default start time if you not set.$defaultTime = '2019-08-08 08:08:08';return strtotime($defaultTime) * 1000;}/*** Set Sequence Resolver.** @param SequenceResolver|callable $sequence*/public function setSequenceResolver($sequence){$this->sequence = $sequence;return $this;}/*** Get Sequence Resolver.** @return \Godruoyi\Snowflake\SequenceResolver|callable|null*/public function getSequenceResolver(){return $this->sequence;}/*** Get Default Sequence Resolver.** @return \Godruoyi\Snowflake\SequenceResolver*/public function getDefaultSequenceResolver(): SequenceResolver{return $this->defaultSequenceResolver ?: $this->defaultSequenceResolver = new RandomSequenceResolver();}/*** Call resolver.** @param callable|\Godruoyi\Snowflake\SequenceResolver $resolver* @param int                                           $maxSequence** @return int*/protected function callResolver($currentTime){$resolver = $this->getSequenceResolver();if (is_callable($resolver)) {return $resolver($currentTime);}return is_null($resolver) || !($resolver instanceof SequenceResolver)? $this->getDefaultSequenceResolver()->sequence($currentTime): $resolver->sequence($currentTime);}
}

php 雪花算法问题相关推荐

  1. 雪花算法 Java 版

    雪花算法根据时间戳生成有序的 64 bit 的 Long 类型的唯一 ID 各 bit 含义: 1 bit: 符号位,0 是正数 1 是负数, ID 为正数,所以恒取 0 41 bit: 时间差,我们 ...

  2. Twitter的分布式雪花算法 SnowFlake 每秒自增生成26个万个可排序的ID (Java版)

    分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一 ...

  3. 改进型 clock 页面置换算法实现_ID生成算法雪花算法介绍及实现

    1. SnowFlake 算法介绍 雪花算法是由 Twitter 公司开源的可在分布式系统中产生一个全局唯一 ID 的算法.最初 Twitter 把存储系统从 MySQL 迁移到 Cassandra, ...

  4. php设置id递增,php实现雪花算法(ID递增)

    雪花算法简单描述: 最高位是符号位,始终为0,不可用. 41位的时间序列,精确到毫秒级,41位的长度可以使用69年.时间位还有一个很重要的作用是可以根据时间进行排序. 10位的机器标识,10位的长度最 ...

  5. 分布式主键解决方案----Twitter 雪花算法的原理(Java 版)

    SnowFlake 雪花算法 对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键,优点是方便又能解决问题,缺点是插入 ...

  6. long 雪花算法_雪花算法

    小背景:我们的订单编号要求是 16 位,改造了一下雪花算法 * * 参考Twitter Snowflake算法,按实际需求,做了部分修改,结构如下(每部分用-分开): * 0000000000 - 1 ...

  7. Twitter的分布式雪花算法 SnowFlake

    为什么80%的码农都做不了架构师?>>>    原理 Twitter的雪花算法SnowFlake,使用Java语言实现. SnowFlake算法产生的ID是一个64位的整型,结构如下 ...

  8. Java工具类--雪花算法生成全局唯一ID

    import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkI ...

  9. long 雪花算法_海量数据分库分表方案(一)算法方案

    本文主要描述分库分表的算法方案.按什么规则划分.循序渐进比较目前出现的几种规则方式,最后第五种增量迁移方案是我设想和推荐的方式.后续章再讲述技术选型和分库分表后带来的问题.. 背景 随着业务量递增,数 ...

  10. PHP生成订单号的五种方法:时间拼接随机数 混拼字母 减年份转十六进制 雪花算法 拼接时间戳与随机数

    第一种:年月日时分秒+拼接随机数   危险 稍微体量一大这种肯定有重复 $danhao = date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', ST ...

最新文章

  1. 运营商级网络地址转换(LSN/CGN)方案介绍
  2. 京津冀青少年网球分级赛总决赛开打 118名选手对决
  3. 蓝色三角_梅山!长三角唯一近海蓝色海湾成网红打卡地
  4. mysql创建数据库schooldb_MySQL 创建数据表
  5. python生成的词云没有图案_Python生成词云的实现代码
  6. OpenCV中像素逻辑运算:逻辑或运算
  7. Linux、Ubuntu、CentOS安装和配置zsh
  8. 网络连接方式 NAT
  9. visionpro 窗口显示文字
  10. emmap erlang_erLang学些笔记2—基本类型
  11. DRL实战 : 强化学习在广告点击业务中的应用
  12. matplotlib 使用简明教程(三)-一些专业图表简介
  13. LM算法求解最小二乘问题
  14. 大学生计算机竞赛试题,大学生计算机基础知识竞赛题库_大学生计算机基础知识竞赛试题附答案.docx...
  15. Linux命令 - df命令
  16. lvds传输距离标准_lvds接口标准
  17. 日常工作计划安排工具
  18. Ubuntu / Debian: sudo 出现 unable to resolve host 错误解决办法
  19. 搭配安卓手机领夹式麦克风的PD快充方案来了LDR6023C 分享给大家
  20. 哈工大 编译原理 复习笔记

热门文章

  1. docker 架构 与原理
  2. 已解决selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted:
  3. 万全系列服务器,联想7款万全服务器
  4. XV6阅读报告及新功能实现
  5. STM32CubeMX系列教程8:配置工程模板(串口+不定长数据收发+DMA+IDLE中断+软中断)
  6. Bom是什么?列举你知道的Bom对象。
  7. [照片调色]调出唯美亮丽色调PP的简单方法
  8. SPSS学习笔记(1)
  9. DataGridView绑定DataTable出现大红叉
  10. 世界之窗浏览器 2.0 春节安装版