dromara / hutool

🍬A set of tools that keep Java sweet.
https://hutool.cn
Other
29.07k stars 7.5k forks source link

Performance issue of Snowflake #3581

Closed aofall closed 5 months ago

aofall commented 5 months ago

版本情况

JDK版本: jdk-8u_381 hutool版本: 5.8.26(请确保最新尝试是否还有问题)

问题描述(包括截图)

使用 Snowflake 的无参构造方法时,初始化实例需要较长时间。使用 arthas trace 发现因为每次都获取本机网卡 Mac 地址导致初始化实例需要较长时间。是否考虑将 DATACENTER_IDWORKER_ID 缓存/设置为静态变量以提高 Snowflake 的性能?一般来说网卡硬件在对外提供服务时不会轻易更换。

可以考虑一下这么修改

    private volatile long DATACENTER_ID = IdUtil.getDataCenterId(MAX_DATA_CENTER_ID);
    private volatile long WORKER_ID = IdUtil.getWorkerId(DATACENTER_ID, MAX_WORKER_ID);
    public Snowflake() {
        this(WORKER_ID);
    }
    public Snowflake(long workerId) {
        this(workerId, DATACENTER_ID);
    }
  1. 复现代码
Snowflake snowflake = new Snowflake();
snowflake.nextId();
  1. 堆栈信息

arthas trace 输出:

[arthas@22732]$ trace className methodName '#cost > 100'
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 113 ms, listenerId: 1
`---ts=2024-05-13 10:23:24;thread_name=XNIO-1 task-1;id=9c;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
    `---[1579.6784ms] className:methodName()
        +---[0.00% 0.0205ms ] className:methodName() #61
        +---[4.81% 75.991ms ] className:methodName() #61
        +---[0.00% 0.008ms ] className:methodName() #65
        +---[69.27% 1094.1848ms ] cn.hutool.core.lang.Snowflake:<init>() #68
        +---[0.00% 0.0319ms ] cn.hutool.core.lang.Snowflake:nextId() #69
        +---[0.00% 0.051ms ] className:methodName() #69
        +---[0.36% 5.6136ms ] com.fasterxml.jackson.databind.ObjectMapper:writeValueAsString() #72
        +---[25.49% 402.6902ms ] org.springframework.kafka.core.KafkaTemplate:send() #77
        `---[0.00% 0.0306ms ] className:methodName() #78

经观察: 无参构造 cn.hutool.core.lang.Snowflake#Snowflake() 初始化时调用了一次 cn.hutool.core.util.IdUtil#getDataCenterId 方法获取实例ID

无参构造调用有参构造 cn.hutool.core.lang.Snowflake#Snowflake(long) 初始化时又再次调用了 cn.hutool.core.util.IdUtil#getDataCenterId 方法获取实例ID

生成实例ID时cn.hutool.core.util.IdUtil#getDataCenterId ,获取本机网卡Mac地址耗时较长,导致无参 Snowflake 初始化时耗费时间较长。

[arthas@22732]$ trace cn.hutool.core.util.IdUtil getDataCenterId
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 39 ms, listenerId: 2
`---ts=2024-05-13 10:28:51;thread_name=XNIO-1 task-1;id=9c;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
    `---[546.1071ms] cn.hutool.core.util.IdUtil:getDataCenterId()
        +---[0.00% 0.0141ms ] cn.hutool.core.lang.Assert:isTrue() #207
        `---[99.98% 546.0187ms ] cn.hutool.core.net.NetUtil:getLocalHardwareAddress() #214
  1. 测试涉及到的文件(注意脱密)
looly commented 5 months ago

非常有道理~~

5.8.28 增加IdConstants,提高Snowflake初始化性能