76.Go分布式ID总览

news2024/12/29 8:21:27

文章目录

  • 简介
  • 一:UUID
  • 二、雪花算法
  • 三:Leaf-snowflake
  • 四:数据库自增ID
  • 五:使用Redis实现分布式ID生成
  • 六:使用数据库分段(Leaf-segment)
  • 七 :增强版Leaf-segment
  • 八:Tinyid
  • 九: 分布式键生成服务(如Zookeeper、etcd)

简介

在分布式系统中,生成唯一的ID是一个核心问题,特别是在需要确保数据完整性和避免冲突的场景中,比如作为链路追踪的trace_id,作为幂等性的主键id, 分布式锁中为了避免释放的是别人的锁时,本地保存的唯一id等。以下是对一些分布式唯一ID生成方法的详细阐述,包括它们的工作原理、优缺点,以及对网络依赖性的考量

一:UUID

实现原理

  • 工作方式:UUID是通过一系列算法生成的128位数字,通常基于时间戳、计算机硬件标识符、随机数等元素。

  • 全局唯一性:算法设计确保了即使在分布式系统中也能生成全局唯一的ID

优缺点

  • 优点:实现简单,无需网络交互,保证了ID的全球唯一性。

  • 缺点:通常不能保证顺序性,ID较长,可能导致存储和索引效率低下。

  • 网络依赖性:无网络依赖。

注意:工作中基本不使用uuid,这里是为了介绍分布式ID的完整性,以及UUID大家都熟知,所以一起介绍一下

uuid有两种包:

  • github.com/google/uuid,仅支持V1V4版本。

  • github.com/gofrs/uuid ,支持全部五个版本。

下面简单说下五种版本的区别:

Version 1,基于mac地址、时间戳。

Version 2,based on timestamp,MAC address and POSIX UID/GID (DCE 1.1)

Version 3,Hash获取入参并对结果进行MD5。

Version 4,纯随机数。

Version 5,based on SHA-1 hashing of a named value。

特点

  • 5个版本可供选择。

  • 定长36字节,偏长。

  • 无序。

package mian

import (
    "github.com/gofrs/uuid"
    "fmt"
)

func main() {
    // Version 1:时间+Mac地址
    id, err := uuid.NewV1()
    if err != nil {
        fmt.Printf("uuid NewUUID err:%+v", err)
    }
    // id: f0629b9a-0cee-11ed-8d44-784f435f60a4 length: 36
    fmt.Println("id:", id.String(), "length:", len(id.String()))

    // Version 4:是纯随机数,error会在内部报panic
    id, err = uuid.NewV4()
    if err != nil {
        fmt.Printf("uuid NewUUID err:%+v", err)
    }
    // id: 3b4d1268-9150-447c-a0b7-bbf8c271f6a7 length: 36
    fmt.Println("id:", id.String(), "length:", len(id.String()))
}

二、雪花算法

Twitter开发的一种生成64ID的服务,基于时间戳、节点ID和序列号。

实现原理

  • 工作方式:结合时间戳、工作机器的ID和序列号来生成64位的ID。时间戳保证了ID的唯一性和顺序性,工作机器ID保证了在多机环境下的唯一性。

  • 时间戳:确保ID按时间顺序增长。

优缺点

  • 优点:ID有时间顺序,长度适中,生成速度快。

  • 缺点:对系统时钟有依赖,时钟回拨会导致ID冲突。(时钟回拨:服务器上的时间突然倒退回之前的时间。可能是人为的调整时间;也可能是服务器之间的时间校对。)

  • 网络依赖性:通常无需网络交互,除非在多机器环境中同步机器ID

由于雪花算法工作中还是可能用到的,所以介绍更详细一些。

Snowflake的核心思想是:使用41bit作为毫秒数,10bit作为机器的ID5bit是数据中心(DC,机房)),5bit的机器ID(也可能是容器id)),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是01。这样可以确保每个ID都是唯一的。
图片

package main

import(
    "fmt"
    "github.com/bwmarrin/snowflake"
)

func main() {
// 参数为机器id
  node, err := snowflake.NewNode(1)
    if err != nil {
      fmt.Println(err)
      return
    }

    id := node.Generate().String()    
    // id: 1552614118060462080 length: 19
    fmt.Println("id:", id, "length:", len(id))
}

