雪花算法的机器id重复-创新互联

通常雪花算法的机器id是根据网络ip地址计算得到的一个long类型值。从阿里的nacos扒下来的雪花算法实现:

创新互联公司专业为企业提供湛河网站建设、湛河做网站、湛河网站设计、湛河网站制作等企业网站建设、网页设计与制作、湛河企业网站模板建站服务,十年湛河做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
static {InetAddress address = NetUtil.getLocalAddress0();
        if (address == null) {throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!");
        }
        byte[] ipAddressByteArray = address.getAddress();
        hostIp = address.getHostAddress();
        workerId = (((ipAddressByteArray[ipAddressByteArray.length - 2] & 0B11)<< Byte.SIZE) + (
                ipAddressByteArray[ipAddressByteArray.length - 1] & 0xFF));
        log.info("snowflower workerId: {}", workerId);
    }

getLocalAddress0方法的实现 NetworkInterface的getInetAddress对象,返回的是Inet6Address

public static InetAddress getLocalAddress0() {InetAddress localAddress = null;


        // @since 2.7.6, choose the {@link NetworkInterface} first
        try {NetworkInterface networkInterface = findNetworkInterface();
            Enumerationaddresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {OptionaladdressOp = toValidAddress(addresses.nextElement());
                if (addressOp.isPresent()) {try {if (addressOp.get().isReachable(100)) {return addressOp.get();
                        }
                    } catch (IOException e) {// ignore
                    }
                }
            }
        } catch (Throwable e) {log.warn("{}", e.getMessage(), e);
        }

        try {localAddress = InetAddress.getLocalHost();
            OptionaladdressOp = toValidAddress(localAddress);
            if (addressOp.isPresent()) {return addressOp.get();
            }
        } catch (Throwable e) {log.warn("{}", e.getMessage(), e);
        }


        return localAddress;
    }

getValidNetworkInterfaces方法的实现:
返回53个主机上的网络接口,名字是lo eth1 eth2 … net0 net1 wlan0等等。这些ip地址都是ipv6的。NetworkInterface类。

private static ListgetValidNetworkInterfaces() throws SocketException {ListvalidNetworkInterfaces = new LinkedList<>();
        Enumerationinterfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {NetworkInterface networkInterface = interfaces.nextElement();
            validNetworkInterfaces.add(networkInterface);
        }
        return validNetworkInterfaces; 
    }

findNetworkInterface方法的实现:

public static NetworkInterface findNetworkInterface() {ListvalidNetworkInterfaces = Collections.emptyList();
        try {validNetworkInterfaces = getValidNetworkInterfaces();
        } catch (Throwable e) {log.warn("{}", e.getMessage(), e);
        }

        for (NetworkInterface networkInterface : validNetworkInterfaces) {Enumerationaddresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {OptionaladdressOp = toValidAddress(addresses.nextElement());
                if (addressOp.isPresent()) {try {if (addressOp.get().isReachable(100)) {return networkInterface;
                        }
                    } catch (IOException e) {// ignore
                    }
                }
            }
        }

        return validNetworkInterfaces.get(0);
    }

上面的代码含义是获取主机的所有网络接口。然后从第一个网络接口开始,如果可访问(isReachable(100)),就将这个IP地址返回。相同的ip地址必然产生相同的机器id(workerId)

今天的坑是因为服务器不同,ipv4地址不同,但是ipv6地址相同。使用了ipv6地址生成的workerId,就必然相同了。影响了雪花算法。以及其它用workerid作分布式的业务。

因为只有测试环境的ipv6地址都相同;线上的不会相同,所以为了测试,在IDEA edit configuration里加上的-Djava.net.preferIPv4Stack=true,这时看到所有的接口用的ipv4。
例如lo的地址,不加这个option,是16个字节的0::1;加了就是4个字节的127.0.0.1

后期改进,可以先从文件读取workerId, 如果没有再生成,并保存到文件中。避免主机ip地址变更导致的workerid变更问题。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前标题:雪花算法的机器id重复-创新互联
网站URL:http://azwzsj.com/article/deooii.html