分布式ID
概念:分库分表时全局唯一id
条件:
- 全局唯一
- 好性能:响应快
- 高可用:无限接近
- 好接入
- 趋势递增
生成方式:
UUID:
java
public static void main(String[] args) {
String uuid = UUID.randomUUID().toString().replaceAll("-","");
System.out.println(uuid);
}缺点:无序字符串
数据库自增id
id自增,高并发不适用
数据多主模式
mysql1配置:起始值1,步长为2 1、3、5、7
mysql1配置:起始值2,步长为2 2、4、6、8
不利于后续扩容
号段模式
从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。
Redis
redis的incr
雪花算法
Snowflake
生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。Snowflake ID组成结构:
正数位
(占1比特)+时间戳
(占41比特)+机器ID
(占5比特)+数据中心
(占5比特)+自增值
(占12比特),总共64比特组成的一个Long类型。
第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
工作机器id(10bit):也被叫做
workId
,这个可以灵活配置,机房或者机器号组合都可以。序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID
php 方法uniqid()
```
uniqid()是通过微妙级时间戳来实现的,在分布式高并发的情况下,ID的重复率是很高的,所以我们不能使用uniqid()来生成唯一ID
```
# snowflake算法
```
高端的第一位不使用,接着的41位字节用于存储毫秒级的时间戳,紧跟着时间戳的10位作为机器ID,而最后12位为序列号。
-
对于不同的机器来说,可以为每一台机器分配一个唯一的机器ID,这样就可以保证每台机器锁生成的ID不会重复。
-
对于同一台机器,如果同一时刻多个客户端并发请求,那么可以通过增加序列号来保证ID唯一性。
默认情况下41位的时间戳可以支持该算法使用到2082年(需要通过减去一个起始时间戳),10位的工作机器ID可以支持1023台机器,12位的序列号支持1毫秒产生4095个自增序列ID。
也就是说1台机器1秒可以承受4095000个并发,可以胜任任何场景
```
static uint64_t last_ts = 0;
static uint64_t sequence = 0;
static uint64_t datacenter_id = 0;
// 获取毫秒时间戳
uint64_t current_timestamp()
{
struct timeval tv;
uint64_t retval;
if (gettimeofday(&tv, NULL) == -1) {
return 0ULL;
}
retval = (u64_t)tv.tv_sec * 1000ULL +
(u64_t)tv.tv_usec / 1000ULL;
return retval;
}
// 如果在同一毫秒内超过了并发现在, 那么等待下一毫秒
uint64_t skip_next_millis()
{
uint64_t ts;
while (1) {
ts = current_timestamp();
if (ts > last_ts) {
break;
}
}
return ts;
}
// 获取下一个ID
uint64_t get_next_id()
{
uint64_t retval, ts;
ts = current_timestamp();
if (ts == last_ts) { // 同一毫秒内多个并发
sequence = (sequence + 1) & 0xFFF; // 增加序列号计数器
if (sequence == 0) { // 计数器用完
ts = skip_next_millis(); // 等待下一毫秒
}
} else {
sequence = 0; // 清空序列号计数器
}
last_ts = ts;
retval = (ts << 22) | (datacenter_id << 12) | sequence;
return retval;
}
未完,敬请期待