电商项目part05 分布式ID服务实战

背景

日常开发中,需要对系统中的各种数据使用 ID 唯一表示,比如用户 ID
对应且仅对应一个人,商品 ID 对应且仅对应一件商品,订单 ID 对应且仅对应
一个订单。现实生活中也有各种 ID,比如身份证 ID 对应且仅对应一个人,
简单来说,ID 就是数据的唯一标识。
一般情况下,会使用数据库的自增主键作为数据 ID,但是在大数量的情况下,往往会引入分布式、分库分表等手段来应对,很明显对数据分库分表后依然需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 已经无法满足需求。此时一个能够生成全局唯一 ID 的系统是非常必要的。
概括下来业务系统对 ID 号的要求有
全局唯一性:不能出现重复的 ID 号,既然是唯一标识,这是最基本的要求。
趋势递增、单调递增:保证下一个 ID 一定大于上一个 ID。
信息安全:如果 ID 是连续的,恶意用户的扒取工作就非常容易做了,直接
按照顺序下载指定 URL 即可;如果是订单号就更危险了,竞对可以直接知道一天的单量。所以在一些应用场景下,会需要 ID 无规则、不规则。
同时除了对 ID 号码自身的要求,业务还对 ID 号生成系统的可用性要求极高,
想象一下,如果 ID 生成系统不稳定,大量依赖 ID 生成系统,比如订单生成等关
键动作都无法执行。所以一个 ID 生成系统还需要做到平均延迟和 TP999 延迟都
要尽可能低;可用性 5 个 9;高 QPS。

常见方法介绍

UUID

UUID(Universally Unique Identifier)的标准型式包含 32 个 16 进制数字,以连
字号分为五段,形式为 8-4-4-4-12 的 36 个字符,示例:
550e8400-e29b-41d4-a716-446655440000,到目前为止业界一共有 5 种方式生成
UUID,详情见 IETF 发布的 UUID 规范 A Universally Unique IDentifier (UUID) URN
Namespace。
优点:
性能非常高:本地生成,没有网络消耗。
缺点:
不易于存储:UUID 太长,16 字节 128 位,通常以 36 长度的字符串表示,
很多场景不适用。
信息不安全:基于 MAC 地址生成 UUID 的算法可能会造成 MAC 地址泄露
这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。

ID作为主键时在特定的环境会存在一些问题,比如做DB主键的场景下,UUID
就非常不适用:
① MySQL官方有明确的建议主键要尽量越短越好[4],36个字符长度的UUID
不符合要求。
② 对 MySQL 索引不利:如果作为数据库主键,在 InnoDB 引擎下,UUID 的
无序性可能会引起数据位置频繁变动,严重影响性能。在 MySQL InnoDB 引擎中使用的是聚集索引,由于多数 RDBMS 使用 B-tree 的数据结构来存储索引数据,在主键的选择上面应该尽量使用有序的主键保证写入性能。可以直接使用 jdk 自带的 UUID,原始生成的是带中划线的,如果不需要,可自行去除

在这里插入图片描述

雪花算法

Snowflake 是 Twitter 开源的分布式 ID 生
成算法。Snowflake 把 64-bit 分别划分成多段,分开来标示机器、时间等,比如
在 snowflake 中的 64-bit 分别表示如下图所示:(时间戳+机房号+序列号)
在这里插入图片描述
第 0 位: 符号位(标识正负),始终为 0,没有用,不用管。
第 1~41 位 :一共 41 位,用来表示时间戳,单位是毫秒,可以支撑 2 ^41
毫秒(约 69 年)
第 42~52 位 :一共 10 位,一般来说,前 5 位表示机房 ID,后 5 位表
示机器 ID(实际项目中可以根据实际情况调整),这样就可以区分不同集群/机
房的节点,这样就可以表示 32 个 IDC,每个 IDC 下可以有 32 台机器。
第 53~64 位 :一共 12 位,用来表示序列号。 序列号为自增值,代表单
台机器每毫秒能够产生的最大 ID 数(2^12 = 4096),也就是说单台机器每毫秒最
多可以生成 4096 个 唯一 ID。
理论上 snowflake 方案的 QPS 约为 409.6w/s,这种分配方式可以保证在任何
一个 IDC 的任何一台机器在任意毫秒内生成的 ID 都是不同的。

