【分布式】分布式ID生成-基于数据库方案设计

目录

1. 需求

2.方案设计

2.1 数据库设计

2.2 代码设计

2.2.1 缺陷:

2.2.3 优化方案

2.2.4 新缺陷:

2.2.5 优化方案2


1. 需求

  1. 全局唯一,绝对不会出现重复的ID,且ID整体趋势递增。
  2. 高可用,服务完全基于分布式架构,即使MySQL宕机,也能容忍一段时间的数据库不可用。
  3. 高并发低延时,远程调用QPS可达5W+,TP99在1ms内。
  4. 接入简单,通过RPC或者HTTP调用即可接入。

2.方案设计

2.1 数据库设计

数据库中建立如下表,以seq_name为单位,每个seq有独立的id序列。

CREATE TABLE `sequence` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `seq_name` varchar(45) NOT NULL COMMENT '序列名称',
  `seq_value` bigint(20) unsigned NOT NULL COMMENT '序列值',
  `min_value` bigint(20) NOT NULL COMMENT '最小值',
  `max_value` bigint(20) NOT NULL COMMENT '最大值',
  `step` bigint(20) NOT NULL COMMENT '步长',
  `memo` varchar(64) DEFAULT NULL COMMENT '备注',
  `gmt_create` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `gmt_modified` timestamp NULL DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=189 DEFAULT CHARSET=gbk COMMENT='seq生成表';

2.2 代码设计

获取流水号第一反应就是每次都去更新数据库的seq_value,但是由于update的耗时长,并发不了(有写锁),会导致并发低,延迟高,不能满足性能需求。优化方案是预分发的思路:

  1. 取段:每次从数据库中获取一批SequenceRange流水号,将这个范围缓存起来,并更新数据库seq_value=seq_value+step,这样这一批的流水号就不会被别的机器获取到(无重复要求)。
  2. 段中取号:每次获取时先从缓存的返回去获取value.getAndIncrement(),如果获取到的id达到范围的max

2.2.1 缺陷:

  1. 在更新DB的时候会出现耗时尖刺,系统最大耗时取决于更新DB号段的时间。
  2. 当更新DB号段的时候,如果DB宕机或者发生主从切换,会导致一段时间的服务不可用

2.2.3 优化方案

异步更新 for 耗时尖刺

号段消费到10%且下个号段未ready,异步线程获取下一个id段,不会影响同步获取id流程的耗时。

双Buffer for 可用性

一次取两个id段buffer,这样DB出现问题能有一个Buffer的号段可以正常对外提供服务,只要DB在一个Buffer的下发的周期内恢复,就不会影响可用性。

2.2.4 新缺陷:

  1. 号段长度固定的,假如Leaf本来能在DB不可用的情况下,维持10分钟正常工作,如果流量增加10倍就只能维持1分钟了。
  2. 号段长度设置的过长,导致缓存中的号段迟迟消耗不完,进而导致更新DB的新号段与前一次下发的号段ID跨度过大。

2.2.5 优化方案2

动态调整Step

服务QPS为Q,号段长度为L,号段更新周期为T,那么Q * T = L。

最开始L长度是固定的,导致随着Q的增长,T会越来越小。但是Leaf本质的需求是希望T是固定的。那么如果L可以和Q正相关的话,T就可以趋近一个定值了。所以Leaf每次更新号段的时候,根据上一次更新号段的周期T和号段长度step,来决定下一次的号段长度nextStep:

  • T < 15min,nextStep = step * 2
  • 15min < T < 30min,nextStep = step
  • T > 30min,nextStep = step / 2

至此,满足了号段消耗稳定趋于某个时间区间的需求。当然,面对瞬时流量几十、几百倍的暴增,该种方案仍不能满足可以容忍数据库在一段时间不可用、系统仍能稳定运行的需求。因为本质上来讲,Leaf虽然在DB层做了些容错方案,但是号段方式的ID下发,最终还是需要强依赖DB。

发布了132 篇原创文章 · 获赞 122 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sarafina527/article/details/105573190