前置要点:
在 Mybatis Plus 内置的雪花算法中,workerId
和 datacenterId
的最大长度为 5 位,即取值范围为:0~31。
核心代码:
// 计算 workerId 和 datacenterId
int loopCount = thirdSectionNum % MAX_IP_THIRD_SECTION_COUNT;
int workerId = (fourthSectionNum / 32) + (loopCount * 8);
int datacenterId = fourthSectionNum % 32;
代码说明:
- 本工具类总共可获取1024对
workerId
和datacenterId
。 thirdSectionNum
变量为IPv4地址中第三段的IP地址部分。MAX_IP_THIRD_SECTION_COUNT
为常量值:4,表示最大可使用4个连续的IPv4第三段地址。(例:10.10.103.x, 10.10.104.xx, 10.10.105.xxx, 10.10.106.x)fourthSectionNum
变量表示IPv4地址中第四段的值,本段内容没有限制,可以取 0~255 中任意值。- 代码总体思路:根据IP地址的值不同,将录入的IP平均分配到1024对
workerId
和datacenterId
的组合中。 - 第一行代码含义:取轮次。因为
workerId
最多可取32个值,IPv4第三段地址最大可使用4个连续的值,所以把32等分成4份,每份8个值, 余数的范围为:0~3。 - 第二行代码含义:计算
workerId
。因为第四段IP地址最大值为255,而workerId
的最大值为31,所以当前半部分的最大商为7时,后半部分的最大积为24时,仍可满足workerId
的最大值要求。 - 第三行代码含义:计算
datacenterId
。第四段IP地址对32取余,结果范围为0~31,符合datacenterId
的最大值要求。
局限性:
- 需要运维同学配合设置pod的IP地址范围,且必须满足地址的前两段不变,IP地址第三段存在多个可用的地址时,取值为连续的值(最多四个)。
- 本方法最多可获取到1024种不同结果,即最多启动1024个pod。
完整代码:
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 获取雪花算法 workerId 和 datacenterId 工具类
*
* 局限性:1. 服务必须可获取到pod的 IP 地址,且 IP 地址的前两段不变,第三段若存在多个可用地址,其必须为连续的值(最多四个)
* 2. 最多可获取到 1024 种不同结果
*/
public class IPBasedUniqueWorkerIdAndDatacenterIdGenerator {
/**
* IP地址第三段编号最大个数(32*32/256=4)
*/
private static final int MAX_IP_THIRD_SECTION_COUNT = 4;
/**
* IPv4 正则表达式验证规则
*/
private static final Pattern IPV4_PATTERN = Pattern.compile(
"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
/**
* 雪花算法 workerId
*/
public static final String KEY_WORKER_ID = "workerId";
/**
* 雪花算法 datacenterId
*/
public static final String KEY_DATACENTER_ID = "datacenterId";
/**
* 获取雪花算法 workerId 和 datacenterId(IP地址第三、四段都有变化)
*
* @param ip IP地址
*
* @return {@link Map<String, Integer>} workerId 和 datacenterId
* @author Supreme_Sir
* @date 2024/6/11 17:40
*/
public static Map<String, Integer> getWorkerIdAndDatacenterId(String ip) {
if (!isValidIPv4(ip)){
throw new RuntimeException("ip is not valid");
}
// 切分 IP 地址,获取第三段和第四段内容
String[] split = ip.split("\\.");
int thirdSectionNum = Integer.parseInt(split[2]);
int fourthSectionNum = Integer.parseInt(split[3]);
// 计算 workerId 和 datacenterId
int loopCount = thirdSectionNum % MAX_IP_THIRD_SECTION_COUNT;
int workerId = (fourthSectionNum / 32) + (loopCount * 8);
int datacenterId = fourthSectionNum % 32;
// 返回结果
Map<String, Integer> result = new HashMap<>();
result.put(KEY_WORKER_ID, workerId);
result.put(KEY_DATACENTER_ID, datacenterId);
return result;
}
/**
* 验证给定的字符串是否为有效的IPv4地址。
*
* @param ip 要验证的IP地址字符串
* @return 如果是有效的IPv4地址则返回true,否则返回false
*/
public static boolean isValidIPv4(String ip) {
Matcher matcher = IPV4_PATTERN.matcher(ip);
return matcher.matches();
}
}
---------------------------------------每个人都很努力,并不是只有你一个人满腹委屈。-------------------------------------