分布式ID的简单实现

在上一篇博文(JDK自带UUID的性能问题)中我提到的一个满足我们需求,并能代替UUID的分布式ID的方案。在这里我做了简单的实现。

实现如下:
8位用作机器名
50位用作timestamp
6位用作标识符
 

用8位表示机器,可以表示256台机器。
50位表示的timestamp(毫秒),一年31536000000毫秒,可以表示35702年。
6位标识符,标识符只有在同一时间点上有两次ID的请求时会用到,用来区别这两个ID.6位表示64,也就是说只要你请求ID的TPS<64000,就不会有问题。

经过我简单的测试,这个实现在单线程下性能要比JDK自带UUID好一个数量级。在多线程下就更不用说了,因为我这个实现没有用同步。不过这两个本身也没有可比性。

import java.util.concurrent.atomic.AtomicLong;

/**
 * This class is used for generating unique id in a distributed environment. 
 * It require a server identifier. Server identifier is a 0-255 integer.
 * DistributedID(64 bits) = ServerID(8) + Time(50) + clk_seq(6)
 * @author "Peter Lu"
 */
public class DistributedID {
	
    /**
     * The last time value. Used to remove duplicate IDs.
     */
    private final static AtomicLong lastTime = new AtomicLong(Long.MIN_VALUE);
    
    /**
     * generate distributed ID. 
     * 
     * @param serverIdentifier support 256 servers. 0-255
     * @return
     */
    public static String getDistributedID(int serverIdentifier) {
    	
    	long dentifier = (long)serverIdentifier << 56;
    	
    	long distributedID = dentifier | genTimeBasedID();
    	
    	String id = Long.toHexString(distributedID);
    	
    	while(id.length()<16) {
    		id = "0" + id;
    	}
    	
    	return id;
    }
    
	/**
     * Generates a new time field. Each time field is unique and larger than the
     * previously generated time field. 
	 * @return
	 */
	private static long genTimeBasedID() {
		return genTimeBasedID(System.currentTimeMillis());
	}
    
	/**
     * generate a new time field from the given timestamp. Note that even identical
     * values of <code>time</code> will produce different time fields.
	 * @param time
	 * @return
	 */
	private static long genTimeBasedID(long time) {
		
		// 6 bits for clk_seq
		time = time << 6;
		
		// try again if compareAndSet failed
		while(true) {
			long tempTime = lastTime.get();
			if(time>tempTime) {
				if(lastTime.compareAndSet(tempTime, time)) {
					break;
				}
			} else {
				// +1 to make sure the timestamp field is different 
                                //even the time is identical.
				if(lastTime.compareAndSet(tempTime, ++tempTime)) {
					time = tempTime;
					break;
				}
			}
		}
		return time;
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
在 Java 中实现分布式自增 ID 可以使用 Snowflake 算法,该算法使用一个 64 位的二进制数字,其中前 41 位为时间戳,接着是 10 位的机器 ID 和 12 位的序列号。 以下是一个简单的 Java 实现: ```java public class SnowflakeIdGenerator { // 开始时间戳(2021-01-01) private final static long START_TIMESTAMP = 1609430400000L; // 机器 ID 所占位数 private final static long MACHINE_BITS = 10L; // 序列号所占位数 private final static long SEQUENCE_BITS = 12L; // 最大机器 ID private final static long MAX_MACHINE_ID = ~(-1L << MACHINE_BITS); // 最大序列号 private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS); // 机器 ID 左移位数 private final static long MACHINE_SHIFT = SEQUENCE_BITS; // 时间戳左移位数 private final static long TIMESTAMP_SHIFT = MACHINE_BITS + SEQUENCE_BITS; // 当前机器 ID private long machineId; // 当前序列号 private long sequence = 0L; // 上次生成 ID 的时间戳 private long lastTimestamp = -1L; public SnowflakeIdGenerator(long machineId) { if (machineId > MAX_MACHINE_ID || machineId < 0) { throw new IllegalArgumentException(String.format("Machine ID can't be greater than %d or less than 0", MAX_MACHINE_ID)); } this.machineId = machineId; } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & MAX_SEQUENCE; if (sequence == 0) { timestamp = nextTimestamp(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT) | (machineId << MACHINE_SHIFT) | sequence; } private long nextTimestamp(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } } ``` 使用示例: ```java SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1); long id = idGenerator.nextId(); ``` 该实现中,机器 ID 和序列号都是自增的,时间戳取当前时间,如果当前时间小于上一次生成 ID 的时间戳,则抛出异常。如果当前时间等于上一次生成 ID 的时间戳,则序列号自增,如果序列号超过最大值,则等待下一个时间戳。如果当前时间大于上一次生成 ID 的时间戳,则序列号重置为 0。最后,将时间戳、机器 ID 和序列号拼接成一个 64 位的二进制数字作为 ID 返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值