分布式主键

2024-09-02 07:04
文章标签 分布式 主键

本文主要是介绍分布式主键,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.分布式主键的基本需求

2.常见的分布式主键生成策略

2.1UUID(128位)

2.2MySQL

2.2.1自增主键

2.2.2区间号段

2.3Redis

2.4SnowFlake雪花算法(64位)


1.分布式主键的基本需求

全局唯一:不管什么主键,都需要全局唯一。
高性能高可用:分布式主键服务本身就是一个底层的服务,很多服务都依赖于这个服务,如果底层服务都不稳定,那么上游的服务就更谈不上稳定。
递增:大部分数据存储使用MySQL存储数据,为了快速存储和检索,分布式主键生成策略总趋势要求是递增的。

2.常见的分布式主键生成策略

2.1UUID(128位)

在Java中自带的UUID就具有唯一性。如下面代码所示。生成的结果不是数字,是字符串

UUID 是由128位二进制数组成,通常表示为32个十六进制字符。

public static void main(String[] args) {String uuid = UUID.randomUUID().toString().replaceAll("-","");System.out.println(uuid);//e48126eb0e6646638b043fca85f38818
}

优点:简单,没有网络消耗。

缺点:

  • 不保证大趋势递增,不利于检索,对索引的构建和维护成本比较大。
  • 长度过长,不利于存储。
  • 没有具体的业务含义。

2.2MySQL

2.2.1自增主键

基于数据库的自增主键充当分布式ID服务器。

具体实现
1)创建一个SEQUENCE_ID表(id,value)
2)每次请求该分布式主键服务时 向SEQUENCE_ID 插入一条数据,并返回自增主键作为分布式主键

优点:实现简单,自增有序;

缺点:DB单点存在宕机风险,扛不住高并发场景。

对于MySQL集群,单点数据库方式不可取,那对上边的方式做一些高可用优化,换成主从模式集群。害怕一个主节点挂掉没法用,那就做双主模式集群,也就是两个Mysql实例都能单独的生产自增ID。(起始值+自增步长)

2.2.2区间号段

以单节点为例,在数据库中维护一个SEQUENCE_ID表。表中定义的是一个order主键生成规则和user主键生成规则。简单对表做一下解释,biz_code表示一种主键,max_id表示已经分配的最大ID,step表示步长用于每次生成一批主键

biz_code

max_id

step

desc

update_time

order

11000

1000

订单表

2022-09-06

user

1000

100

用户表

2022-09-09

在上面数据库的原始数据之上,此时上线了3个节点的订单服务。当用户创建订单时,Order_Node1节点会请求主键服务器生成一批主键,此时数据库表记录为

biz_code

max_id

step

desc

update_time

order

11000

1000

订单表

2022-09-06

[max_id + 1 , max_id + step]这批主键会返回给Order_Node1,即[11001,12000],此时会更新表的数据为

biz_code

max_id

step

desc

update_time

order

12000

1000

订单表

2022-09-07

每个节点的内存中存的是一批主键ID,当时候完毕后再去申请一批数据,效率极高

优点:

  • 并发压力不会再MySQL主键服务器侧。
  • 容灾性好,我一次给你一批,即使主键服务器挂了,Node内存中的主键可以继续使用,Node不应该order_node对外提供服务。

缺点:每当请求主键服务器申请一批主键时,TP 999数据会偶尔出现尖刺。因为当Clinet大量的请求到Order_Node时因没有主键去申请主键时会导致这一批的请求时间会hang住。

双Buffer优化

针对 区间号段 中出现尖刺的情况,使用双Buffer进行优化。

首先申请一批主键,当使用到该批次的10%时,后台起一个线程申请下一批主键,这样一种预加载的情况可以时主键串联起来,有效解决上面的请求RT抖动情况。

2.3Redis

原理就是利用redis的incr命令实现ID的原子性自增

127.0.0.1:6379>set seq_id 1 // 初始化自增ID为1 
OK 
127.0.0.1:6379> incr seq_id // 增加1,并返回递增后的数值 
(integer)2

优点:

  • 极大降低了主键服务器MySQL的流量

缺点:

  • Redis如果使用RDB进行持久化,那么数据会存在丢失的风险。即 incr 后的数据丢失,则再次生成的主键会重复
  • 依赖第三方服务,系统的复杂性会增加

2.4SnowFlake雪花算法(64位)

(雪花算法的基本思想是采用一个8字节的二进制序列来生成一个主键。为什么用8个字节呢?因为8个字节正好是一个Long类型的变量。既保持足够的区分度,又能比较自然的与业务结合。)

  • 第一个bit位(1bit):一般生成ID都为正数,所以默认为0。
  • 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
  • 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。
  • 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID

核心思想:

多种唯一的值 进行拼接,使其更唯一
Snowflake的第二部分是时间戳,时间戳是唯一的,但是如果多个节点同时生产则会参数相同的时间戳,那怎么办?接着加唯一的值,工作机器的ID唯一呀。那么就出现了第三部分的值。但是如果在一个进程中可能两个线程同时请求,那么会产生相同的(时间戳+工作机器ID),那就继续加唯一值,在加上最后的序列号,从而保证全局唯一。

  • 第一个bit位(1bit):一般生成ID都为正数,所以默认为0。
  • 时间戳部分(41bit):保证单节点下请求唯一,但是多节点内请求会生成相同的时间戳
  • 工作机器id(10bit):时间戳 + 工作机器 保证多节点同同时请求可以生成不同的主键ID。但是多节点下多线程还是存在重复
  • 序列号部分(12bit),解决多节点下多线程生成ID重复的问题

