分布式 ID 生成策略(二)

在上一篇文章,分布式 ID 生成策略(一),我们讨论了基于数据库的 ID 池策略,今天来看另一种实现,基于雪花算法的分布式 ID 生成策略。

在这里插入图片描述
如图所示,我们用 41 位时间戳 + 12 位机器 ID + 10 位序列号,来表示一个 64 位的分布式 ID。

基于这样的雪花算法来保证 ID 的唯一性

  • 时间戳是递增的,不同时刻产生的 ID 肯定是不同的;
  • 机器 ID 是不同的,同一时刻不同机器产生的 ID 肯定也是不同的;
  • 同一时刻同一机器上,可以轻易控制序列号。
CREATE TABLE `global_sequence_time` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`node_name` varchar(32) NOT NULL DEFAULT '' COMMENT '机器名称,通常为内网IP',`node_id` smallint(6) NOT NULL COMMENT '机器ID,数字,最大1023',`sn` varchar(128) NOT NULL DEFAULT '' COMMENT '业务字段名称',`version` bigint(20) NOT NULL DEFAULT '1' COMMENT '乐观锁版本',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_name` (`sn`,`node_name`) USING BTREE,UNIQUE KEY `uk_id` (`sn`,`node_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='全局ID生成表';
  • node_name:节点名称,默认为节点的内网IP。所以,同一个机器上,部署多个应用,他们的 node_name 是一样的;

  • sn:业务名称,根据此值分类ID的生成;

  • node_id:数字类型,最大值不能超过1024,即此算法最多支持1024个节点。

还有两个唯一约束

  • 同一个业务sn值,在一个机器上不能部署2个;
  • 同一个业务sn值,node_id不能重复。
package idgenerator;/*** Description* 基于SnowFlake算法实现* 将node_id保存在数据库中,根据本机IP地址作为标识.每个机器对应一个node_id.*/
public class TimeBasedIDGenerator extends IDGenerator {protected static final int DEFAULT_RETRY = 6;public static final int NODE_SHIFT = 10;public static final int SEQ_SHIFT = 12;public static final short MAX_NODE = 1024;//最大node 个数,public static final short MAX_SEQUENCE = 4096;//每秒最大ID个数private short sequence;private long referenceTime;private DataSource dataSource;private Map<String, Integer> cachedNodeId = new HashMap<>();private String nodeName;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}/****/public TimeBasedIDGenerator() {nodeName = getLocalAddress();}private synchronized Integer getNodeId(String sn) {Integer nodeId = cachedNodeId.get(sn);//正常,返回if (nodeId != null) {return nodeId;}int i = 0;while (i < DEFAULT_RETRY) {nodeId = fetch(sn);if (nodeId > MAX_NODE) {throw new IllegalStateException("node_id is greater than " + MAX_NODE + ",please check sn=" + sn);}if (nodeId > 0) {cachedNodeId.put(sn, nodeId);break;}i++;}return nodeId;}/*** @return The next 64-bit integer.*/public synchronized long next(String sn) {Integer nodeId = getNodeId(sn);if (nodeId == null || nodeId < 0) {throw new IllegalStateException("无法获取nodeId,sn=" + sn);}long currentTime = System.currentTimeMillis();long counter;if (currentTime < referenceTime) {throw new RuntimeException(String.format("Last referenceTime %s is after reference time %s", referenceTime, currentTime));} else if (currentTime > referenceTime) {this.sequence = 0;} else {if (this.sequence < MAX_SEQUENCE) {this.sequence++;} else {throw new RuntimeException("Sequence exhausted at " + this.sequence);}}counter = this.sequence;referenceTime = currentTime;return currentTime << NODE_SHIFT << SEQ_SHIFT | nodeId << SEQ_SHIFT | counter;}/*** 获取nodeId.* @param sn* @return*/private int fetch(String sn) {Connection connection = null;PreparedStatement ps = null;try {connection = dataSource.getConnection();connection.setAutoCommit(true);//普通操作connection.setReadOnly(false);ps = connection.prepareStatement("select node_id from `global_sequence_time` where `sn` = ? and node_name = ? limit 1");ps.setString(1, sn);ps.setString(2, nodeName);ResultSet rs = ps.executeQuery();//已有数据,则直接返回if (rs.next()) {return rs.getInt(1);}ps.close();//如果没有数据,则首先获得已有的最大node_id,然后自增//查询已知最大idps = connection.prepareStatement("select MAX(node_id) AS m_id from `global_sequence_time` where `sn` = ?");ps.setString(1, sn);rs = ps.executeQuery();int id = 1;if (rs.next()) {id = rs.getInt(1) + 1;}ps.close();//新建记录ps = connection.prepareStatement("insert into global_sequence_time(node_name,node_id,sn,create_time,update_time) VALUE (?,?,?,NOW(),NOW())");ps.setString(1, nodeName);ps.setInt(2, id);ps.setString(3, sn);int row = ps.executeUpdate();if (row > 0) {return id;}} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (ps != null) {ps.close();}if (connection != null) {connection.close();}} catch (Exception ex) {//}}return -1;}private String getLocalAddress() {try {Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();//一个主机有多个网络接口while (netInterfaces.hasMoreElements()) {NetworkInterface netInterface = netInterfaces.nextElement();Enumeration<InetAddress> addresses = netInterface.getInetAddresses();while (addresses.hasMoreElements()) {InetAddress address = addresses.nextElement();if (address.isSiteLocalAddress() && !address.isLoopbackAddress()) {return address.getHostAddress();}}}} catch (Exception e) {throw new RuntimeException("无法获取本地IP地址", e);}return null;}
}

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

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