有很多基于 Snowflake 算法的开源实现比如美团的 Leaf、百度的
UidGenerator(自 18 年后,UidGenerator 就基本没有再维护了,
https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md),并且这
些开源实现对原有的 Snowflake 算法进行了优化。在实际项目中,一般也
会对 Snowflake 算法进行改造,最常见的就是在算法生成的 ID 中加入业务类型
信息。
关于自行实现 Snowflake 算法,可以参考 tulingmall-unqid 下的
com.tuling.tulingmall.service.snowflake 下的代码。
Snowflake 优缺点是:
优点:
毫秒数在高位,自增序列在低位,整个 ID 都是趋势递增的。
不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的
性能也是非常高的。
可以根据自身业务特性分配 bit 位,非常灵活。
缺点:
强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不
可用状态。
当然,在项目中如果不想自行实现唯一性 ID,还可以利用外部中
间件,比如 Mongdb objectID,它也可以算作是和 snowflake 类似方法,通过“时
间+机器码+pid+inc”共 12 个字节,通过 4+3+2+3 的方式最终标识成一个 24 长度的十六进制字符。
其次 Seata 内置了一个分布式 UUID 生成器,用于辅助生成全局事务 ID 和分
支事务 ID,同样可以拿来使用,完整类名为: io.seata.common.util.IdWorker

数据库生成

MYSQL

以 MySQL 举例,
1.创建一个数据库表。

