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 相关文章推荐
Trying to clone an uncloneable object of class Imagic的解决方法
Jan 11 PHP
php缓冲输出实例分析
Jan 05 PHP
PHP统计数值数组中出现频率最多的10个数字的方法
Apr 20 PHP
PHP获取文件行数的方法
Jun 10 PHP
CodeIgniter中使用Smarty3基本配置
Jun 29 PHP
php实现简单的MVC框架实例
Sep 23 PHP
Zend Framework实现自定义过滤器的方法
Dec 09 PHP
php+redis实现多台服务器内网存储session并读取示例
Jan 12 PHP
PHP中error_reporting函数用法详细介绍
Jun 11 PHP
PHP实现的简单路由和类自动加载功能
Mar 13 PHP
yii2实现Ueditor百度编辑器的示例代码
Nov 02 PHP
php 文件上传至OSS及删除远程阿里云OSS文件
Jul 04 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
JavaScript入门教程(2) JS基础知识
2009/01/31 Javascript
浅析javascript闭包 实例分析
2010/12/25 Javascript
分享XmlHttpRequest调用Webservice的一点心得
2012/07/20 Javascript
使用javascript做的一个随机点名程序
2014/02/13 Javascript
javascript自定义的addClass()方法
2014/05/28 Javascript
jquery和css3实现的炫酷时尚的菜单导航
2014/09/01 Javascript
Javascript中使用A标签获取当前目录的绝对路径方法
2015/03/02 Javascript
AngularJS学习笔记之基本指令(init、repeat)
2015/06/16 Javascript
BootStrap栅格系统、表单样式与按钮样式源码解析
2017/01/20 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
js实现数组去重方法及效率?Ρ? target=
2017/02/14 Javascript
JS实现json的序列化和反序列化功能示例
2017/06/13 Javascript
详解vue.js+UEditor集成 [前后端分离项目]
2017/07/07 Javascript
深入理解requireJS-实现一个简单的模块加载器
2018/01/15 Javascript
Vue filter介绍及详细使用
2018/04/04 Javascript
AngularJS自定义过滤器用法经典实例总结
2018/05/17 Javascript
vue路由跳转传参数的方法
2019/05/06 Javascript
JS前端知识点总结之页面加载事件,数组操作,DOM节点操作,循环和分支
2019/07/04 Javascript
Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作
2020/08/31 Javascript
js实现随机圆与矩形功能
2020/10/29 Javascript
初学Python函数的笔记整理
2015/04/07 Python
Python 爬虫学习笔记之正则表达式
2016/09/21 Python
Python 自动刷博客浏览量实例代码
2017/06/14 Python
pycharm: 恢复(reset) 误删文件的方法
2018/10/22 Python
python 格式化输出百分号的方法
2019/01/20 Python
python函数参数(必须参数、可变参数、关键字参数)
2019/08/16 Python
Python中list循环遍历删除数据的正确方法
2019/09/02 Python
Pytorch maxpool的ceil_mode用法
2020/02/18 Python
python中if及if-else如何使用
2020/06/02 Python
在django中查询获取数据,get, filter,all(),values()操作
2020/08/09 Python
python两种注释用法的示例
2020/10/09 Python
详解canvas drawImage()方法绘制图片不显示的问题
2018/10/08 HTML / CSS
本科毕业生自荐信
2014/06/02 职场文书
弘扬焦裕禄精神践行三严三实心得体会
2014/10/13 职场文书
同事打架检讨书
2015/05/06 职场文书
《刺客之王:C罗全景传记》:时代从来不会亏待手艺人
2019/11/28 职场文书