【解决问题】使用hutool工具包中ID生成器问题

注意在使用hutool工具包中,雪花算法生成分布式ID时,可能会使用不当,出现重复问题。

线上一共三台实例,而数据库表的数量已经接近八百万行,系统有一个功能,需要每次批量插入1000行的数据,查看日志请求,发现当时同一秒要处理多名用户的任务,导致用户无法批量插入出现异常。

问题所在:

//workerId : 终端ID
//dataCenterId: 数据中心ID
Snowflake SNOWFLAKE = IdUtil.getSnowflake(workerId,dataCenterId)

原因:发现当时三台实例中,有两台的workerId和dataCenterId都是一样。这个问题非常严重,先看一下源码中getSnowflake方法的具体实现。

	/**
	 * 获取单例的Twitter的Snowflake 算法生成器对象<br>
	 * 分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。
	 *
	 * <p>
	 * snowflake的结构如下(每部分用-分开):<br>
	 *
	 * <pre>
	 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
	 * </pre>
	 * <p>
	 * 第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年)<br>
	 * 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点)<br>
	 * 最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
	 *
	 * <p>
	 * 参考:http://www.cnblogs.com/relucent/p/4955340.html
	 *
	 * @param workerId     终端ID
	 * @param datacenterId 数据中心ID
	 * @return {@link Snowflake}
	 * @since 4.5.9
	 */
	public static Snowflake getSnowflake(long workerId, long datacenterId) {
		return Singleton.get(Snowflake.class, workerId, datacenterId);
	}
private static long getDataCenterId(long maxDataCenterId) {
        long id = 0L;
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                if (null != mac) {
                	//bug在这里,封装时候取得第一位和第二位的mac地址
                    id = ((0x000000FF & (long) mac[0]) | (0x0000FF00 & (((long) mac[1]) << 8))) >> 6;
                    id = id % (maxDataCenterId + 1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return id;
    }

看一下getDataCenterId()方法实现,取得mac地址的第一位和第二位生成的。然后查看服务器中的mac地址,发现两台事故机的mac地址前两位是一样的,而mac地址前两位是生产厂家标识,后四位字节是厂家特定序列号,无语至极,问题在封装的ID生成器。

因为如果每台实例的workerId和datacenterId一样,会发现重复的概率非常大,所以必须让每台实例中的workerId和datacenterId不一样,才能解决毫秒内产生最多的ID序列。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot,我们可以轻松地使用Hutool生成雪花IDHutool是一个Java工具库,其包括了各种各样的工具类,包括生成雪花ID的工具类。 下面是使用Hutool生成雪花ID的步骤: 1.导入Hutool的依赖 在您的Spring Boot项目的pom.xml文件添加以下依赖: ``` <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>x.x.x</version> </dependency> ``` 请将x.x.x替换为您使用Hutool版本。 2.生成雪花ID 在您的代码,可以使用Snowflake类来生成雪花ID。以下是一个简单的示例: ``` import cn.hutool.core.lang.Snowflake; import cn.hutool.core.util.IdUtil; public class Demo { public static void main(String[] args) { Snowflake snowflake = IdUtil.getSnowflake(1, 1); long id = snowflake.nextId(); System.out.println(id); } } ``` 在这个例子,我们创建了一个Snowflake对象,然后使用nextId()方法来生成一个雪花ID。 3.在Spring Boot使用雪花ID 在Spring Boot,您可以将Snowflake对象注入到您的bean,并在需要生成雪花ID的地方使用它。以下是一个示例: ``` import cn.hutool.core.lang.Snowflake; import cn.hutool.core.util.IdUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public Snowflake snowflake() { return IdUtil.getSnowflake(1, 1); } } ``` 在这个例子,我们创建了一个Snowflake对象,并将它作为一个bean注入到我们的应用程序。现在,我们可以在我们的代码使用它来生成雪花ID了。例如: ``` import cn.hutool.core.lang.Snowflake; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { @Autowired private Snowflake snowflake; @GetMapping("/id") public long getId() { return snowflake.nextId(); } } ``` 在这个例子,我们注入了Snowflake对象,并在我们的控制器使用它来生成雪花ID
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值