CREATE TABLE `sequence_id` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`stub` char(10) NOT NULL DEFAULT '',PRIMARY KEY (`id`),UNIQUE KEY `stub` (`stub`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 

stub字段无意义,只是为了占
位,便于我们插入或者修改数据。并且,给 stub 字段创建了唯一索引,保证其
唯一性。
2.通过 replace into 来插入数据。
BEGIN;
REPLACE INTO sequence_id (stub) VALUES (‘stub’);
SELECT LAST_INSERT_ID();
COMMIT;
插入数据这里,我们没有使用 insert into 而是使用 replace into 来插入数据。
replace 是 insert 的增强版,replace into 首先尝试插入数据到表中,1. 如果发现
表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插
入新的数据。 2. 否则,直接插入新数据。
数据库方案的优缺点如下:
优点:
非常简单,利用现有数据库系统的功能实现,成本小,有 DBA 专业维护。ID
号单调自增,存储消耗空间小。
缺点:
支持的并发量不大、存在数据库单点问题(可以使用数据库集群解决,不过
增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增
规律就能推算出每天的订单量,商业机密啊! )、每次获取 ID 都要访问一次
数据库(增加了对数据库的压力,获取速度也慢)

Redis

通过 Redis 的 incr 命令即可实现对 id 原子顺序递增,例如:

127.0.0.1:6379> incr sequence_id_biz_type
(integer) 2

为了提高可用性和并发,我们可以使用 Redis Cluster。
除了高可用和并发之外,我们知道 Redis 基于内存,我们需要持久化数据,
避免重启机器或者机器故障后数据丢失。很明显,Redis 方案性能很好并且生成
的 ID 是有序递增的。
不过,我们也知道,即使 Redis 开启了持久化,不管是快照(snapshotting,
RDB)、只追加文件(append-only file, AOF)还是 RDB 和 AOF 的混合持久化依然存在着丢失数据的可能,那就意味着产生的 ID 存在着重复的概率。

弱依赖 ZooKeeper

除了每次会去 ZK 拿数据以外,也会在本机文件系统上缓存一个 workerID 文件。当 ZooKeeper 出现问题,恰好机器出现问题需要重启时,能保证服务能够正常启动。这样做到了对三方组件的弱依赖。

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

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

相关文章

C#,《小白学程序》第七课:列表(List)应用之一“编制高铁车次信息表”

1 文本格式 /// <summary> /// 车站信息类 class /// </summary> public class Station { /// <summary> /// 编号 /// </summary> public int Id { get; set; } 0; /// <summary> /// 车站名 /// </summary>…

【无法联网】电脑wifi列表为空的解决方案

打开电脑, 发现wifi列表为空, 点击设置显示未连接 首先检查是不是网卡驱动有问题, cmd, devmgmt.msc 找到网络适配器, 看看网卡前面是否有感叹号, 如果没有则说明网卡没问题, 有问题则重装驱动 看看网络协议是否设置正确 找到"控制面板\所有控制面板项\网络和共享中心&…

AP5192 DC-DC降压恒流LED汽车灯 LED长条灯 汽车雾灯驱动IC

AP5192是一款PWM工作模式,高效率、外围简单、 内置功率MOS管&#xff0c;适用于4.5-100V输入的高精度 降压LED恒流驱动芯片。最大电流1.5A。 AP5192可实现线性调光和PWM调光&#xff0c;线性调光 脚有效电压范围0.55-2.6V. AP5192 工作频率可以通过RT 外部电阻编程 来设定&…

力扣:73. 矩阵置零(Python3)

题目&#xff1a; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚…

【LeetCode-中等题】105. 从前序与中序遍历序列构造二叉树

文章目录 题目方法一&#xff1a;递归 题目 方法一&#xff1a;递归 preorder [3,9,20,15,7] inorder [9,3,15,20,7] 首先根据 preorder 找到根节点是 3然后根据根节点将 inorder 分成左子树和右子树 左子树 inorder [9]右子树 inorder [15,20,7]这时候3是根节点 3的左子树…

基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI 高校汉服租赁网站的 设计与实现

一.项目介绍 高校汉服租赁网站分为普通用户以及管理员两类 普通用户&#xff1a; 注册、登录系统、查看汉服首页发帖公告信息、 交流论坛&#xff08;发帖、查看帖子、评论&#xff09;、 公告咨询&#xff08;查看公告以及评论&#xff09;、 汉服信息&#xff08;查…

k8s 查看加入主节点命令 k8s重新查看加入节点命令 k8s输入删除,重新查看加入命令 kuberadm查看加入节点命令

1. 使用kuberadm 安装成功后&#xff0c;clear清除了屏幕数据&#xff0c;加入命令无法查看&#xff0c;使用如下&#xff0c;重新查看node如何加入主节点命令&#xff1a; kubeadm token create --print-join-command --ttl 0 2.画圈的全部是&#xff0c;都复制&#xff0c;在…

【中危】Spring Kafka 反序列化漏洞 (CVE-2023-34040)

zhi.oscs1024.com​​​​​ 漏洞类型反序列化发现时间2023-08-24漏洞等级中危MPS编号MPS-fed8-ocuvCVE编号CVE-2023-34040漏洞影响广度小 漏洞危害 OSCS 描述Spring Kafka 是 Spring Framework 生态系统中的一个模块&#xff0c;用于简化在 Spring 应用程序中集成 Apache Kaf…

数据结构1 -- leetcode练习

三. 练习 3.1 时间复杂度 用函数 f ( n ) f(n) f(n) 表示算法效率与数据规模的关系&#xff0c;假设每次解决问题需要 1 微秒&#xff08; 1 0 − 6 10^{-6} 10−6 秒&#xff09;&#xff0c;进行估算&#xff1a; 如果 f ( n ) n 2 f(n) n^2 f(n)n2 那么 1 秒能解决多…

【面试题】MVC、MVP与MVVM模式是什么?

MVC模式 MVC是应用最广泛的软件架构之一&#xff0c;一般MVC分为&#xff1a; Model&#xff08; 模型 &#xff09;、Controller&#xff08; 控制器 &#xff09;、View&#xff08; 视图 &#xff09;。 这主要是基于分层的目的&#xff0c;让彼此的职责分开。View 一般…

单片机电子元器件-数码管

数码管分类 共阳 把所有数码管的阳极接到一起形成公共阳极COM 数码管 共阳极COM 接到 5V 电源 共阴 把所有数码管的阴极接到一起形成公共阴极COM 数码管 共阴极COM 接到 地 GND 上 八段 数码管 和 七段数码管&#xff0c; 多了一个 小数点 DP 数码管显示原理 一个数码管如…

线性代数的学习和整理13: 定义域,值域,到达域 和单射,满射,双射,反函数,逆矩阵

目录 1 函数与 向量/矩阵 2 初等数学的函数 2.1 函数 2.2 函数的定义&#xff1a;定义域 →映射→ 值域 3 高等数学里的函数&#xff1a;定义域和陪域/到达域&#xff08;非值域&#xff09;的映射关系 3.1 函数 3.2 单射&#xff0c;满射&#xff0c;双射等都是针对…

Kubernetes入门 十、HPA 自动扩/缩容

目录 概述安装metrics-server使用HPA 概述 我们已经可以通过手动执行 kubectl scale 命令实现Pod的扩缩容&#xff0c;但是这显然不符合 Kubernetes 的定位目标–自动化和智能化。Kubernetes 期望可以通过监测Pod的使用情况&#xff0c;实现 Pod 数量的自动调整&#xff0c;于…

0基础学习VR全景平台篇 第92篇:智慧景区-智慧景区常见问题

Q&#xff1a;怎么编辑景区里面各个景点的介绍和推荐该景点A&#xff1a;在下方素材栏中该景点&#xff08;素材&#xff09;的右上角选择【编辑场景】里面就可以在场景介绍中编辑该场景的介绍并且在该选项中可以将此场景设置为推荐景点。 Q&#xff1a;景区项目可不可以离线浏…

【VMware】CentOS 设置静态IP(Windows 宿主机)

文章目录 1. 更改网络适配器设置2. 配置虚拟网络编辑器3. 修改 CentOS 网络配置文件4. ping 测试结果 宿主机&#xff1a;Win11 22H2 虚拟机&#xff1a;CentOS-Stream-9-20230612.0 (Minimal) 1. 更改网络适配器设置 Win R&#xff1a;control 打开控制面板 依次点击&#x…

0829【综述】面向时空数据的区块链研究综述

摘要:时空数据包括时间和空间2个维度,常被应用于物流、供应链等领域。传统的集中式存储方式虽然具有一定的便捷性,但不能充分满足时空数据存储及查询等要求,而区块链技术采用去中心化的分布式存储机制,并通过共识协议来保证数据的安全性。研究现有区块链1.0、2.0和以Block-DAG为…

Mysql高阶语句 (一)

一、常用查询 &#xff08;增、删、改、查&#xff09; 对 MySQL 数据库的查询&#xff0c;除了基本的查询外&#xff0c;有时候需要对查询的结果集进行处理。 例如只取 10 条数据、对查询结果进行排序或分组等等 1、按关键字排序 PS:类比于windows 任务管理器 使用 SELECT 语句…

debug调试时,通过[[FunctionLocation]]找到函数在源代码中的位置

[[FunctionLocation]] 是 JavaScript 引擎内部的一个属性&#xff0c;用于记录函数在代码中的位置。它不是 JavaScript 语法的一部分&#xff0c;而是在调试和开发过程中用于追踪函数定义位置的一个辅助属性。 当我们在浏览器的开发者工具或其他调试工具中查看函数的属性时&am…

docker部署前端项目保姆级教程

本地启动docker&#xff08;有不会启动的吗&#xff1f;下载docker&#xff08;小海豚&#xff09;双击起来就行&#xff09; 准备阿里云账号&#xff08;免费&#xff09; 没有就去注册一个&#xff0c;记住密码后面要用到 官网地址&#xff1a;阿里云登录 - 欢迎登录阿里云…

各个微服务模块之间互相依赖调用的问题

首先是模块之间不能够循环引用&#xff0c;否则会报循环依赖引入的错误。 没有了模块之间的相互依赖&#xff0c;在项目中这两个模块是相互调用的&#xff0c;分别各自定义相应的Feign接口&#xff0c;如下&#xff1a; 最开始写的运行报错的代码如下&#xff1a; FeignCli…