数据库演进之路提到了当数据库的压力瓶颈到了,咱们能够采纳分库分表来分担数据库的压力,分库分表的状况下,主键是怎么设置的?
数据库主键自增长
失常状况下,如果每个数据库都自增长,那就会呈现多个数据库 id 反复的问题,比方下图所示,都呈现了 id 为 1,2,3 的主键。
为了防止上述的问题,咱们能够在每个数据库设置一个初始值,以及设置每次的增量,如下图所示,第一个数据库初始值是 1,增量是 3,id 就是 1,4,7。
尽管防止了 ID 反复,然而 id 的递增是没有方法保障的,比方数据库 1 的 id 是 1,4,7,10。数据库 2 的 id 是 2,5,数据库 3 的 id 是 3。而且前面如果要扩容,也是很麻烦。
既然数据库自身没方法生成 id,那咱们能够用一个专门的数据库生成自增长的 id。尽管 id 能够自增长,不反复,递增,但此时所有的压力都在生成 id 的数据库上。
为了缓解数据库的压力,能够一次性生成 N 个主键,比方 100,而后存在缓存利用中,数据库每次须要 id 的时候,去缓存利用取。
毛病就是又多了一层服务。取一个自增长 id 要缓存服务 + 数据库。
下面的主键生成用 redis 行不行?尽管 redis 速度比拟快,然而没有实时长久化,可能造成主键的反复。比方此时为 9,incr 后变成 10,而后挂了,此时还没长久化,再生成 id 的时候还是 9,而后 incr 为 10,就有两个 id 为 10 的数据。即使做了故障转移,因为是异步同步数据的,有可能数据还没到 slave,master 就挂了,此时 id 还是会反复。
除了数据库的压力,自增长的主键还可能泄露商业秘密,他人很容易拆到下一个主键是什么。
UUID
才用数据库生成主键,数据库压力就很大,那能够采纳利用来生成。比较简单的就是 UUID,性能好,不反复。毛病就是不能保障递增,而且 UUID 字符串比拟长,索引性能很差。
工夫戳
以以后毫秒作为主键,长处就是简略、递增,毛病就是可能反复。比方以后毫秒同时有 10 个并发,此时就反复了。为了缩小反复,升高到微秒级别,或者在工夫戳前面加个随机字符串,仍然有反复的危险。
snowflake
snowflake 是 twitter 开源的分布式 ID 生成算法,生成 64 位的 bit,第一位是 0,保障 id 是负数。前面 41 位是以后工夫戳的二进制模式,再前面 10 位机器码的二进制,最初 12 位是计数顺序号,记录同一毫秒内生成的数量。
比方以后工夫为 2020-01-01 00:00:00,转换工夫戳为 1577808000000,再转二进制为 10110111101011100101011110111010000000000。此时,后面 42 位为:
假如以后的机器码为 100,转为二进制为 1100100,因为不满 10 位,咱们在后面补 3 个 0,后果为 0001100100。此时,后面 52 位为:
如果同一毫秒,同一个机器的并发比拟大,此时生成的数据就有反复的,所以 snowflake 就有前面的 12 位作为计数器,比方第一个拜访的是 1,第二个拜访的是 2,假如咱们此时为以后毫秒的第 200 个获取 id 的,200 转为二进制为 11001000,补 0 后为 000011001000,此时,后面 64 位为:
如果感觉前面的 12 位不够,咱们能够压缩后面机器码的位数,这样计数顺序号的值就能够更大了。
毛病也很显著,因为这个算法是依赖工夫戳的,所以当零碎的工夫回拨的时候,就可能造成 id 的反复