1、方案说明

1.1、本方案没有使用时间戳,因为加入时间戳后长度会比较长。时间戳的方案可以参考百度和美团的。

1.2、本方案只利用分段自增的特性,在虚拟机中自增,不依赖redis,mysql等中间件的自增属性。

 

2、实现方案

2.1架构图

 

2.2 算法流程说明

1、代码中需要配置变量bit_type。

2、集群服务启动后,通过mysql的悲观锁(for update) 各个服务先后获取段的max_id,并更新保存新的max_id。

3、服务把号段生成数组保存在虚拟机中。

4、采用双号段,当前号段使用超过20%,则启动线程去更新空闲的号段。

 

2.3 设计和实现

数据库设计

算法

1、每个服务先后通过数据库锁和定义的步长计算自己的起始和结束序号。

2、把自增序列增长转换成二进制(长度要大于10位)。

3、使用0到1023的随机数,转换为二进制,从自增的第10位开始插入。

示例

java算法代码

public void test001() {
		
		Long  startIndex = 460000L;
		for(int i=0;i<800000;i++) {
			Integer f = RandomUtils.nextInt(1024);
			String r = full(Integer.toBinaryString(f));
			String seqString = Long.toBinaryString(startIndex+i);
			String seqFirString = seqString.substring(0, 10);
			String seqSeString = seqString.substring(10);
			
			String zString = seqFirString+r+seqSeString;
			if(i%5123==0) {
				System.out.println(seqFirString+"-"+r+"-"+seqSeString+"-"+Long.parseLong(zString, 2)+"-"+startIndex+i);
			}
		}
	}
	
	/**
	 * 填充位10位,防止少于10位
	 * @param src
	 * @return
	 */
	public String full(String src) {
		int n = 10-src.length();
		for(int i=0;i<n;i++) {
			src="0"+src;
		}
		return src;
	}

运行效果

1110000010-1011101111-011100000-471195360-4600000
1110001100-0101000100-011100011-476219619-4600005123
1110010110-0011001100-011100110-481401062-46000010246
1110100000-0100111011-011101001-486700777-46000015369
1110101010-1001010110-011101100-492088556-46000020492
1110110100-0100010101-011101111-497167087-46000025615
1110111110-0010101101-011110010-502356722-46000030738
1111001000-1111111100-011110101-508033269-46000035861
1111010010-0101001011-011111000-512923384-46000040984
1111011100-0100100010-011111011-518145275-46000046107
1111100110-0001011011-011111110-523286270-46000051230
1111110000-1101111101-100000001-528939777-46000056353
1111111010-0010010110-100000100-533802244-46000061476

//格式:前10位-10位随机-剩余位数-订单号-对应的自增id

 

问题:

1、对于qps比较高的应用step可以设置大些,这个可以通过监控更新频率去设置。

2、本方案对数据库依赖还是比较强,所以数据库不能宕机很久。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