PHP生成唯一ID之SnowFlake算法


Posted in PHP onDecember 17, 2016

前言:最近需要做一套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

PHP 相关文章推荐
php disk_free_space 返回目录可用空间
May 10 PHP
PHP IN_ARRAY 函数使用注意事项
Jul 24 PHP
PHP的5个安全措施小结
Jul 17 PHP
PHP循环函数使用介绍之PHP基础入门教程
Sep 21 PHP
php文件上传的例子及参数详解
Dec 12 PHP
PHP中一些可以替代正则表达式函数的字符串操作函数
Nov 17 PHP
memcache一致性hash的php实现方法
Mar 05 PHP
php中通过DirectoryIterator删除整个目录的方法
Mar 13 PHP
PHP receiveMail实现收邮件功能
Apr 25 PHP
PHP实现微信商户支付企业付款到零钱功能
Sep 30 PHP
PHP SESSION机制的理解与实例
Mar 22 PHP
ThinkPHP3.2框架操作Redis的方法分析
May 05 PHP
简单解决微信文章图片防盗链问题
Dec 17 #PHP
PHP 7.1新特性的汇总介绍
Dec 16 #PHP
浅谈PHP命令执行php文件需要注意的问题
Dec 16 #PHP
PHP+Ajax 检测网络是否正常实例详解
Dec 16 #PHP
php微信公众号开发(4)php实现自定义关键字回复
Dec 15 #PHP
php微信公众号开发(3)php实现简单微信文本通讯
Dec 15 #PHP
php微信公众号开发(2)百度BAE搭建和数据库使用
Dec 15 #PHP
You might like
php抓即时股票信息
2006/10/09 PHP
PHP操作数组相关函数
2011/02/03 PHP
php中调用其他系统http接口的方法说明
2014/02/28 PHP
php+ajax登录跳转登录实现思路
2016/07/31 PHP
php中如何执行linux命令详解
2018/11/06 PHP
PHP小程序支付功能完整版【基于thinkPHP】
2019/03/26 PHP
在子窗口中关闭父窗口的一句代码
2013/10/21 Javascript
js取消单选按钮选中并判断对象是否为空
2013/11/14 Javascript
jquery中常用的函数和属性详细解析
2014/03/07 Javascript
JavaScript时间转换处理函数
2015/04/14 Javascript
结合代码图文讲解JavaScript中的作用域与作用域链
2016/07/05 Javascript
针对BootStrap中tabs控件的美化和完善(推荐)
2016/07/06 Javascript
详解Angular2表单-模板驱动的表单(Template-Driven Forms)
2017/08/04 Javascript
Webpack 4.x搭建react开发环境的方法步骤
2018/08/15 Javascript
JavaScript基础之静态方法和实例方法分析
2018/12/26 Javascript
Python3实现配置文件差异对比脚本
2019/11/18 Python
Windows10下Tensorflow2.0 安装及环境配置教程(图文)
2019/11/21 Python
关于tf.reverse_sequence()简述
2020/01/20 Python
python def 定义函数,调用函数方式
2020/06/02 Python
python 实现图片裁剪小工具
2021/02/02 Python
美国汽配连锁巨头Pep Boys官网:轮胎更换、汽车维修服务和汽车零部件
2017/01/14 全球购物
英国最大的电子零件及配件零售商:Partmaster
2017/04/24 全球购物
怎样比较两个类型为String的字符串
2016/08/17 面试题
自我鉴定思想方面
2013/10/07 职场文书
《画》教学反思
2014/04/14 职场文书
社团活动总结怎么写
2014/06/30 职场文书
办公室个人总结
2015/02/28 职场文书
学校证明范文
2015/06/24 职场文书
大学生读书笔记大全
2015/07/01 职场文书
活动新闻稿范文
2015/07/17 职场文书
通知怎么写?
2019/04/17 职场文书
辞职信怎么写?
2019/05/21 职场文书
详解Redis实现限流的三种方式
2021/04/27 Redis
sentinel支持的redis高可用集群配置详解
2022/04/01 Redis
国际最新研究在陨石中发现DNA主要成分 或由陨石带来地球
2022/04/29 数码科技
教你如何用cmd快速登录服务器
2022/06/10 Servers