千万级并发架构下,关系型数据库应该如何优化?大厂是如何做分库分表的! (5)

在数据库中专门创建一张序列表,利用数据库表中的自增ID来为其他业务的数据生成一个全局ID,那么每次要用ID的时候,直接从这个表中获取即可。

CREATE TABLE `uid_table` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `business_id` int(11) NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE (business_type) )

在应用程序中,每次调用下面这段代码,就可以持续获得一个递增的ID。

begin; REPLACE INTO uid_table (business_id) VALUES (2); SELECT LAST_INSERT_ID(); commit;

其中,replace into是每次删除原来相同的数据,同时加1条,就能保证我们每次得到的就是一个自增的ID

这个方案的优点是非常简单,它也有缺点,就是对于数据库的压力比较大,而且最好是独立部署一个DB,而独立部署又会增加整体的成本,这个在美团的leaf里面设计了一个很巧妙的设计方案,后面再讲

优点:

非常简单,利用现有数据库系统的功能实现,成本小,有DBA专业维护。

ID号单调自增,可以实现一些对ID有特殊要求的业务。

缺点:

强依赖DB,当DB异常时整个系统不可用,属于致命问题。配置主从复制可以尽可能的增加可用性,但是数据一致性在特殊情况下难以保证。主从切换时的不一致可能会导致重复发号。

ID发号性能瓶颈限制在单台MySQL的读写性能。

UUID

UUID的格式是: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 8-4-4-4-12共36个字符,它是一个128bit的二进制转化为16进制的32个字符,然后用4个-连接起来的字符串。

UUID的五种生成方式

基于时间的UUID(date-time & MAC address): 主要依赖当前的时间戳及机器mac地址,因此可以保证全球唯一性。(使用了Mac地址,因此会暴露Mac地址和生成时间。)

分布式安全的UUID(date-time & group/user id)将版本1的时间戳前四位换为POSIX的UID或GID。

基于名字空间的UUID-MD5版(MD5 hash & namespace),基于指定的名字空间/名字生成MD5散列值得到,标准不推荐。

基于随机数的UUID(pseudo-random number):基于随机数或伪随机数生成。

基于名字空间的UUID-SHA1版(SHA-1 hash & namespace):将版本3的散列算法改为SHA1

在Java中,提供了基于MD5算法的UUID、以及基于随机数的UUID。

优点:

本地生成,没有网络消耗,生成简单,没有高可用风险。

缺点:

不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。

信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。

无序查询效率低:由于生成的UUID是无序不可读的字符串,所以其查询效率低。

UUID不适合用来做数据库的唯一ID,如果用UUID做主键,无序的不递增,大家都知道,主键是有索引的,然后mysql的索引是通过b+树来实现的,每一次新的UUID数据的插入,为了查询的优化,都会对索引底层的b+树进行修改,因为UUID数据是无序的,所以每一次UUID数据的插入都会对主键的b+树进行很大的修改,严重影响性能

雪花算法

SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。雪花算法比较常见,在百度的UidGenerator、美团的Leaf中,都有用到雪花算法的实现。

如图6-11所示,表示雪花算法的组成,一共64bit,这64个bit位由四个部分组成。

第一部分,1bit位,用来表示符号位,而ID一般是正数,所以这个符号位一般情况下是0。

第二部分,占41 个 bit:表示的是时间戳,是系统时间的毫秒数,但是这个时间戳不是当前系统的时间,而是当前系统时间-开始时间,更大的保证这个ID生成方案的使用的时间!

那么我们为什么需要这个时间戳,目的是为了保证有序性,可读性,我一看我就能猜到ID是什么时候生成的。

41位可以241 - 1表示个数字,

如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 241-1,减1是因为可表示的数值范围是从0开始算的,而不是1。

也就是说41位可以表示241-1个毫秒的值,转化成单位年则是(241-1)/1000 * 60 * 60 * 24 *365=69年,也就是能容纳69年的时间

第三部分,用来记录工作机器id,id包含10bit,意味着这个服务最多可以部署在 2^10 台机器上,也就是 1024 台机器。

其中这10bit又可以分成2个5bit,前5bit表示机房id、5bit表示机器id,意味着最多支持2^5个机房(32),每个机房可以支持32台机器。

第四部分,第四部分由12bit组成,它表示一个递增序列,用来记录同毫秒内产生的不同id。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdsws.html