三:Leaf-snowflake

时钟回拨

服务器上的时间突然倒退回之前的时间。可能是人为的调整时间;也可能是服务器之间的时间校对。

实现方案
在这里插入图片描述

Zookeeper顺序增、全局唯一的节点版本号,替换了原有的机器地址。解决了时钟回拨的问题。强依赖ZooKeeper、大流量下可能存在网络瓶颈。下图的方案在Leaf-snowflake 中通过缓存一个ZooKeeper文件夹,提高可用性。运行时,时差小于5ms会等待时差两倍时间,如果时差大于5ms报警并停止启动。

在这里插入图片描述

四:数据库自增ID

实现原理

  • 工作方式:基于中央数据库的序列生成器,如自增主键ID,每次请求时递增序列值。

  • 顺序性:保证了生成ID的顺序性和唯一性。

优缺点

  • 优点:简单可靠,保证顺序性。

  • 缺点:

    • 可能成为系统的单点故障,对数据库有较高的依赖。
    • 由于有序递增,易暴露业务量。受到数据库性能限制,对高并发场景不友好。
    • bigint最大是2^64-1,但是数据库单表肯定放不了这么多,那么就涉及到分表。
    • 如果业务量真的太大了,主键的自增id涨到头了,会发生什么?报错:主键冲突。
    • 网络依赖性:高度依赖网络,所有ID生成请求都需要访问中央数据库。

正是由于这众多缺点,所以工作中是不用它的,不过可以作为一种思路。

五:使用Redis实现分布式ID生成

Redis是一个高性能的键值数据库,它可以用于生成分布式唯一标识符。

实现原理

  • 利用Redis的原子操作:Redis提供了原子性的INCRINCRBY命令,可用于生成唯一的递增数值。这些数值可以作为唯一ID

  • 分布式环境中的应用:在分布式环境中,可以部署多个Redis实例。每个实例可以独立生成ID,或者通过配置不同的起始值和步长来确保ID的全局唯一性。

  • 高性能和可靠性:Redis的高性能确保了即使在高负载下也能快速生成ID,同时Redis的持久化和复制特性提高了系统的可靠性。

优缺点分析

  • 优点:快速、简单且易于扩展;支持高并发环境。

  • 缺点:依赖于外部服务(Redis),需要管理和维护额外的基础设施。

  • 网络依赖性:高度依赖网络。

六:使用数据库分段(Leaf-segment)

这种方法涉及到使用数据库来生成和管理ID段,以实现分布式ID的生成。

实现原理

  • ID段的分配:在数据库中预设一个起始ID和步长,每个应用实例或服务节点从数据库中获取一个ID段,然后在本地生成ID,直到该段用完再从数据库获取新的段。

  • 减少数据库交互:每个节点在消耗完一个ID段之前不需要与数据库交互,这减少了数据库的负载,并提高了ID生成的效率。

  • 避免冲突:通过确保每个节点获取的ID段不重叠,可以保证生成的ID在全系统范围内是唯一的。

优缺点分析

  • 优点:减少了对数据库的频繁访问,提高了性能;适合在分布式系统中使用。

  • 缺点:管理复杂性:管理不同的ID段需要额外的逻辑和数据库设计。可能的ID浪费:如果某个服务或实例在用完其ID段之前下线或重启,可能导致分配的ID未被完全使用。

  • 网络依赖性:对网络的依赖相对较低,只在申请新的ID段时需要访问数据库。

实际例子
把数据库自增主键换成了计数法。每个业务分配一个biz_tag、并记录各业务最大id(max_id)、号段跨度(step)等数据。这样每次取号只需要更新biz_tag对应的max_id,就可以拿到stepid。比如业务business_a当前max_id3000,取了1000个号在本地使用,使用完后,可以更新DB中对应的max_id4000,这样business_a本地就有1000个新的id可以用了

在这里插入图片描述

优点

  1. 除了拥有自增ID的优点之外,在性能上比自增ID更好,扩展灵活。
  2. 使用灵活、可配置性强。
  3. 缓存机制,突发状况下短时间内能保证服务正常运转。

