轻量级前端框架助力开发者提升项目效率与性能
669
2022-10-19
雪花算法详解
SnowFlake 介绍
SnowFlake 中文意思为雪花,故称为雪花算法。 最早是 Twitter 公司在其内部用于分布式环境下生成唯一 ID。 2014年开源 scala 语言版本。
组成部分
首位:1bit,固定为0。 时间戳:41bit,((2^41 ) - 1) / (1000x60x60x24x365) 大约可以使用69年。 机器码: 10bit,一般前5bit用户机房,后5bit用于服务器,共可部署2^5 x 2^5 = 1024 台服务器。 序列号:12bit,同一毫秒时间戳,通过序列号来递增区分,1ms可以容纳 (2^12) -1= 4095个id,超过则获取下一毫秒。
java算法实现雪花算法
package com.example.demo.utils; /** * @author 谢阳 * @version 1.8.0_131 * @date 2022/08/12 20:30:00 * @description 雪花算法 */ public class SnowFlake { /** * 组成部分 最高符号位 + 时间戳 + (机房id+机房id) + 序列号 */ // 修复时间戳 2022-08-12 20:30:00 private static final long FIX_TIME_STAMP = 1660307400L; // 机房id private final long computerRoomId; // 机器id private final long machineId; // 序列号 private long sequence = 0L; /** * 所占用的bit个数 */ // 时间戳41bit // 5bit机房id private static final long COMPUTER_ROOM_BIT_CNT = 5L; // 5bit机器id private static final long MACHINE_BIT_CNT = 5L; // 12bit序列号 private static final long SEQUENCE_BIT_CNT = 12L; /** * 位移的位数 */ // 机器id 左移12位 private static final long MACHINE_ID_SHIFT = SEQUENCE_BIT_CNT; // 机房id 左移17位 private static final long COMPUTER_ROOM_ID_SHIFT = MACHINE_ID_SHIFT + MACHINE_BIT_CNT; // 时间戳 左移22位 private final static long TIME_STAMP_SHIFT = COMPUTER_ROOM_ID_SHIFT + COMPUTER_ROOM_BIT_CNT; /** * 聚合信息 */ // 支持最大的机房id机房id 5bit private static final long MAX_COMPUTER_ROOM_ID = ~(-1 << COMPUTER_ROOM_BIT_CNT); // 支持最大的机器id 5bit private static final long MAX_MACHINE_ID = ~(-1 << MACHINE_BIT_CNT); // 序列号支持的最大的个数 12bit private static final long SEQUENCE_MASK = ~(-1 << SEQUENCE_BIT_CNT); // 上一次生成的时间戳 private long lastTimeStamp = -1L; /** * @param computerRoomId 机房id * @param machineId 机器id */ public SnowFlake(long computerRoomId, long machineId) { if (computerRoomId < 0 || computerRoomId > MAX_COMPUTER_ROOM_ID) { throw new IllegalArgumentException("computerRoomId 不在范围"); } if (machineId < 0 || machineId > MAX_MACHINE_ID) { throw new IllegalArgumentException("computerRoomId 不在范围"); } this.computerRoomId = computerRoomId; this.machineId = machineId; } /** * @return 返回毫秒级时间戳 */ private long getCurrentTime() { return System.currentTimeMillis(); } /** * @return 雪花刷法生成 id */ public synchronized long getNextId() { // 拿到时间戳 long currentTimeStamp = getCurrentTime(); // 时间戳回拨问题 if (currentTimeStamp < lastTimeStamp) { throw new RuntimeException( String.format("可能出现服务器时钟回拨问题,请检查服务器时间。当前服务器时间戳:%d,上一次使用时间戳:%d", currentTimeStamp, lastTimeStamp)); } // 时间为同一毫秒时间,sequence + 1 if (currentTimeStamp == lastTimeStamp) { // 序列号 + 1 sequence = (sequence + 1) & SEQUENCE_MASK; // 序列号用完 if (sequence == 0) { // 获取下一个毫秒级 currentTimeStamp = getNextMillis(); } } else { sequence = 0; } // 记录上一次时间戳 lastTimeStamp = currentTimeStamp; // 生成唯一id return ((currentTimeStamp - FIX_TIME_STAMP) << TIME_STAMP_SHIFT) | (computerRoomId << COMPUTER_ROOM_ID_SHIFT) | (machineId << MACHINE_ID_SHIFT) | sequence; } /** * @return 下一毫秒 */ private long getNextMillis() { long currentTimeStamp = getCurrentTime(); while (currentTimeStamp <= lastTimeStamp) { currentTimeStamp = getCurrentTime(); } return currentTimeStamp; } }
springBoot整合使用雪花算法
第一步:配置yaml
SnowFlake: computerRoomId: 0 machineId: 0
第二步:编写SnowFlake雪花算法
略.
第三步:编写SnowFlakeConfig配置文件
package com.example.demo.config; import com.example.demo.utils.SnowFlake; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 谢阳 * @version 1.8.0_131 * @date 2022/8/12 21:25 * @description */ @Slf4j @Configuration public class SnowFlakeConfig { @Value("${SnowFlake.computerRoomId}") private long computerRoomId; @Value("${SnowFlake.machineId}") private long machineId; @Bean public SnowFlake snowFlake() { return new SnowFlake(computerRoomId,machineId); } }
测试代码如下:
package com.example.demo; import com.example.demo.utils.SnowFlake; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class DemoApplicationTests { @Autowired SnowFlake snowFlake; @Test void contextLoads() { for (int i = 0; i < 5; i++) { long flakeId = snowFlake.getNextId(); System.out.println(i + " = " +flakeId); } } }
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~