概述
项目中为了缓解数据库服务器压力和提高并发量进行分库分表,在新增数据时,如果此时按照传统方式使用数据库主键自增,那么在并发下ID可能会冲突; 使用UUID的话又因其无序会产生页分裂导致磁盘IO过大使得系统性能降低; 经过了解雪花算法根据其特点可以解决分布式系统中生成高性能、趋势递增、全局唯一ID, 因此项目中使用雪花算法策略生成ID
雪花算法特点
- 唯一性: 通过结合时间戳、机器ID和序列号,雪花算法可以生成几乎唯一的ID
- 高性能: 雪花算法在内存中生成ID,无需访问数据库或其他外部服务,因此具有很高的性能
- 趋势递增: 生成的ID是趋势递增的,这有助于数据库索引优化,提高查询效率
- 去中心化: 每个节点可以独立生成ID,无需协调,适合分布式系统
- 可定制性: 算法中的不同部分(时间戳、机器ID、序列号)可以根据实际需求进行调整
- 扩展
- 中心化生成主键方案
- 基于SEQUENCE区间方案
- 各数据库按特定步长自增
- 基于redis生成自增序列
- 去中心化生成主键方案
- UUID生成无序的唯一ID
- 雪花算法生成ID
- 中心化生成主键方案
项目最佳实践
- 引入第三方依赖
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId>
</dependency>
- 雪花Id生成工具类
import cn.hutool.core.lang.Snowflake;
import java.util.Random;public class SnowFlakeUtil {// 终端机器ID: 【0-31】private static long workerId = 1; // 数据中心ID: 【0-31】private static long dataCenterId = 1;private volatile static Snowflake snowflake; //雪花对象//静态块实现对象初始化static{Random rand=new Random();// 分布式环境下确保为每个实例配置了唯一的workerId和dataCenterId,以避免ID冲突,因此采取随机方法设置workerId = rand.nextInt(31)+1;//[1,31]内的随机整数dataCenterId = rand.nextInt(31)+1;//[1,31]内的随机整数snowflake = getInstance();}// Long型IDpublic static long nextId() {return snowflake.nextId();}// String类型IDpublic static String nextIdStr(){return snowflake.nextIdStr();}// 通过双重检测保证Snowflake对象在高并发下对象唯一private static Snowflake getInstance() {if (null == snowflake) {synchronized (SnowFlakeUtil.class) {if (null == snowflake) {snowflake = new Snowflake(workerId, dataCenterId);}}}return snowflake;}// 测试public static void main(String[] args) {System.out.println("IdLong: " + SnowFlakeUtil.nextId()); // IdLong: 1798609085217599488 雪花算法默认LongSystem.out.println("IdStr: " + SnowFlakeUtil.nextIdStr()); // IdStr: 1798609085217599489 某些场景下需要字符串类型}
}