分布式id总体思想:全局唯一 + 局部唯一
1 基于UUID
UUID的核心思想是使用「机器的网卡、当地时间、一个随机数」来生成UUID
UUID.randomUUID().toString()就可以生成
2 基于DB数据库多种模式
数据库自增ID
指定主键auto_increment(自增)
数据库水平拆分,设置初始值和相同的自增步长
数据库自增ID出现的问题:ID重复、性能不好
数据库水平拆分,设置初始值和相同的自增步长 和 批量申请自增ID
批量申请自增ID
一次性给对应的数据库上分配一批的id值进行消费,使用完了,再回来申请
3 基于Redis
Redis本身有incr和increby 这样自增的命令,保证原子性,生成的ID也是有序的
使用Redis的方式还要考虑持久化,Redis的持久化有两种「RDB和AOF」,「RDB是以快照的形式进行持久化,会丢失上一次快照至此时间的数据」
第一种是使用RedisAtomicLong 原子类使用CAS操作来生成ID
@Service public class RedisSequenceFactory { @Autowired RedisTemplate<String, String> redisTemplate; public void setSeq(String key, int value, Date expireTime) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); counter.set(value); counter.expireAt(expireTime); } public void setSeq(String key, int value, long timeout, TimeUnit unit) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); counter.set(value); counter.expire(timeout, unit); } public long generate(String key) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); return counter.incrementAndGet(); } public long incr(String key, Date expireTime) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); counter.expireAt(expireTime); return counter.incrementAndGet(); } public long incr(String key, int increment) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); return counter.addAndGet(increment); } public long incr(String key, int increment, Date expireTime) { RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); counter.expireAt(expireTime); return counter.addAndGet(increment); } }
第二种是使用redisTemplate.opsForHash()和结合UUID的方式来生成生成ID
public Long getSeq(String key,String hashKey,Long delta) throws BusinessException{ try { if (null == delta) { delta=1L; } return redisTemplate.opsForHash().increment(key, hashKey, delta); } catch (Exception e) { // 若是redis宕机就采用uuid的方式 int first = new Random(10).nextInt(8) + 1; int randNo=UUID.randomUUID().toString().hashCode(); if (randNo < 0) { randNo=-randNo; } return Long.valueOf(first + String.format("%16d", randNo)); } }
5 基于雪花算法
采用64bit作为id生成类型,并且将64bit划分为,如下图的几段
Leaf和UidGenerator
美团Leaf算法需要依赖于数据库,ZK,并且也能保证去全局ID的唯一性,单项递增百度UidGenerator算法是基于雪花算法进行实现的,也是需要借助于数据库,与雪花算法不同的是,「UidGenerator支持自定义时间戳、主句中心ID和机器ID、序列号的位数」
参考:https://zhuanlan.zhihu.com/p/157978714 作者:Java程序员danni