目的:设计一个可以生成递增的long类型唯一 ID 的生成器
- long 类型占用空间小,可以表示的 ID 范围足够大。
- long 类型容易实现递增效果。
分布式唯一 ID
在复杂的系统中,实体需要 ID 做唯一标识,方便操作。 如:每个用户有唯一用户 ID 等等。
全局唯一与 UUID
全局唯一:无论业务实体的数据被分散到多少个数据库中,每条数据的唯一 ID 都是全局的。
UUID
UUID :通用唯一识别码 ( Universally Unique Identifier , UUID ),是计算机体系中用于识别信息的一个 128 位标识符。
UID 的标准格式由 32 个十六进制数字组成,并通过连字符“-”分隔成 “8-4-4-4-12”共 36 个字符的形式 。
例如:“6a0d3e6f-allc-4b7d-bb35-c4c530a456b0”,“123e4567-e89b-12d3-a456-426655440000 ”
- 自增主键做唯一 ID:
- 全局不唯一,数据量少,没有分库分表 可以满足。
- 做了分库分表之后,数据表之间是相互独立的,插入数据时,会生成相同的自增主键。
- UUID 做唯一 ID:
- 生成简单,本地计算就可以生成全球唯一的 UUID。
- 占用 36 字节,海量数据下浪费内存。
- UUID 是无规律的,做为主键,会导致数据在磁盘中频繁移动(页分裂、页合并),影响数据库性能。
唯一 ID 生成器特点
- 不重复
- 空间占用小
- 高并发、高可用:作为大多数服务的依赖方,唯一 ID 生成的操作要做到高并发,维持长期高可用。
- 唯一 ID 可用作数据库主键:不对数据库的写操作造成负面影响,需要保证唯一 ID 对数据库主键友好。
- 对于 InnoDB 引擎,使用自增性质的主键,唯一 ID 在数值上是递增的。
- 不顺序插入,会有页分裂现象,增加时间开销。
- 对于 InnoDB 引擎,使用自增性质的主键,唯一 ID 在数值上是递增的。
单调递增和趋势递增


受限于全局时钟、延迟等分布式系统问题,单调递增的唯一 ID 生成器会有局限性,相对的,趋势递增的唯一 ID 生成器更受业界欢迎。
单调递增的唯一 ID
Redis INCYBY 命令
incrby seq_id 1
生成唯一 ID 的请求到来时,唯一 ID 生成器对 seq_id 加 1,并将操作完之后的值返回。
批量获取优化

- 唯一 ID 生成器服务可以每次从 Redis 中批量获取 ID 并存储到本地内存中。
- 当业务服务请求到来时 , 直接从本地内存返回最小可用的 ID 。
- 如果本地内存中没有可用的 ID, 则再次从 Redis 中批量获取。
package com.wispx.service;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class IdGeneratorService {
// redis 客户端
private StringRedisTemplate stringRedisTemplate;
// 互斥锁
private Lock lock = new ReentrantLock();
// 下一个可用 ID,初始值为 -1
private long nextIdAvailable = -1;
// 最大可用 ID
private long maxIdAvailable;
/**
* 从 Redis 中批量获取 ID
* @param count 获取的数量
* @return 返回 null 说明获取成功
*/
private Exception multiGenIDFromRedis(int count){
// 最后插入的 ID
long lastInsertId;
try{
lastInsertId = (long)stringRedisTemplate.opsForValue().increment("seq_id",count);
}<

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