优点:

  • 高性能,生成的主键贼多

缺点

  • 生成的主键之间跨度大,不密集,比如我想看一天的订单量,那么根据主键ID相减就没办法
  • 该算法强依赖时间,存在时钟回拨问题

时钟回拨问题常见的解决方案

其实很多大厂基于雪花算法开源的分布式ID解决方案一方面偏重于64的设计,另一方面偏重于时钟回拨出现后的解决方案优化。

  • 回拨时间很短(<100ms)
    当请求系统时如果发现这个时钟回拨的时间段很小,则可以使其睡一会到达之前最新的时间节点而继续往下执行。
  • 回拨时间适中(>100ms && < 1s)
    维护最近的一秒(1000毫秒)每毫秒请求的最大值到Redis中(time,maxId),如果发生时钟回拨则取该毫秒的最大值+1。
  • 回拨时间较长(>1s && < 5s)
    当请求Snowflake1时发现时钟回拨,则可以抛一个异常给客户端,客户端则进行其他节点的访问,负载均衡去实现

  • 回拨时间很长(>5s )
    直接报警下线吧,都不能用了

参考:

分布式主键生成设计策略_分布式主键生成策略-CSDN博客

这篇关于分布式主键的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129324

相关文章

集中式版本控制与分布式版本控制——Git 学习笔记01

什么是版本控制 如果你用 Microsoft Word 写过东西,那你八成会有这样的经历: 想删除一段文字,又怕将来这段文字有用,怎么办呢?有一个办法,先把当前文件“另存为”一个文件,然后继续改,改到某个程度,再“另存为”一个文件。就这样改着、存着……最后你的 Word 文档变成了这样: 过了几天,你想找回被删除的文字,但是已经记不清保存在哪个文件了,只能挨个去找。真麻烦,眼睛都花了。看

开源分布式数据库中间件

转自:https://www.csdn.net/article/2015-07-16/2825228 MyCat:开源分布式数据库中间件 为什么需要MyCat? 虽然云计算时代,传统数据库存在着先天性的弊端,但是NoSQL数据库又无法将其替代。如果传统数据易于扩展,可切分,就可以避免单机(单库)的性能缺陷。 MyCat的目标就是:低成本地将现有的单机数据库和应用平滑迁移到“云”端

laravel框架实现redis分布式集群原理

在app/config/database.php中配置如下: 'redis' => array('cluster' => true,'default' => array('host' => '172.21.107.247','port' => 6379,),'redis1' => array('host' => '172.21.107.248','port' => 6379,),) 其中cl

基于MySQL实现的分布式锁

概述 在单机时代,虽然不需要分布式锁,但也面临过类似的问题,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制,即当某个线程获取到这个资源后,就立即对这个资源进行加锁,当使用完资源之后,再解锁,其它线程就可以接着使用了。例如,在JAVA中,甚至专门提供了一些处理锁机制的一些API(synchronize/Lock等)。 但是到了分布式系统的时代,这种

Oracle主键和外键详解及实用技巧

在 Oracle 数据库中,主键(Primary Key)和外键(Foreign Key)用于维护数据库表之间的数据完整性。 1. 主键(Primary Key) 主键是一列或多列,能够唯一标识表中的每一行。表中只能有一个主键,并且主键列不能为空(即 NOT NULL)。 特性: 唯一性:主键中的每一个值都是唯一的,不能重复。非空性:主键列不能包含 NULL 值。索引:Oracle 自动为

Kafka 分布式消息系统详细介绍

Kafka 分布式消息系统 一、Kafka 概述1.1 Kafka 定义1.2 Kafka 设计目标1.3 Kafka 特点 二、Kafka 架构设计2.1 基本架构2.2 Topic 和 Partition2.3 消费者和消费者组2.4 Replica 副本 三、Kafka 分布式集群搭建3.1 下载解压3.1.1 上传解压 3.2 修改 Kafka 配置文件3.2.1 修改zookeep

Spring Cloud整合Seata实现分布式事务

文章目录 1.Seata1.1 官网1.2 下载1.3 通过安装包运行seata1.3.1 解压seata-server-1.3.0.zip1.3.2 修改 conf/file.conf 配置文件1.3.3 修改conf/registry.conf配置文件1.3.4 添加seata配置信息到nacos1.3.5 配置seata服务端数据库表结构1.3.6 启动seata 2.Spring

ELK+Spring Cloud搭建分布式日志中心

ELK+Spring Cloud搭建分布式日志中心 1.ELK简介2.资源包下载3.Elasticsearch安装3.1 解压Elasticsearch3.2 修改Elasticsearch的配置文件3.3 修改系统配置3.4 启动Elasticsearch 4.ElasticSearch-head插件安装5.Logstash安装6.Kibana安装7.SpringCloud集成logsta

Redis进阶(七):分布式锁

在分布式系统下,涉及到多个节点访问同一个公共资源的情况,此时需要通过 锁 进行互斥控制:避免出现 线程安全问题。 1.分布式锁的基本实现 超卖问题: 解决: 采用redis实现分布式锁 可用采取:在购票的时候,操作过程中需要先加锁。在redis上设置一个key - value,完成上述买票操作,再把key - value 删掉。如果发现key - value 存在,就加锁失败,无法进

聊聊分布式,再讨论分布式解决方案

前言 最近很久没有写博客了,一方面是因为公司事情最近比较忙,另外一方面是因为在进行 CAP 的下一阶段的开发工作,不过目前已经告一段落了。 接下来还是开始我们今天的话题,说说分布式事务,或者说是我眼中的分布式事务,因为每个人可能对其的理解都不一样。 分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎可以说是无法避免,本文就分布式事