缺点

  1. id是有序自增,容易暴露信息,不可用于订单。
  2. leaf的缓存ID用完再去获取新号段的间隙,性能会有波动。
  3. 强依赖DB

七 :增强版Leaf-segment

增强版是对上面描述的缺点2进行的改进——双cache。在leafID消耗到一定百分比时,常驻的后台进程会预先去号段服务获取新的号段并缓存。具体消耗百分比、及号段step根据业务消耗速度来定。

在这里插入图片描述

八:Tinyid

和增强版Leaf-segment类似,也是号段模式,提前加载号段。

在这里插入图片描述

九: 分布式键生成服务(如Zookeeper、etcd)

分布式协调服务在集群中生成唯一ID

ZooKeeper是使用了Znode结构中的Zxid实现顺序增IDZookeeper类似一个文件系统,每个节点都有唯一路径名(Znode),Zxid是个全局事务计数器,每个节点发生变化都会记录响应的版本(Zxid),这个版本号是全局唯一且顺序递增的。这种架构还是出现了ZooKeeper的单点问题。

实现原理

  • 工作方式:这些服务提供了分布式锁和原子性操作来生成唯一的ID

  • 协调机制:通过集群协调机制保证ID的唯一性和顺序性。

优缺点

  • 优点:提供了更加灵活和可控的ID生成方式,适合分布式环境。

  • 缺点:引入外部依赖,增加了系统的复杂性。

  • 网络依赖性:高度依赖网络,因为它们需要在多个节点之间协调ID的生成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅学JAVAFX布局

