唯一ID生成器

分布式ID

概念:分库分表时全局唯一id

条件:

  1. 全局唯一
  2. 好性能:响应快
  3. 高可用:无限接近
  4. 好接入
  5. 趋势递增

生成方式:

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位为序列号。

  1. 对于不同的机器来说,可以为每一台机器分配一个唯一的机器ID,这样就可以保证每台机器锁生成的ID不会重复。

  2. 对于同一台机器,如果同一时刻多个客户端并发请求,那么可以通过增加序列号来保证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;
}

 

未完,敬请期待 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值