全局主键避重问题

MySQL 的数据库里面字段有一个自增的属性,Oracle 也有Sequence 序列。如果是一个数据库,那么可以保证ID 是不重复的,但是水平分表以后,每个表都按照自己的规律自增,肯定会出现ID 重复的问题,这个时候我们就不能用本地自增的方式了。

我们有几种常见的解决方案:

1)UUID(Universally Unique Identifier 通用唯一识别码)

UUID 标准形式包含32 个16 进制数字,分为5 段,形式为8-4-4-4-12 的36 个字符,例如:c4e7956c-03e7-472c-8909-d733803e79a9。

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

M 表示UUID 版本,目前只有五个版本,即只会出现1,2,3,4,5,数字N 的一至三个最高有效位表示UUID 变体,目前只会出现8,9,a,b 四种情况。

1、基于时间和MAC 地址的UUID

2、基于第一版却更安全的DCE UUID

3、基于MD5 散列算法的UUID

4、基于随机数的UUID——用的最多,JDK 里面是4

5、基于SHA1 散列算法的UUID

 UUID 是主键是最简单的方案,本地生成,性能高,没有网络耗时。但缺点也很明显,由于UUID 非常长,会占用大量的存储空间;另外,作为主键建立索引和基于索引进行查询时都会存在性能问题,在InnoDB 中,UUID 的无序性会引起数据位置频繁变动,导致分页。

2) 数据库

把序号维护在数据库的一张表中。这张表记录了全局主键的类型、位数、起始值,当前值。当其他应用需要获得全局ID 时,先for update 锁行,取到值+1 后并且更新后返回。并发性比较差。

3)Redis

基于Redis 的INT 自增的特性,使用批量的方式降低数据库的写压力,每次获取一段区间的ID 号段,用完之后再去数据库获取,可以大大减轻数据库的压力。

4)雪花算法Snowflake(64bit)

核心思想:

a)使用41bit 作为毫秒数,可以使用69 年

b)10bit 作为机器的ID(5bit 是数据中心,5bit 的机器ID),支持1024 个节点

c)12bit 作为毫秒内的流水号(每个节点在每毫秒可以产生4096 个ID)

d)最后还有一个符号位,永远是0。

代码:snowflake.SnowFlakeTest

优点:毫秒数在高位,生成的ID 整体上按时间趋势递增;不依赖第三方系统,稳定性和效率较高,理论上QPS 约为409.6w/s(1000*2^12),并且整个分布式系统内不会产生ID 碰撞;可根据自身业务灵活分配bit 位。

不足就在于:强依赖机器时钟,如果时钟回拨,则可能导致生成ID 重复。

当我们对数据做了切分,分布在不同的节点上存储的时候,是不是意味着会产生多个数据源?既然有了多个数据源,那么在我们的项目里面就要配置多个数据源。

现在问题就来了,我们在执行一条SQL 语句的时候,比如插入,它应该是在哪个数据节点上面执行呢?又比如查询,如果只在其中的一个节点上面,我怎么知道在哪个节点,是不是要在所有的数据库节点里面都查询一遍,才能拿到结果?

那么,从客户端到服务端,我们可以在哪些层面解决这些问题呢?

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值