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

news2025/1/15 12:55:01

背景

日常开发中,需要对系统中的各种数据使用 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.coloradmin.cn/o/922450.html

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

相关文章

XL74HC165 Parallel-2-Serail Controller

XL74HC165 Parallel-2-Serail Controller (SOP16) ( SN74LS165, CD74LS165 - DIP16 / SOP16 ) ( 不频繁存取, 可以考虑 I2C I/O Expender ) PCF8574/ T module (8bits Address *0x40~0x4E* ) PCF8574A module (8bit address *0x70~0x7E* )XL74HC165 fmax : VCC 3.3V &l…

冠达管理股票分析:首家!券商放大招,立马拉升

A股的“回购潮”,开始蔓延至券商行业。 广东研山私募证券投资(百度搜索冠达管理)基金管理有限公司成立于2022年,是一家专注于私募基金管理的公司。8月23日盘后,国金证券发布公告称,收到控股股东长沙涌金(集…

Fegin异步情况丢失上下文问题

在微服务的开发中,我们经常需要服务之间的调用,并且为了提高效率使用异步的方式进行服务之间的调用,在这种异步的调用情况下会有一个严重的问题,丢失上文下 通过以上图片可以看出异步丢失上下文的原因是不在同一个线程&#xff0c…

『PyQt5-基础篇』| 01 简单的基础了解

『PyQt5-基础篇』| 01 简单的基础了解 1 Qt了解1.1 支持的平台1.2 Qt Creator 2 PyQt52.1 PyQt5主要模块2.2 PyQt5主要类2.3 重要类的继承关系2.4 常用控件 1 Qt了解 跨平台C图形用户界面应用程序开发框架;既可以开发GUI程序,也可用于开发非…

JMeter分布式集群---部署多台机器进行性能压力测试

有些时候,我们在进行压力测试的时候,随着模拟用户的增加,电脑的性能(CPU,内存)占用是非常大的,为了我们得到更加理想的测试结果,我们可以利用jmeter的分布式来缓解机器的负载压力,分…

LVS集群 (四十四)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、集群概述 1. 负载均衡技术类型 2. 负载均衡实现方式 二、LVS结构 三、LVS工作模式 四、LVS负载均衡算法 1. 静态负载均衡 2. 动态负载均衡 五、ipvsadm命令详…

npm报错:xxx packages are looking for funding run `npm fund` for details(解决办法)

报错信息:30 packages are looking for funding run npm fund for details 报错原因:这里是开发者捐赠支持的提示,打开一个github的链接之后,会显示是否需要打赏捐赠的信息。 解决方案:这个打赏是资源的,因…

Golang Gorm 一对多关系 关系表创建

一对多关系 我们先从一对多开始多表关系的学习因为一对多的关系生活中到处都是,例如: 老板与员工女神和添狗老师和学生班级与学生用户与文章 在创建的时候先将没有依赖的创建。表名称ID就是外键。外键要和关联的外键的数据类型要保持一致。 package ma…

投影标杆,旗舰实力,极米投影仪Z7X为用户创造影院级体验

2023年,在彩电消费市场复苏疲软的背景下,智能投影这个显示新品类却持续走红。今年第一季度,极米科技推出Z系列全新一代产品极米Z7X,和极米Z6相比,在保持轻薄体积不变的情况下将亮度提升了83%,达到600CCB 流…

五、linux分析命令

linux分析命令 一、服务器基础知识二、linux文件结构三、linux文件权限四、linux命令1、安装应用fedora家族: 如centosdebain家族:如ubuntu 2、获取帮助第一种:command --help第二种:man command第三种:info 3、服务器性能分析基础…

先加密后签名还是先签名后加密?

先签名后加密还是先加密后签名呢? 先说结论,通常情况下应该先签名后加密。 签名算法计算出来的签名是为了验证消息的完整性,签名算法有比如HMAC-SHA256,加密算法则是为了保证消息的机密性,类似AES-GCM、AES-CBC&#…

海马优化(SHO)算法(含开源MATLAB代码)

先做一个声明:文章是由我的个人公众号中的推送直接复制粘贴而来,因此对智能优化算法感兴趣的朋友,可关注我的个人公众号:启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法,经典的,或者是近几年…

最小二乘法——参数估计过程推导

一 准备 1 给定数据集 D{(),(),...,()},其中假设X是一维的情况,即只有一个自变量 2 线性回归学习的目标:,使得 3 如何确定w和b?关键在于衡量f(x)和y之间距离的方法,此处使用的是‘均方误差’,其具有非常好的几何意义&a…

23款奔驰GLE450时尚型升级ACC自适应巡航系统,解放双脚缓解驾驶疲劳

有的时候你是否厌倦了不停的刹车、加油?是不是讨厌急刹车,为掌握不好车距而烦恼?如果是这样,那么就升级奔驰原厂ACC自适应式巡航控制系统,带排队自动辅助和行车距离警报功能,感受现代科技带给你的舒适安全和…

英特尔开始加码封装领域 | 百能云芯

在积极推进先进制程研发的同时,英特尔正在加大先进封装领域的投入。在这个背景下,该公司正在马来西亚槟城兴建一座全新的封装厂,以加强其在2.5D/3D封装布局领域的实力。据了解,英特尔计划到2025年前,将其最先进的3D Fo…

将公共组件提取到npm包中

多个前端项目中公共组件使用方案(npm包方式) - 简书

AMEYA360:大唐恩智浦电池管理芯片DNB1168-新能源汽车BMS系统的选择

DNB1168是一款全球独有的集成(EIS)交流阻抗谱监测功能的单电池监测芯片。该芯片通过车规级AEC-Q100和汽车行业最高功能安全等级ISO 26262:2018 ASIL-D双重认证。芯片?内部集成多种高精度电池参数监测,支持电压、温度、交流阻抗检…

error: can‘t find Rust compiler

操作系统 win11 pip install -r requirements.txt 报错如下 Using cached https://pypi.tuna.tsinghua.edu.cn/packages/56/fc/a3c13ded7b3057680c8ae95a9b6cc83e63657c38e0005c400a5d018a33a7/pyreadline3-3.4.1-py3-none-any.whl (95 kB) Building wheels for collected p…

python中两个可以美化表格数据输出结果的工具,很好用

目录标题 前言1.使用tabulate美化表格输出2.使用prettytable美化输出总结尾语 前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 在用python处理表格数据中,这其中的工作重点就是对表格类型的数据进行梳理、计算和展示,本文重点介绍展示这个方面的工作…

Redis怎么测试?

有些测试朋友来问我,redis要怎么测试?首先我们需要知道,redis是什么?它能做什么? redis是一个key-value类型的高速存储数据库。 redis常被用做:缓存、队列、发布订阅等。 所以,“redis要怎么…