package cc.mrbird.febs.common.core.utils; import com.baomidou.mybatisplus.core.toolkit.SystemClock; import lombok.extern.slf4j.Slf4j; /** * name: SequenceUtil * package: cc.mrbird.febs.common.core.utils * description: 全局ID生成器,基于雪花算法 * 时间戳+机器码+系统码+序列号 * 时间戳:从2020-01-01开始的秒数 32位 * 机器码:5位 可有32台机器 * 系统码:6位 可设置64个系统 * 系统框架 * 系统管理 000000 1 * 组织架构 000001 2 * 运营管理000010 3 * Hr系统 * 组织规划 001010 10 * 招聘选拔 001011 11 * 员工关系 001100 12 * 考勤管理 001101 13 * 薪酬管理 001110 14 * 社保福利 001111 15 * 绩效管理 010000 16 * 培训开发 010001 17 * 序列号:10位,每秒1024个ID * date: 2021-01-27 20:39 * * @author luoyibo * @version 0.1 * @since JDK 1.8 */ @Slf4j public class SequenceUtil { /** * 初始偏移时间戳 */ private static final long OFFSET = 1546300800L; /** * 机器id */ private static long WORKER_ID; /** * 系统模块码 */ private static long MODULE_CODE; /** * 机器id所占位数 (5bit, 支持最大机器数 2^5 = 32) */ private static final long WORKER_ID_BITS = 5L; /** * 系统模块码所占位数 (6bit, 支持最大机器数 2^6 = 64) */ private static final long MODULE_CODE_BITS = 6L; /** * 自增序列所占位数 (10bit, 支持最大每秒生成 2^10 = 1024) */ private static final long SEQUENCE_ID_BITS = 10L; /** * 系统模块码偏移位数 */ private static final long MODULE_SHIFT_BITS = SEQUENCE_ID_BITS; /** * 机器id偏移位数 */ private static final long WORKER_SHIFT_BITS = SEQUENCE_ID_BITS + MODULE_CODE_BITS; /** * 自增序列偏移位数 */ private static final long OFFSET_SHIFT_BITS = SEQUENCE_ID_BITS + MODULE_CODE_BITS + WORKER_ID_BITS; /** * 机器标识最大值 (2^5 / 2 - 1 = 15) */ private static final long WORKER_ID_MAX = ((1 << WORKER_ID_BITS) - 1) >> 1; /** * 备份机器ID开始位置 (2^5 / 2 = 16) */ private static final long BACK_WORKER_ID_BEGIN = (1 << WORKER_ID_BITS) >> 1; /** * 系统模块码最大值 (2^6 - 1 = 63) */ private static final long MODULE_CODE_MAX = (1 << MODULE_CODE_BITS) - 1; /** * 自增序列最大值 (2^15 - 1 = 1023) */ private static final long SEQUENCE_MAX = (1 << SEQUENCE_ID_BITS) - 1; /** * 发生时间回拨时容忍的最大回拨时间 (秒) */ private static final long BACK_TIME_MAX = 1L; /** * 上次生成ID的时间戳 (秒) */ private static long lastTimestamp = 0L; /** * 当前秒内序列 (2^16) */ private static long sequence = 0L; /** * 备份机器上次生成ID的时间戳 (秒) */ private static long lastTimestampBak = 0L; /** * 备份机器当前秒内序列 (2^16) */ private static long sequenceBak = 0L; /** * 私有构造函数禁止外部访问 */ private SequenceUtil() { } /** * 获取自增序列 * * @return long */ public static long generateId(long workerId, long moduleCode) { WORKER_ID = workerId; MODULE_CODE = moduleCode; if (WORKER_ID > WORKER_ID_MAX || WORKER_ID < 0) { throw new IllegalArgumentException(String.format("机器数量范围: 0 ~ %d 目前: %d", WORKER_ID_MAX, workerId)); } if (MODULE_CODE > MODULE_CODE_MAX || MODULE_CODE < 0) { throw new IllegalArgumentException(String.format("模块数量范围: 0 ~ %d 目前: %d", MODULE_CODE_MAX, moduleCode)); } return nextId(SystemClock.now() / 1000); } /** * 主机器自增序列 * * @param timestamp 当前Unix时间戳 * @return long */ private static synchronized long nextId(long timestamp) { // 时钟回拨检查 if (timestamp < lastTimestamp) { // 发生时钟回拨 log.warn("时钟回拨, 启用备份机器ID: now: [{}] last: [{}]", timestamp, lastTimestamp); return nextIdBackup(timestamp); } // 开始下一秒 if (timestamp != lastTimestamp) { lastTimestamp = timestamp; sequence = 0L; } if (0L == (++sequence & SEQUENCE_MAX)) { sequence--; return nextIdBackup(timestamp); } return ((timestamp - OFFSET) << OFFSET_SHIFT_BITS) | (WORKER_ID << WORKER_SHIFT_BITS) | (MODULE_CODE << MODULE_SHIFT_BITS) | sequence; } /** * 备份机器自增序列 * * @param timestamp timestamp 当前Unix时间戳 * @return long */ private static long nextIdBackup(long timestamp) { int toSecond = 1000; if (timestamp < lastTimestampBak) { if (lastTimestampBak - SystemClock.now() / toSecond <= BACK_TIME_MAX) { timestamp = lastTimestampBak; } else { throw new RuntimeException(String.format("时钟回拨: now: [%d] last: [%d]", timestamp, lastTimestampBak)); } } if (timestamp != lastTimestampBak) { lastTimestampBak = timestamp; sequenceBak = 0L; } if (0L == (++sequenceBak & SEQUENCE_MAX)) { return nextIdBackup(timestamp + 1); } return ((timestamp - OFFSET) << OFFSET_SHIFT_BITS) | (WORKER_ID << WORKER_SHIFT_BITS) | (MODULE_CODE << MODULE_SHIFT_BITS) | sequence; } }