前言

Twitter 的 snowflake 在分布式生成唯一 UUID 应用还是蛮广泛的,基于 snowflake 的一些变种的算法网上也有不少。使用 snowflake 生成 UUID 很多都是在分布式场景下使用,我看了下网上有其中有几篇 PHP 实现的都没有考虑到线程安全。现在 PHP 有了 Swoole 的锁和协程的加持,对于我们开发线程安全和高并发模拟还是很方便的,这里用 PHP 结合 Swoole 来学习下实现最简单的 snowflake。

先来看以下 snowflake 的结构:

生成的数值是 64 位,分成 4 个部分:第一个 bit 为符号位,最高位为 0 表示正数

第二部分 41 个 bit 用于记录生成 ID 时候的时间戳,单位为毫秒,所以该部分表示的数值范围为 2^41 - 1(69 年),它是相对于某一时间的偏移量

第三部分的 10 个 bit 表示工作节点的 ID,表示数值范围为 2^10 - 1,相当于支持 1024 个节点

第四部分 12 个 bit 表示每个工作节点没毫秒生成的循环自增 id,最多可以生成 2^12 -1 个 id,超出归零等待下一毫秒重新自增。<?php

class Snowflake

{

const EPOCH = 1543223810238; // 起始时间戳,毫秒

const SEQUENCE_BITS = 12; //序号部分12位

const SEQUENCE_MAX = -1 ^ (-1 << self::SEQUENCE_BITS); // 序号最大值

const WORKER_BITS = 10; // 节点部分10位

const WORKER_MAX = -1 ^ (-1 << self::WORKER_BITS); // 节点最大数值

const TIME_SHIFT = self::WORKER_BITS + self::SEQUENCE_BITS; // 时间戳部分左偏移量

const WORKER_SHIFT = self::SEQUENCE_BITS; // 节点部分左偏移量

protected $timestamp; // 上次ID生成时间戳

protected $workerId; // 节点ID

protected $sequence; // 序号

protected $lock; // Swoole 互斥锁

public function __construct($workerId)

{

if ($workerId < 0 || $workerId > self::WORKER_MAX) {

trigger_error("Worker ID 超出范围");

exit(0);

}

$this->timestamp = 0;

$this->workerId = $workerId;

$this->sequence = 0;

$this->lock = new swoole_lock(SWOOLE_MUTEX);

}

/**

* 生成ID

* @return int

*/

public function getId()

{

$this->lock->lock(); // 这里一定要记得加锁

$now = $this->now();

if ($this->timestamp == $now) {

$this->sequence++;

if ($this->sequence > self::SEQUENCE_MAX) {

// 当前毫秒内生成的序号已经超出最大范围,等待下一毫秒重新生成

while ($now <= $this->timestamp) {

$now = $this->now();

}

}

} else {

$this->sequence = 0;

}

$this->timestamp = $now; // 更新ID生时间戳

$id = (($now - self::EPOCH) << self::TIME_SHIFT) | ($this->workerId << self::WORKER_SHIFT) | $this->sequence;

$this->lock->unlock(); //解锁

return $id;

}

/**

* 获取当前毫秒

* @return string

*/

public function now()

{

return sprintf("%.0f", microtime(true) * 1000);

}

}

其实逻辑并不复杂,解释一下代码中的位运算:-1 ^ (-1 << self::SEQUENCE_BITS)

就是-1的二进制表示为1的补码,其实等同于 :

2**self::SEQUENCE_BITS - 1

最后部分左移后或运算:(($now - self::EPOCH) << self::TIME_SHIFT) | ($this->workerId << self::WORKER_SHIFT) | $this->sequence;

这里主要是对除了第一位符号位以外的三个部分进行左移相应的偏移量使其归位,并通过或运算重新整合成上面 snowflake 的结构,比如我们用 3 部分 4 位来演示一下该归并操作:0000 0000 0010 --左移0位--> 0000 0000 0010

0000 0000 0100 --左移4位--> 0000 0100 0000 --或操作-->1000 0100 0010

0000 0000 1000 --左移8位--> 1000 0000 0000

总结

到此这篇关于PHP实现Snowflake生成分布式唯一ID的文章就介绍到这了,更多相关PHP Snowflake生成分布式唯一ID内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

