其实就是一个long类型的数据64位
手写一个最简单的雪花算法
核心思路就是让位置,把前面的位置让出来,让别人进来
主要角色:符号位、时间戳、工作机器id、序列号
需要让位的:时间戳让出前22位、工作机器id让出前12位
/**
* 位移
* 5的2进制 101
* 左移两位 5<<2 = 10100 = 20
*/
public static void main(String[] args) {
//符号位1bit,需要左移63,因为前63位是时间戳+工作机器+序列号,但0左移还是0,所以不需要
long id = 0;
//13位时间戳占用41bit,需要左移22,因为前22位是时间戳+工作机器+序列号
long time = System.currentTimeMillis();
//工作机器id 10bit MAX = 2^10,min=1,需要左移12因为前12位是序列号
long workId = 1L;
//序列号12bit MAX = 2^12,min=1,不需要左移(本地自增的一个变量i++)
long sequenceId = 1L;
id = id << 63;
time=time << 22;
workId = workId << 12;
//这样就得到了一个19位雪花id
System.out.println(id+time+workId+sequenceId);
}
源码的思路,源码链接
/**
* time 时间戳,时间回溯问题,如果管理员调整了系统时间,就需要死循环等待到将来才能使用,或者直接抛异常
* workId
* sequenceId 序列id,做成一个本地的变量就欧克了,每个毫秒最多生成2^12=4096个id,超过这个值就抛异常
* 获取SnowId的方法要加锁,否则会重复
*/
数据库设计思路
workId 可以利用数据库或者redis
每次项目启动时就去数据库占用一条数据返回一个的id,项目停止时把这个id的占用状态清理掉
最大值不超过2^10=1024
CREATE TABLE `snow` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'workId最大值1024',
`use_flag` tinyint DEFAULT NULL COMMENT '是否被使用0否1是',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
每台机器每毫秒2^12=4096个id(QPS=4096000,百万的QPS已经满足百分之90多的场景)
如果机器部署的不多,但又想每毫秒生成更多的id
调整workId和sequenceId 所占用的位数
比如只部署10个节点,那么workId就可以是2^4 占用4位
那么sequenceId可以占用18位2^18=262144
每台机器每毫秒20多万个id