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实时显示输出
Oct 02 PHP
PHP 变量定义和变量替换的方法
Jul 30 PHP
php HtmlReplace输入过滤安全函数
Jul 03 PHP
解析php file_exists无效的解决办法
Jun 26 PHP
php使用curl访问https示例分享
Jan 17 PHP
PHP使用内置dir类实现目录遍历删除
Mar 31 PHP
PHP基于phpqrcode生成带LOGO图像的二维码实例
Jul 10 PHP
PHP魔术方法使用方法汇总
Feb 14 PHP
PHP文件及文件夹操作之创建、删除、移动、复制
Jul 13 PHP
php微信公众账号开发之前五个坑(一)
Sep 18 PHP
PHP运行模式汇总
Nov 06 PHP
php慢查询日志和错误日志使用详解
Feb 27 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
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
2006/10/09 PHP
php可变长参数处理函数详解
2017/02/22 PHP
JavaScript OOP类与继承
2009/11/15 Javascript
获取dom元素那些讨厌的位置封装代码
2010/06/23 Javascript
js 动态修改css文件用到了cssRule
2014/08/20 Javascript
jquery mobile开发常见问题分析
2016/01/21 Javascript
原生javascript实现的一个简单动画效果
2016/03/30 Javascript
基于Vuejs框架实现翻页组件
2020/06/29 Javascript
js 文字超出长度用省略号代替,鼠标悬停并以悬浮框显示实例
2016/12/06 Javascript
BootStrap学习笔记之nav导航栏和面包屑导航
2017/01/03 Javascript
JS中正则表达式要注意lastIndex属性
2017/08/08 Javascript
微信小程序表单验证功能完整实例
2017/12/01 Javascript
python 获取本机ip地址的两个方法
2013/02/25 Python
一篇文章入门Python生态系统(Python新手入门指导)
2015/12/11 Python
Python argv用法详解
2016/01/08 Python
Python使用matplotlib绘制多个图形单独显示的方法示例
2018/03/14 Python
Python通用循环的构造方法实例分析
2018/12/19 Python
利用python实现对web服务器的目录探测的方法
2019/02/26 Python
python 在threading中如何处理主进程和子线程的关系
2020/04/25 Python
基于Python脚本实现邮件报警功能
2020/05/20 Python
Python通过yagmail实现发送邮件代码解析
2020/10/27 Python
实例讲解CSS3中的border-radius属性
2015/08/18 HTML / CSS
Canvas实现保存图片到本地的示例代码
2018/06/28 HTML / CSS
Casadei卡萨蒂官网:意大利奢侈鞋履品牌
2017/10/28 全球购物
乡镇八一建军节活动方案
2014/08/24 职场文书
廉政教育的心得体会
2014/09/01 职场文书
大学运动会加油稿200字(5篇)
2014/09/27 职场文书
办理护照工作证明
2014/10/10 职场文书
临时用工协议书范本
2014/10/29 职场文书
护士求职自荐信范文
2015/03/04 职场文书
行政经理岗位职责
2015/04/15 职场文书
《钓鱼的启示》教学反思
2016/02/18 职场文书
《为人民服务》教学反思
2016/02/20 职场文书
Redis5之后版本的高可用集群搭建的实现
2021/04/27 Redis
Mybatis-Plus 使用 @TableField 自动填充日期
2022/04/26 Java/Android
利用正则表达式匹配浮点型数据
2022/05/30 Java/Android