PHP生成唯一ID之SnowFlake算法

 更新时间:2016年12月17日 10:27:06   作者:煮茶  
snowflake算法是个啥?首先我来提出个问题,怎么在分布式系统中生成唯一性id并保持该id大致自增?在twitter中这是最重要的业务场景,于是twitter推出了一种snowflake算法。

前言:最近需要做一套CMS系统,由于功能比较单一,而且要求灵活,所以放弃了WP这样的成熟系统,自己做一套相对简单一点的。文章的详情页URL想要做成url伪静态的格式即xxx.html 其中xxx考虑过直接用自增主键,但是感觉这样有点暴露文章数量,有同学说可以把初始值设高一点,可是还是可以通过ID差算出一段时间内的文章数量,所以需要一种可以生成唯一ID的算法。

考虑过的方法有

  1. 直接用时间戳,或者以此衍生的一系列方法
  2. Mysql自带的uuid

以上两种方法都可以查到就不多做解释了

最终选择了Twitter的SnowFlake算法

这个算法的好处很简单可以在每秒产生约400W个不同的16位数字ID(10进制)

原理很简单

ID由64bit组成

其中 第一个bit空缺

41bit用于存放毫秒级时间戳

10bit用于存放机器id

12bit用于存放自增ID

除了最高位bit标记为不可用以外,其余三组bit占位均可浮动,看具体的业务需求而定。默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器,序列号支持1毫秒产生4095个自增序列id。
下面是PHP源码

<?php
namespace App\Services;

abstract class Particle {
  const EPOCH = 1479533469598;
  const max12bit = 4095;
  const max41bit = 1099511627775;

  static $machineId = null;

  public static function machineId($mId = 0) {
    self::$machineId = $mId;
  }

  public static function generateParticle() {
    /*
    * Time - 42 bits
    */
    $time = floor(microtime(true) * 1000);

    /*
    * Substract custom epoch from current time
    */
    $time -= self::EPOCH;

    /*
    * Create a base and add time to it
    */
    $base = decbin(self::max41bit + $time);


    /*
    * Configured machine id - 10 bits - up to 1024 machines
    */
    if(!self::$machineId) {
      $machineid = self::$machineId;
    } else {
      $machineid = str_pad(decbin(self::$machineId), 10, "0", STR_PAD_LEFT);
    }
    
    /*
    * sequence number - 12 bits - up to 4096 random numbers per machine
    */
    $random = str_pad(decbin(mt_rand(0, self::max12bit)), 12, "0", STR_PAD_LEFT);

    /*
    * Pack
    */
    $base = $base.$machineid.$random;

    /*
    * Return unique time id no
    */
    return bindec($base);
  }

  public static function timeFromParticle($particle) {
    /*
    * Return time
    */
    return bindec(substr(decbin($particle),0,41)) - self::max41bit + self::EPOCH;
  }
}

?>

调用方法如下

Particle::generateParticle($machineId);//生成ID
Particle::timeFromParticle($particle);//反向计算时间戳

这里我做了改良 如果机器ID传0 就会去掉这10bit 因为有些时候我们可能用不到这么多ID

相关文章

  • CI框架中$this->load->library()用法分析

    CI框架中$this->load->library()用法分析

    这篇文章主要介绍了CI框架中$this->load->library()用法,详细分析了加载library方法的步骤与相关注意事项,需要的朋友可以参考下
    2016-05-05
  • php原生数据库分页的代码实例

    php原生数据库分页的代码实例

    在本篇内容中小编给大家分享了关于php原生数据库分页的代码实例的简单介绍,需要的朋友们跟着学习下。
    2019-02-02
  • joomla组件开发入门教程

    joomla组件开发入门教程

    这篇文章主要介绍了joomla组件开发的方法,结合实例形式分析了joomla组件的结构、功能与具体使用技巧,需要的朋友可以参考下
    2016-05-05
  • PHP jQuery+Ajax结合写批量删除功能

    PHP jQuery+Ajax结合写批量删除功能

    这篇文章主要介绍了PHP jQuery+Ajax结合写批量删除功能的相关资料,需要的朋友可以参考下
    2017-05-05
  • php版微信公众号自定义分享内容实现方法

    php版微信公众号自定义分享内容实现方法

    这篇文章主要介绍了php版微信公众号自定义分享内容实现方法,结合实例形式分析了php实现微信公众号自定义分享内容的接口调用与相关使用技巧,需要的朋友可以参考下
    2016-09-09
  • PHP批量生成静态HTML的简单原理和方法

    PHP批量生成静态HTML的简单原理和方法

    PHP生成HTML的技术要比ASP的技术相对来说要简单一点,下面简要说一下怎样用PHP批量生成HTML技术吧
    2014-04-04
  • php中创建和调用webservice接口示例

    php中创建和调用webservice接口示例

    这篇文章主要介绍了php中创建和调用webservice接口示例,包括webservice基本知识、webservice服务端例子、webservice客户端例子,需要的朋友可以参考下
    2014-07-07
  • 检测codeigniter脚本消耗内存情况的方法

    检测codeigniter脚本消耗内存情况的方法

    这篇文章主要介绍了检测codeigniter脚本消耗内存情况的方法,实例分析了codeigniter中memory_usage方法及{ memory_usage}伪变量的使用技巧,需要的朋友可以参考下
    2015-03-03
  • 关于PHP 如何用 curl 读取 HTTP chunked 数据

    关于PHP 如何用 curl 读取 HTTP chunked 数据

    通过本文给大家介绍php用curl读取http chunked数据的方法,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-02-02
  • PHP如何使用Memcached

    PHP如何使用Memcached

    memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。本文给大家介绍PHP如何使用Memcached,感兴趣的朋友一起学习吧
    2016-04-04

最新评论