主键详解(分布式环境,UUID,雪花算法,时钟回拨问题)——知识分享第一期

33 阅读3分钟

分布式环境下为什么不推荐使用自增ID?

可能出现的问题

  • A,B,C三个数据库分别存储主键值为0~300,301~600,601~900,在这种情况下去查询数据库,如果自增id没有达到设定的值,则会将压力给到前面的数据库,这样没有做到负载均衡,不合理

UUID可以用来做主键吗,会存在什么问题

  • UUID的全局唯一是最好的,但是由于不是有序自增的,可能会导致mysql的索引b+tree中已经构建好的结构发生变化,影响性能
  • MYSQL的bin_to_uuid()语法,能够交换uuid的时间低位和时间高位,可以使uuid变为有序的
  • bin_to_uuid(binary_uuid,swap_flag),binary_uuid为null时函数返回null,swap_flag的值可以为0或1,当为1时进行交换,使uuid变为有序的

雪花算法详解

  • 雪花算法的优点:
    • 全局唯一
    • 趋势递增
    • 信息安全(不会被猜到下一位)
  • 雪花算法的缺点:
    • 无法保证单调递增(还是会导致b+tree已经构建好的结构发生变化的,但是概率较小)
  • 雪花算法的构成
    1. 0 表示为正数
    2. 41位的时间戳 能表示69年,一般使用当前时间减去系统的上线时间
    3. 10位的机器码 1024,表示部署1024个服务
    4. 12位的序列号 4096,表示每毫秒最多能新增的数据条数

时钟回拨问题

  • 概念:当服务器的时间与真实时间出现了不匹配(有几秒的差异),此时需要将时间进行校准
  • 由于雪花算法强依赖时间戳,所以容易出现重复取号的问题,例如当服务器的时间为3秒时,真实的时间才1秒,此时我们需要将服务器的时间同步为正确的时间,但是这也会让雪花算法在1秒到3秒这个过程中出现重复取号的问题
  • 解决方案:
    • 当取号时间大于当前时间时,说明出现了时钟回拨问题,此时抛出异常
    • 当取号时间大于当前时间时,延迟等待,等待一定的时间后再进行取号
    • 使用时钟序列,可以将10位的机器码分为3位的时钟序号和7位的机器码,当每一次取号时间大于当前时间时,将时钟序号+1,也就是说在1毫秒内可以解决8次时钟回拨问题。当然在分布式架构中部署的服务数量也会因为机器码变为7位从而导致最大只能部署128个服务,所以如何取时钟序列的位数可以根据实际业务来定