CREATE TABLE SEQID.SEQUENCE_ID (
id bigint(20) unsigned NOT NULL auto_increment,
stub char(10) NOT NULL default ‘’,
PRIMARY KEY (id),
UNIQUE KEY stub (stub)
) ENGINE=MyISAM;

可以使用下面的语句生成并获取到一个自增ID
```java
begin;
replace into SEQUENCE_ID (stub) VALUES ('anyword');
select last_insert_id();
commit;

stub字段在这里并没有什么特殊的意义,只是为了方便的去插入数据,只有能插入数据才能产生自增id。而对于插入我们用的是replace,replace会先看是否存在stub指定值一样的数据,如果存在则先delete再insert,如果不存在则直接insert。

这种生成分布式ID的机制,需要一个单独的Mysql实例,虽然可行,但是基于性能与可靠性来考虑的话都不够,业务系统每次需要一个ID时,都需要请求数据库获取,性能低,并且如果此数据库实例下线了,那么将影响所有的业务系统。

为了解决数据库可靠性问题,我们可以使用第二种分布式ID生成方案。

二、数据库多主模式

如果我们两个数据库组成一个主从模式集群,正常情况下可以解决数据库可靠性问题,但是如果主库挂掉后,数据没有及时同步到从库,这个时候会出现ID重复的现象。我们可以使用双主模式集群,也就是两个Mysql实例都能单独的生产自增ID,这样能够提高效率,但是如果不经过其他改造的话,这两个Mysql实例很可能会生成同样的ID。需要单独给每个Mysql实例配置不同的起始值和自增步长。

第一台Mysql实例配置:

set @@auto_increment_offset = 1; -- 起始值
set @@auto_increment_increment = 2; -- 步长

第二台Mysql实例配置:

set @@auto_increment_offset = 2; -- 起始值
set @@auto_increment_increment = 2; -- 步长

经过上面的配置后,这两个Mysql实例生成的id序列如下: mysql1,起始值为1,步长为2,ID生成的序列为:1,3,5,7,9,… mysql2,起始值为2,步长为2,ID生成的序列为:2,4,6,8,10,…

对于这种生成分布式ID的方案,需要单独新增一个生成分布式ID应用,比如DistributIdService,该应用提供一个接口供业务应用获取ID,业务应用需要一个ID时,通过rpc的方式请求DistributIdServiceDistributIdService随机去上面的两个Mysql实例中去获取ID。

实行这种方案后,就算其中某一台Mysql实例下线了,也不会影响DistributIdServiceDistributIdService仍然可以利用另外一台Mysql来生成ID。

但是这种方案的扩展性不太好,如果两台Mysql实例不够用,需要新增Mysql实例来提高性能时,这时就会比较麻烦。

现在如果要新增一个实例mysql3,要怎么操作呢? 第一,mysql1、mysql2的步长肯定都要修改为3,而且只能是人工去修改,这是需要时间的。 第二,因为mysql1和mysql2是不停在自增的,对于mysql3的起始值我们可能要定得大一点,以给充分的时间去修改mysql1,mysql2的步长。 第三,在修改步长的时候很可能会出现重复ID,要解决这个问题,可能需要停机才行。

为了解决上面的问题,以及能够进一步提高DistributIdService的性能,如果使用第三种生成分布式ID机制。

三、号段模式

我们可以使用号段的方式来获取自增ID,号段可以理解成批量获取,比如DistributIdService从数据库获取ID时,如果能批量获取多个ID并缓存在本地的话,那样将大大提供业务应用获取ID的效率。

比如DistributIdService每次从数据库获取ID时,就获取一个号段,比如(1,1000],这个范围表示了1000个ID,业务应用在请求DistributIdService提供ID时,DistributIdService只需要在本地从1开始自增并返回即可,而不需要每次都请求数据库,一直到本地自增到1000时,也就是当前号段已经被用完时,才去数据库重新获取下一号段。

所以,我们需要对数据库表进行改动,如下:

CREATE TABLE id_generator ( id int(10) NOT NULL, current_max_id bigint(20) NOT NULL COMMENT '当前最大id', increment_step int(10) NOT NULL COMMENT '号段的长度', PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这个数据库表用来记录自增步长以及当前自增ID的最大值(也就是当前已经被申请的号段的最后一个值),因为自增逻辑被移到DistributIdService中去了,所以数据库不需要这部分逻辑了。

这种方案不再强依赖数据库,就算数据库不可用,那么DistributIdService也能继续支撑一段时间。但是如果DistributIdService重启,会丢失一段ID,导致ID空洞。

为了提高DistributIdService的高可用,需要做一个集群,业务在请求DistributIdService集群获取ID时,会随机的选择某一个DistributIdService节点进行获取,对每一个DistributIdService节点来说,数据库连接的是同一个数据库,那么可能会产生多个DistributIdService节点同时请求数据库获取号段,那么这个时候需要利用乐观锁来进行控制,比如在数据库表中增加一个version字段,在获取号段时使用如下SQL:

update id_generator set current_max_id=#{newMaxId}, version=version+1 where version = #{version}

因为newMaxId是DistributIdService中根据oldMaxId+步长算出来的,只要上面的update更新成功了就表示号段获取成功了。

为了提供数据库层的高可用,需要对数据库使用多主模式进行部署,对于每个数据库来说要保证生成的号段不重复,这就需要利用最开始的思路,再在刚刚的数据库表中增加起始值和步长,比如如果现在是两台Mysql,那么 mysql1将生成号段(1,1001],自增的时候序列为1,3,4,5,7… mysql1将生成号段(2,1002],自增的时候序列为2,4,6,8,10…

在TinyId中还增加了一步来提高效率,在上面的实现中,ID自增的逻辑是在DistributIdService中实现的,而实际上可以把自增的逻辑转移到业务应用本地,这样对于业务应用来说只需要获取号段,每次自增时不再需要请求调用DistributIdService了。

四、雪花算法

上面的三种方法总的来说是基于自增思想的,而接下来就介绍比较著名的雪花算法-snowflake

我们可以换个角度来对分布式ID进行思考,只要能让负责生成分布式ID的每台机器在每毫秒内生成不一样的ID就行了。

snowflake是twitter开源的分布式ID生成算法,是一种算法,所以它和上面的三种生成分布式ID机制不太一样,它不依赖数据库。

核心思想是:分布式ID固定是一个long型的数字,一个long型占8个字节,也就是64个bit,原始snowflake算法中对于bit的分配如下图:

分布式ID(数据库多主模式,这些知识点你会吗相关推荐

  1. 最新高频Java面试题目分享,分布式ID(数据库多主模式

    三.号段模式 我们可以使用号段的方式来获取自增ID,号段可以理解成批量获取,比如DistributIdService从数据库获取ID时,如果能批量获取多个ID并缓存在本地的话,那样将大大提供业务应用获 ...

  2. 一口气说出 9种 分布式ID生成方式,面试官有点懵了

    写在前边 前两天公众号有个粉丝给我留言吐槽最近面试:"四哥,年前我在公司受点委屈一冲动就裸辞了,然后现在疫情严重两个多月还没找到工作,接了几个视频面试也都没下文.好多面试官问完一个问题,紧接 ...

  3. 分布式 ID的 9 种生成方式

    一.为什么要用分布式 ID? 在说分布式 ID 的具体实现之前,我们来简单分析一下为什么用分布式 ID?分布式 ID 应该满足哪些特征? 1.什么是分布式 ID? 拿 MySQL 数据库举个栗子: 在 ...

  4. 九种分布式ID生成方式

    一.为什么要用分布式ID? 在说分布式ID的具体实现之前,我们来简单分析一下为什么用分布式ID?分布式ID应该满足哪些特征? 1.什么是分布式ID? 拿MySQL数据库举个栗子:在我们业务数据量不大的 ...

  5. 九种分布式ID生成算法详解

    一.分布式ID简介 1.什么是分布式ID? 在我们业务数据量不大的时候,单库单表完全可以支撑现有业务,数据再大一点搞个MySQL主从同步读写分离也能对付. 但随着数据日渐增长,主从同步也扛不住了,就需 ...

  6. 分布式系统概念 | 分布式ID:数据库、号段模式、雪花算法(Snowflake)、Redis实现方案

    文章目录 分布式ID 数据库 自增ID 多主模式 号段模式 雪花算法 Redis 总结 分布式ID ID是数据的唯一标识,传统的做法是使用数据库的自增ID,但是随着业务规模的不断发展,数据量将越来越大 ...

  7. 大型互联网公司分布式ID方案总结

    ID是数据的唯一标识,传统的做法是利用UUID和数据库的自增ID,在互联网企业中,大部分公司使用的都是Mysql,并且因为需要事务支持,所以通常会使用Innodb存储引擎,UUID太长以及无序,所以并 ...

  8. easyui treegrid获取父节点的id_超简单的分布式ID生成方案!美团开源框架介绍

    目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持 RPC 阐述背景 不吹嘘,不夸张,项目中用到 ID 生成的场景确实挺多.比如业务要做幂等 ...

  9. 超简单的分布式ID生成方案!美团开源框架介绍

    目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持 RPC 阐述背景 不吹嘘,不夸张,项目中用到 ID 生成的场景确实挺多.比如业务要做幂等 ...

最新文章

  1. python面试常见问题-Python面试中最常见的25个问题
  2. MySQL show binlog events命令查看binlog日志内容
  3. aggregations 详解1(概述)
  4. 数据库显示日期时仅仅显示“年-月-日”的问题
  5. SIP与RTP综合应用5-RTP解包过程
  6. java properties文件 安全_java 数据库读取工具类(读取config.properties配置文件)[包含线程安全] | 学步园...
  7. SpringBoot2.0都更新了那些内容
  8. ASP .NET基本概念
  9. 正确选择报表工具的十大标准
  10. mvc 生成输出url
  11. mysql导出csv 分隔符_导出到CSV文件,CSV文件好像是以逗号为分隔符的吧?如果数据库字段里含有逗号怎么处理?比如说下面这个字...
  12. 如何使用SLM生成涡旋光束
  13. PSV 2000 3.68降级3.60固化教程
  14. 【历史上的今天】9 月 9 日:C 语言之父诞生;阿里巴巴成立
  15. shell了解MySQL_MySQL Shell的简单介绍(r12笔记第95天)
  16. 【08月13日】预分红股息率最高排名
  17. 蚂蚁金服 花呗借呗 招聘公告
  18. 查找Windows和MacBook序列号
  19. 桌面虚拟化的技术演变发展史
  20. 答一位网友《SBO有哪样的几种开发方式》

热门文章

  1. 在哪能看全国计算机考试试题,2016年全国计算机一级考试试题汇集
  2. 苹果藏在 iOS 14.3 中的新算法被发现,CSAM 检测技术再遭抗议!
  3. AWS 聘用 Rust 编译器联合创始人,大企为何都爱 Rust?
  4. 物联网大战打响,6 岁的涂鸦智能这样突出重围!
  5. 为什么说DeFi将催生银行业杀手级应用?
  6. “我们的边缘计算技术点,可能超前了业界一点”
  7. 超10000支团队参赛,阿里云首届云原生编程挑战赛完美收官
  8. 图解一致性哈希算法,看这文就够了!
  9. 滴滴自动驾驶首轮融资超5亿美元 加大研发投入 助力“新基建”
  10. 登 GitHub 趋势榜首德国疫情追踪 App 号称可保疫情隐私数据无忧,你信吗?