相关文章

解决edge浏览器无法同步问题

有时候电脑没带&#xff0c;但是浏览器没有同步很烦恼。chrome浏览器的同步很及时在多设备之间能很好使用。但是edge浏览器同步没反应。 在这里插入图片描述 解决方法&#xff1a; 一、进入edge浏览器点击图像会显示未同步。点击“管理个人资料”&#xff0c;进入后点击同步&…

【机器学习】14. 集成学习 ensemble: bagging, boosting, 随机森林 random forest

集成学习 ensemble: bagging, boosting, 随机森林 random forest 1. Ensemble 整体认知2. 使用Ensemble的原因3. 构建Ensemble 的方法4. Bagging&#xff08;bootstrap aggregation&#xff09;特点 5. BoostingAdaBoost整体算法思路 6. 比较7. 随机森林 1. Ensemble 整体认知 …

记录一次更新idea

一、官网下载安装包&#xff0c;拿所需版本 二、链接下载&#xff0c; 逐行仔细读readme.txt 三、执行script(unstall<->install)vbs、-javaagent:更改时记得

Vue背景图片自适应大屏与小屏

1&#xff0c;父绝子相 效果是台式看的更多&#xff0c;笔记本看部分。但是图片不会变形 <div class"father" style"width:100%; position:relative"> <img src"test.png" class"son" style"width:1920px; position:a…

低代码平台如何通过AI赋能,实现更智能的业务自动化?

引言 随着数字化转型的加速推进&#xff0c;企业在日常运营中面临的业务复杂性与日俱增。如何快速响应市场需求&#xff0c;优化流程&#xff0c;并降低开发成本&#xff0c;成为各行业共同关注的核心问题。低代码平台作为一种能够快速构建应用程序的工具&#xff0c;因其可视化…

实现企业微信打卡月报与简道云的高效集成

实现企业微信打卡月报与简道云的高效集成 企业微信打卡月报同步到简道云 在企业管理中&#xff0c;员工的考勤数据是至关重要的一环。为了实现高效的数据管理和分析&#xff0c;我们需要将企业微信的打卡月报数据集成到简道云平台。本文将分享一个具体的技术案例&#xff0c;展…

【Redis】常见基本全局命令

一、Redis俩大核心命令 由于Redis是以键值对的形式进行数据存取&#xff0c;自然就离不开不断的存储和获取&#xff0c;而其所对应的命令则是set和get&#xff0c;如此说来二者为Redis的核心基础命令也不为过。 作用&#xff1a;用于存储Stirng类型的数据 返回&#xff1a;当…

GPT避坑指南:如何辨别逆向、AZ、OpenAI官转

市面上有些说自己是官转&#xff0c;一刀只需要1块甚至几毛钱&#xff0c;并声称官方倍率的&#xff0c;很大可能就是使用的是 逆向或Azure。 如何鉴别逆向 逆向的种类很多&#xff0c;主要分为3类 逆向不知名A| 镜像站或偷的 key。成本约等于0&#xff0c;调用聊天数据可能在…

第十一章 Shiro会话管理和加密

学习目标 11.1 会话管理11.1.1 会话相关API一、获取会话二、会话属性管理三、会话信息获取四、会话控制五、会话监听六、会话DAO七、会话验证 11.2 缓存一、缓存接口二、内置缓存实现三、配置缓存四、使用缓存五、缓存清理六、注意事项 前面两章我们已经掌握了Shiro四大基石的认…