JAVAFX FlowPane布局 Flowpane是一个容器。它在一行上排列连续的子组件,并且如果当前行填充满了以后,则自动将子组件向下推到一行 public class FlowPanedemo extends Application {Overridepublic void start(Stage stage) throws Exception {stage.s…

C++入门篇章1(C++是如何解决C语言不能解决的问题的)

目录 1.C关键字(以C98为例)2.命名空间2.1 命名空间定义2.2命名空间使用 3.C输入&输出4.缺省参数4.1缺省参数概念4.2 缺省参数分类 5. 函数重载5.1函数重载概念5.2 C支持函数重载的原理--名字修饰(name Mangling) 1.C关键字(以C98为例) C总计63个关键字,C语言32…

go api(get post传参,数据库,redis) 测试

介绍:分别测试get请求,post请求,请求链接数据库,以及redis操作。 1.api代码 package mainimport (_ "database/sql""encoding/json""github.com/gin-gonic/gin""go-test/com.zs/database&quo…

【RT-DETR有效改进】交叉形窗口网络 | CSWinTransformer(附代码 + 修改教程)

前言 大家好,我是Snu77,这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进,内容持续更新,每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本,同时修改内容也支持Re…

【GitHub项目推荐--一款美观的开源社区系统】【转载】

推荐一款开源社区系统,该系统基于主流的 Java Web 技术栈,如果你是一名 Java 新手掌握了基本 JavaEE 框架知识,可以拿本项目作为练手项目。 开源社区系统功能还算完善包含发布帖子、发布评论、私信、系统通知、点赞、关注、搜索、用户设置、…

ToDesk/向日葵的MAC远程鼠标控制不了?如何解决

不知道各位使用Mac电脑的小伙伴们,在日常进行跨设备远控操作时是否曾遇到过远程鼠标控制不了的问题?其实这是因为有项系统权限没有开设导致的,本篇文章木木小编就给大家逐步教学一下针对该问题如何解决才有效! 当通过ToDesk远程连…

vue中图片不显示问题 - vue中静态资源加载

文章目录 vue中图片不显示问题静态资源URL 转换规则webpack 静态资源处理 图片不显示问题问题描述解决办法1:使用require引入require is not defined 解决办法2:使用import引入解决办法3:将图片放进公共文件夹static或public vue中图片不显示…

当世界加速离你而去

当世界加速离你而去 会不会这个标题显的太悲观,也可能是耳机里正在放着To Be Frank的原因。 对于阳历跨年我是没有太多的感觉,而且跨年夜忙着约会,所以2023年的跨年文章今天才出来。 一年的时间一晃就过了。2022年12月9日时候彻底结束了风控…

基于EfficientNet(B0-B7)全系列不同参数量级模型开发构建中草药图像识别分析系统,实验量化对比不同模型性能

EfficientNet系列的模型在我们前面开发识别类项目或者是检测类项目都是比较少去使用的,一方面是技术本身迭代发展的速度是比较快的,可能新的东西还没学习更新的东西就出来了,另一方面是EfficientNet本身实际业务使用度并不高,可能…

maptalks 右键删除多边形 电子围栏

<!-- 地图组件 --> <template><div :id"id" class"container"></div> </template><script> import _ from "lodash"; import "maptalks/dist/maptalks.css"; import * as maptalks from "ma…

RDMA vs InfiniBand 网卡接口如何区分?

(该架构图来源于参考文献) 高性能计算网络&#xff0c;RoCE vs. InfiniBand该怎么选&#xff1f; 新 RoCEv2 标准可实现 RDMA 路由在第三层以太网网络中的传输。RoCEv2 规范将用以太网链路层上的 IP 报头和 UDP 报头替代 InfiniBand 网络层。这样&#xff0c;就可以在基于 IP…

虹科分享丨AR与AI融合加速,医疗护理更便捷!

来源&#xff1a;虹科数字化与AR 虹科分享丨AR与AI融合加速&#xff0c;医疗护理更便捷&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/Fi0wNfk_TDXRo_1-6cSRNQ 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #AR眼镜 #医疗护理 根据Reports and Da…

【动态规划】【map】【C++算法】1289. 下降路径最小和 II

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 map LeetCode1289. 下降路径最小和 II 给你一个 n x n 整数矩阵 grid &#xff0c;请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为&#xff1a;从 grid 数组中的每一行选择一个数字&#xff0c;…

云计算项目五:部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务

部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务 案例1:配置逻辑卷步骤一:创建LV步骤二:格式化案例2:配置数据库服务器步骤一:安装软件MySQL服务软件(2台数据库服务器都要安装)步骤二:挂载lv设备步骤三:启动服务步骤四:管理员登录案例3:配置主从同步步骤一…

【自然语言处理】【深度学习】文本向量化、one-hot、word embedding编码

因为文本不能够直接被模型计算&#xff0c;所以需要将其转化为向量 把文本转化为向量有两种方式&#xff1a; 转化为one-hot编码转化为word embedding 一、one-hot 编码 在one-hot编码中&#xff0c;每一个token使用一个长度为N的向量表示&#xff0c;N表示词典的数量。 即&…

谷歌地球引擎Google Earth Engine针对不同地表类型分别自动生成随机采样点的方法

本文介绍在谷歌地球引擎&#xff08;Google Earth Engine&#xff0c;GEE&#xff09;中&#xff0c;按照给定的地表分类数据&#xff0c;对每一种不同的地物类型&#xff0c;分别加以全球范围内随机抽样点自动批量选取的方法。 本文是谷歌地球引擎&#xff08;Google Earth En…

05.Elasticsearch应用(五)

Elasticsearch应用&#xff08;五&#xff09; 1.目标 咱们这一章主要学习Mapping&#xff08;映射&#xff09; 2.介绍 Mapping是对索引库中文档的约束&#xff0c;类似于数据表结构&#xff0c;作用如下&#xff1a; 定义索引中的字段的名称定义字段的数据类型&#xff…

0124-2-算法题解析与总结(四)

5.5 如何去除有序数组的重复元素 本文对应的力扣题目&#xff1a; 26.删除排序数组中的重复项 83.删除排序链表中的重复元素 26.删除排序数组中的重复项&#xff1a; int removeDuplicates(int[] nums) {int n nums.length;if (n 0) return 0;int slow 0, fast 1;while…

Spring基于AbstractRoutingDataSource实现MySQL多数据源

目录 多数据源实现 yml配置文件 配置类 业务代码 案例演示 多数据源实现 yml配置文件 spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedatasource1:url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezoneUTC&useUnicodetrue&characte…

第二百八十六回

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了如何拦截路由相关的内容&#xff0c;本章回中将介绍页面转场动画.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在上一章回中介绍了路由拦截相关的内容&#xff0c;本章回中将使用路由拦截实现转场…