• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    PHP实现Snowflake生成分布式唯一ID的方法示例

    前言

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

    先来看以下 snowflake 的结构:

    生成的数值是 64 位,分成 4 个部分:

    ?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 $timest  // 上次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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • PHP生成唯一ID之SnowFlake算法
    上一篇:Yii实现微信公众号场景二维码的方法实例
    下一篇:Laravel中GraphQL接口请求频率实战记录
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    PHP实现Snowflake生成分布式唯一ID的方法示例 PHP,实现,Snowflake,生成,分布式,