主键详解(分布式环境,UUID,雪花算法,时钟回拨问题)——知识分享第一期
分布式环境下为什么不推荐使用自增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已经构建好的结构发生变化的,但是概率较小)
- 雪花算法的构成
- 0 表示为正数
- 41位的时间戳 能表示69年,一般使用当前时间减去系统的上线时间
- 10位的机器码 1024,表示部署1024个服务
- 12位的序列号 4096,表示每毫秒最多能新增的数据条数
时钟回拨问题
- 概念:当服务器的时间与真实时间出现了不匹配(有几秒的差异),此时需要将时间进行校准
- 由于雪花算法强依赖时间戳,所以容易出现重复取号的问题,例如当服务器的时间为3秒时,真实的时间才1秒,此时我们需要将服务器的时间同步为正确的时间,但是这也会让雪花算法在1秒到3秒这个过程中出现重复取号的问题
- 解决方案:
- 当取号时间大于当前时间时,说明出现了时钟回拨问题,此时抛出异常
- 当取号时间大于当前时间时,延迟等待,等待一定的时间后再进行取号
- 使用时钟序列,可以将10位的机器码分为3位的时钟序号和7位的机器码,当每一次取号时间大于当前时间时,将时钟序号+1,也就是说在1毫秒内可以解决8次时钟回拨问题。当然在分布式架构中部署的服务数量也会因为机器码变为7位从而导致最大只能部署128个服务,所以如何取时钟序列的位数可以根据实际业务来定