原理介绍:
Snowflake的核心思想是将64bit的二进制数字分成若*分,每一部分都存储有特定含义的数据,比如说时间戳、机房ID、机器ID、序列号等等,最终生成全局唯一的有序ID。它的标准算法是这样的:
0 0000000000000000000000000000000000000000 0000000000 000000000000
符号位 41位时间戳,大约够69年 10位(机房+机器ID) 12位序列号
具体位数怎么分配,其实可以根据自己的情况来,比如如果只有两个机器,那么用10位显然是浪费的,根据自己情况分配即可
相关知识:
二进制转十进制:
比如 11010[2进制] = 1X2^4+1X2^3+0X2^2+1X2^1+0X2^0
=26[10进制],二进制数转换成十进制数的方法是按权展开就是这样做的
注:2^4表示2的4次方,任何非0数字的0次方都等于1
十进制转二进制:
789=1100010101
789/2=394 余1 第10位
394/2=197 余0 第9位
197/2=98 余1 第8位
98/2=49 余0 第7位
49/2=24 余1 第6位
24/2=12 余0 第5位
12/2=6 余0 第4位
6/2=3 余0 第3位
3/2=1 余1 第2位
1/2=0 余1 第1位
最后把余数从下往上连起来即为: 1100010101
PHP实现
<?php
/**
* 分布式 id 生成类 组成: <毫秒级时间戳+机房id+机器id+序列号>
* 默认情况下41bit的时间戳可以支持该算法使用69年,5bit的机房id可以支持31台机器,5bit的工作机器id可以支持31台机器,序列号支持1毫秒产生4095个自增序列id
*/
class IdCreate
{
const EPOCH = 1640856551866; //开始时间,固定一个小于当前时间的毫秒数,这样后续的时间戳毫秒基于此开始时间才能达到69年;
const max12bit = 4095;
static $dataCenterId = null; // 机房id
static $machineId = null; // 机器id
public static function createOnlyId($dataCenterId = 0,$machineId = 0)
{
self::$machineId = $machineId;
self::$dataCenterId = $dataCenterId;
// 时间戳 41字节
$time = floor(microtime(true) * 1000);
// 当前时间 与 开始时间 差值,这样就可以有69年的时间
$time -= self::EPOCH;
// 二进制的 毫秒级时间戳
$timeStr = str_pad(decbin($time), 41, "0", STR_PAD_LEFT);
// 机房id 5 字节
$dataCenterId = str_pad(decbin(self::$dataCenterId), 5, "0", STR_PAD_LEFT);
// 机器id 5 字节
$machineId = str_pad(decbin(self::$machineId), 5, "0", STR_PAD_LEFT);
// 序列数 12字节
$random = str_pad(decbin(mt_rand(0, self::max12bit)), 12, "0", STR_PAD_LEFT);
//正常应该搞自增id,这里为了演示,所以用了随机数,使用redis的自增id比较好:
//REDIS::incr($::$::$machineId);
// 拼接
$base = $timeStr.$dataCenterId.$machineId.$random;
// 转化为 十进制 返回
return bindec($base);
}
}
$dataCenterId = 2;
$machineId = 1;
$cast_id = IdCreate::createOnlyId($dataCenterId,$machineId);
echo $cast_id;
生成唯一值
13648311620966