frida脚本,自动化寻址JNI方法

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 1. 通过 ArtMethod 结构体找到 jni 方法在内存中的地址&#xff0c;并把寻址方法通过 rpc.exports 暴露给 Python 脚本调用 jni_addr.js let entry_point_fr…

【PnP】详细公式推导,使用DLT直接线性变换法求解相机外参

文章目录 &#x1f680;PnP1️⃣ 求解不考虑尺度的解2️⃣ 恢复解的尺度3️⃣ 另一种解法 &#x1f680;PnP PnP(Perspective-n-Point)是求解3D到2D点相机外参的算法。PnP算法有DLT直接线性变换、P3P三对点估计位姿、EPnP(Efficient PnP)、BA(Bundle Adjustment)光速法平差。这…

数据库基础介绍

前言&#xff1a; 在当今信息化、数字化的时代&#xff0c;数据库是支撑一切信息系统的核心基础设施。无论是金融机构的账户管理、电商平台的商品库存&#xff0c;还是社交媒体的用户信息&#xff0c;数据库都在背后扮演着关键角色数据库不仅用于存储和管理数据&#xff0c;更…

[Ansible实践笔记]自动化运维工具Ansible(一):初探ansibleansible的点对点模式

文章目录 Ansible介绍核心组件任务执行方式 实验前的准备更新拓展安装包仓库在ansible主机上配置ip与主机名的对应关系生成密钥对将公钥发送到被管理端&#xff0c;实现免密登录测试一下是否实现免密登录 常用工具ansibleansible—docansible—playbook 主要配置文件 Ansible 模…

倪师学习笔记-天纪-易经八卦

一、简介 卦代表事情&#xff0c;爻代表时机&#xff0c;三爻为一卦八卦对应的天相&#xff0c;六十四卦对应人间事 二、八卦性 1、乾 天父亲向下看&#xff0c;无所求&#xff0c;雄心万丈始终如一&#xff0c;贞&#xff0c;坚心&#xff0c;专心至刚&#xff0c;天威&am…

Hash表算法

哈希表 理论知识&#xff08;本文来自于代码随想录摘抄&#xff09;什么是哈希常见的三种哈希结数组&#xff1a;set:map:其他常用方法或者技巧&#xff08;自己总结的&#xff09; 练习题和讲解有效的字母移位词349. 两个数组的交集1. 两数之和454. 四数相加 II15. 三数之和 总…

如何选择适合自己的 Python IDE

集成开发环境&#xff08;IDE&#xff09;是指提供广泛软件开发能力的软件应用程序。IDE 通常包括源代码编辑器、构建自动化工具和调试器。大多数现代 IDE 都配备了智能代码补全功能。在本文中&#xff0c;你将发现目前市场上最好的 Python IDE。 什么是 IDE&#xff1f; IDE…

为什么架构设计禁止IP直连?

什么是IP直连&#xff1f; IP直连指应用程序直接在代码中硬编码IP地址&#xff0c;比如&#xff0c;连接mysql数据库的数据库链接&#xff0c;如下的定义方式&#xff0c;就属于IP直连。 这种写法在开发环境中很常见&#xff0c;但是&#xff0c;在正式生产环境中&#xff0c;…

Linux shell编程学习笔记87:blkid命令——获取块设备信息

0 引言 在进行系统安全检测时&#xff0c;我们需要收集块设备的信息&#xff0c;这些可以通过blkid命令来获取。 1 blkid命令的安装 blkid命令是基于libblkid库的命令行工具&#xff0c;可以在大多数Linux发行版中使用。 如果你的Linux系统中没有安装blkid命令&#xff0c;…

Nginx处理并发连接

Nginx以其高效处理并发连接的能力而闻名&#xff0c;这主要归功于其事件驱动的架构和异步非阻塞I/O操作。 是Nginx处理并发连接的关键机制&#xff1a; 1. 事件驱动架构 Nginx采用事件驱动架构&#xff0c;这意味着它使用事件通知机制来响应网络事件&#xff0c;如新连接、读…

构建生产级的 RAG 系统

对 RAG 应用程序进行原型设计很容易&#xff0c;但要使其高性能、健壮且可扩展到大型知识语料库却很困难。 本指南包含各种提示和技巧&#xff0c;以提高 RAG 工作流程的性能。我们首先概述一些通用技术 - 它们按照简单到复杂的顺序进行排列。然后&#xff0c;我们将更深入地研…