snowflake算法 php,PHP实现Snowflake生成分布式唯一ID的方法示例相关推荐

  1. springboot2.x 集成百度 ui-dgenerator生成分布式唯一id

    百度的ui-dgenerator也是根据snowflake算法更改的方法,关于snowflake算法不做介绍,不懂的可以百度. snowflake算法有个缺点是:时间回拨问题,官方文档也是抛出异常. ...

  2. 美团leaf生成分布式唯一id

    1. 介绍 https://github.com/Meituan-Dianping/Leaf.git 源码 改为下载Leaf-feature-spring-boot-starter.zip包 本地安装 ...

  3. 分布式唯一id:snowflake算法思考

    匠心零度 转载请注明原创出处,谢谢! 缘起 为什么会突然谈到分布式唯一id呢?原因是最近在准备使用RocketMQ,看看官网介绍: 一句话,消息可能会重复,所以消费端需要做幂等.为什么消息会重复后续R ...

  4. java生成唯一有序序列号_分布式唯一 ID 之 Snowflake 算法

    SegmentFault 社区专栏:全栈修仙之路作者:semlinker No.1 Snowflake 简介 1.1 什么是 Snowflake Snowflake is a service used ...

  5. 如何在分布式场景下生成全局唯一 ID ?

    作者 l 会点代码的大叔(CodeDaShu) 在分布式系统中,有一些场景需要使用全局唯一 ID ,可以和业务场景有关,比如支付流水号,也可以和业务场景无关,比如分库分表后需要有一个全局唯一 ID,或 ...

  6. idgenerator 会重复吗_终极版:分布式唯一ID的几种生成方案

    在业务开发中,大量场景需要唯一ID来进行标识:用户需要唯一身份标识.商品需要唯一标识.消息需要唯一标识.事件需要唯一标识等,都需要全局唯一ID,尤其是复杂的分布式业务场景中全局唯一ID更为重要. 那么 ...

  7. asp按时间自动递增编号_Java秒杀系统实战系列-分布式唯一ID生成订单编号

    本文是"Java秒杀系统实战系列文章"的第七篇,在本文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们将介绍两种方法 ...

  8. 分布式唯一ID的几种生成方案

    分布式ID的特性 唯一性:确保生成的ID是全网唯一的. 有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的. 高可用性:确保任何时候都能正确的生成ID. 带时间:ID里面包含时间 ...

  9. 存数据返回他的序列号id_雪花般的分布式唯一ID雪花算法

    点击上方 Java老铁,并选择 设为星标 优质文章和资料会及时送达 导读:唯一ID可以标识数据的唯一性,在分布式系统中生成唯一ID的方案有很多,常见的方式大概有以下三种 依赖数据库,使用如MySQL自 ...

最新文章

  1. 小松卡特彼勒无人驾驶_运输量突破20亿吨,卡特彼勒无人驾驶矿卡迎里程碑时刻...
  2. Devexpress 重新编译以后 重新生成DEMO
  3. div+css中clear用法
  4. oracle net manager没有orcl_Oracle-数据库基础知识
  5. 在计算机领域做研究的一些想法-- 转载
  6. Mysql日期和时间函数大全
  7. 选择 GCD 还是 NSTimer ?
  8. Lucene5.5.4入门以及基于Lucene实现博客搜索功能
  9. (Python)零起步数学+神经网络入门
  10. Nginx图片防盗链、缓存和压缩的示例
  11. There is no Action mapped for namespace / and action name .
  12. .unl 文件 导入 mysql_mysql数据导出导入
  13. 东秦数模美赛校赛记录——紧急车辆位置.题目
  14. 再次提升2%,仅85K参数的开源人脸检测算法
  15. snagit 9.0注册码
  16. 让MAC在TouchBar显示网速
  17. 网站CDN加速后对URL中?后的参数跟随问题
  18. 看3D打印技术如何影响未来
  19. java file 的length_java里怎么知道一个file的大小?
  20. JavaScript 和读取服务器cookie

热门文章

  1. Windows 10如何启用ReFS弹性文件系统
  2. 英特尔是 Chrome OS 代码的第二大贡献者
  3. day1 作业编写登录窗口
  4. linux 安全 ***检测 杀毒 rootkit
  5. linux deepin是基于linux mint修改
  6. js+jQuery获取全选并用ajax进行批量删除
  7. linux c 按行读取文件
  8. tomcat关闭 异常报告
  9. RansomCoin 二进制中提取加密货币地址
  10. 使用FindFirstFile,FindNextFile遍历一个文件夹