当前位置: 首页 > news >正文

C#进阶-基于雪花算法的订单号设计与实现

在现代电商系统和分布式系统中,高效地生成全局唯一的订单号是一个关键需求。订单号不仅需要唯一性,还需要具备一定的趋势递增性,以满足数据库索引和排序的需求。本文将介绍如何在C#中使用雪花算法(Snowflake)设计和实现高性能的订单号生成器。

在这里插入图片描述


一、雪花算法的定义

雪花算法最初由Twitter开发,是一种用于生成全局唯一ID的高性能算法。其核心思想是结合当前时间戳机器ID序列号,生成一个64位的整数ID,确保在分布式环境下的唯一性趋势递增性

雪花算法的结构:

雪花算法生成的ID通常由以下几个部分组成:

部分位数说明
符号位1位始终为0,不参与实际运算。
时间戳41位记录当前时间戳,可以使用69年。
机器ID10位标识不同的机器或节点。
序列号12位同一毫秒内的序列号,支持每个节点每毫秒生成4096个ID。

二、使用雪花算法生成订单号

1. 实现前需要考虑的点

在订单号的设计中,我们需要考虑以下几点:

特性说明
唯一性订单号必须全局唯一,不能重复。
有序性订单号应具备趋势递增性,方便数据库索引和排序。
性能生成订单号的过程应高效,支持高并发环境。

基于上述需求,雪花算法是一个理想的选择。下面我们将基于提供的参考代码,详细解释如何在C#中实现雪花算法。


2. 创建含雪花算法的ID生成类

定义 ID生成类 IdWorker.cs:

public class IdWorker
{// 机器IDprivate static long workerId;// 起始时间戳(可以自行设置,不要大于当前时间戳)private static long twepoch = 687888001020L;// 序列号private static long sequence = 0L;// 机器ID所占的位数private static int workerIdBits = 4;// 最大机器IDpublic static long maxWorkerId = -1L ^ -1L << workerIdBits;// 序列号所占的位数private static int sequenceBits = 10;// 机器ID左移位数private static int workerIdShift = sequenceBits;// 时间戳左移位数private static int timestampLeftShift = sequenceBits + workerIdBits;// 序列号的掩码public static long sequenceMask = -1L ^ -1L << sequenceBits;// 上次生成ID的时间戳private long lastTimestamp = -1L;// 构造函数,初始化机器IDpublic IdWorker(long workerId){if (workerId > maxWorkerId || workerId < 0)throw new Exception($"Worker ID can't be greater than {maxWorkerId} or less than 0");IdWorker.workerId = workerId;}// 生成下一个IDpublic long NextId(){lock (this){long timestamp = TimeGen();if (lastTimestamp == timestamp){// 同一毫秒内,序列号自增sequence = (sequence + 1) & sequenceMask;if (sequence == 0){// 序列号达到上限,等待下一毫秒timestamp = TilNextMillis(lastTimestamp);}}else{// 不同毫秒内,序列号归零sequence = 0;}if (timestamp < lastTimestamp){throw new Exception($"Clock moved backwards. Refusing to generate id for {lastTimestamp - timestamp} milliseconds");}lastTimestamp = timestamp;// 按位或运算,组合生成唯一IDlong nextId = ((timestamp - twepoch) << timestampLeftShift)| (workerId << workerIdShift)| sequence;return nextId;}}// 等待下一毫秒private long TilNextMillis(long lastTimestamp){long timestamp = TimeGen();while (timestamp <= lastTimestamp){timestamp = TimeGen();}return timestamp;}// 获取当前时间戳private long TimeGen(){return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;}
}

关键点解析:

  • 时间戳的处理:使用Unix时间戳(毫秒级)减去自定义的起始时间戳twepoch,确保生成的ID较小,且可用时间更长。
  • 序列号的控制:在同一毫秒内,通过自增序列号确保ID的唯一性,当序列号达到上限时,等待下一毫秒。
  • 线程安全:使用lock关键字确保在多线程环境下生成的ID仍然唯一。
  • 位移操作:通过位移和按位或运算,将时间戳、机器ID和序列号组合成一个64位的唯一ID。

3. 订单号工具类的调用

下面,我们使用刚刚创建的工具类来生成订单号。

调用示例:

class Program
{static void Main(string[] args){IdWorker idWorker = new IdWorker(1);for (int i = 0; i < 10; i++){long id = idWorker.NextId();Console.WriteLine($"生成的订单号:{id}");}}
}

输出示例

生成的订单号:2656420150056961
生成的订单号:2656420150056962
生成的订单号:2656420150056963
...

4. 注意事项

① 机器ID的分配:在分布式环境下,需要为每个节点分配唯一的workerId,以避免ID冲突。
② 时间同步:服务器的系统时间需要同步,避免因时间回拨导致ID重复或生成失败。
③ 起始时间戳twepoch:应设置为一个固定的过去时间,以确保ID的有效性和可读性。


三、雪花算法总结

通过雪花算法,我们可以在C#中高效地生成全局唯一且趋势递增的订单号。该算法简单可靠,适用于高并发和分布式系统。雪花算法的设计巧妙地结合了时间戳、机器ID和序列号,确保了在分布式环境下的ID生成既快速又不重复。由于其基于时间的特性,生成的订单号具备天然的有序性,这对于数据库的索引优化和查询性能提升具有显著的优势。

在实际应用中,雪花算法不仅限于订单号的生成,还可以广泛应用于其他需要唯一标识的场景,如用户ID、会话ID以及日志追踪等。其高效的生成能力使其能够支持大规模的并发请求,而不成为系统性能的瓶颈。同时,雪花算法的可扩展性也非常强,通过调整机器ID的位数和序列号的长度,可以灵活地适应不同规模的分布式系统需求。

此外,雪花算法在实现时需要注意时间同步问题,确保各个节点的系统时间保持一致,以避免因时间回拨或偏差导致的ID冲突或生成错误。采用网络时间协议(NTP)等时间同步机制,可以有效缓解这一问题。另一个需要关注的点是机器ID的分配,确保每个节点拥有唯一的机器ID,这是保证ID全局唯一性的关键。

总的来说,雪花算法以其高效、可靠和可扩展的特点,成为分布式系统中生成唯一标识符的首选方案。在C#中实现雪花算法,不仅能够满足当前系统对订单号的需求,还为未来系统的扩展和优化打下了坚实的基础。希望本文的介绍能够帮助您在实际项目中应用雪花算法,实现高性能、高可靠性的订单号生成,提升系统整体的稳定性和用户体验。

在这里插入图片描述

相关文章:

C#进阶-基于雪花算法的订单号设计与实现

在现代电商系统和分布式系统中&#xff0c;高效地生成全局唯一的订单号是一个关键需求。订单号不仅需要唯一性&#xff0c;还需要具备一定的趋势递增性&#xff0c;以满足数据库索引和排序的需求。本文将介绍如何在C#中使用雪花算法&#xff08;Snowflake&#xff09;设计和实现…...

低版本SqlSugar的where条件中使用可空类型报语法错误

SQLServer数据表中有两列可空列&#xff0c;均为数值类型&#xff0c;同时在数据库中录入测试数据&#xff0c;Age和Height列均部分有值。   使用SqlSugar的DbFirst功能生成数据库表类&#xff0c;其中Age、Height属性均为可空类型。   开始使用的SqlSugar版本较低&…...

跨游戏引擎的H5渲染解决方案(腾讯)

本文是腾讯的一篇H5 跨引擎解决方案的精炼。 介绍 本文通过实现基于精简版的HTML5&#xff08;HyperText Mark Language 5&#xff09;来屏蔽不同引擎&#xff0c;平台底层的差异。 好处&#xff1a; 采用H5的开发方式&#xff0c;可以将开发和运营分离&#xff0c;运营部门自…...

docker构建java镜像,运行镜像出现日志 no main manifest attribute, in /xxx.jar

背景 本文主要是一个随笔,记录一下出现"no main manifest attribute"的解决办法 问题原因 主要是近期在构建一个镜像,在镜像构建成功后,运行一直提示"no main manifest attribute",当时还在想,是不是Dockerfile写错了,后来仔细检查了一下,发现是…...

react + antDesignPro 企业微信扫码登录

效果 实现步骤 1、项目中document.ejs文件引入企微js链接 注意&#xff1a;技术栈是使用的react antDesignPro&#xff0c;不同的技术栈有不同的入口文件&#xff08;如vue在html文件引入&#xff09; <script src"https://wwcdn.weixin.qq.com/node/wework/wwopen/j…...

Go-知识-定时器

Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…...

【alluxio编译报错】Some files do not have the expected license header

Some files do not have the expected license header 快捷导航 在开始解决问题之前&#xff0c;大家可以通过下面的导航快速找到相关资源啦&#xff01;&#x1f4a1;&#x1f447; 快捷导航链接地址备注相关文档-ambaribigtop自定义组件集成https://blog.csdn.net/TTBIGDA…...

基于SpringBoot+Vue的商城积分系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目源码、Python精…...

docker-compose up 报错:KeyError: ‘ContainerConfig‘

使用命令查看所有容器&#xff1a; docker ps -a 找到有异常的容器删除 docker rm {容器id} 后续发现还是会出现这种情况&#xff0c;尝试使用更高版本的docker-compose后解决...

股票行情接口,量化金融交易在未来会被广泛应用吗

炒股自动化&#xff1a;申请官方API接口&#xff0c;散户也可以 python炒股自动化&#xff08;0&#xff09;&#xff0c;申请券商API接口 python炒股自动化&#xff08;1&#xff09;&#xff0c;量化交易接口区别 Python炒股自动化&#xff08;2&#xff09;&#xff1a;获取…...

[SDX35+WCN6856]SDX35 开启class/gpio子系统配置操作说明

SDX35 SDX35介绍 SDX35设备是一种多模调制解调器芯片,支持 4G/5G sub-6 技术。它是一个4nm芯片专为实现卓越的性能和能效而设计。它包括一个 1.9 GHz Cortex-A7 应用处理器。 SDX35主要特性 ■ 3GPP Rel. 17 with 5G Reduced Capability (RedCap) support. Backward compati…...

react:React Hook函数

使用规则 只能在组件中或者其他自定义的Hook函数中调用 只能在组件的顶层调用&#xff0c;不能嵌套在if、for、 其他函数中 基础Hook 函数 useState useState是一个hook函数&#xff0c;它允许我们向组件中添加一个状态变量&#xff0c;从而控制影响组件的渲染结果 示例1…...

算法学习2

学习目录 一.插入排序 一.插入排序 从数组的第一个元素开始&#xff0c;当前元素与其前一个元素进行比较&#xff1b; 大于&#xff08;或小于时&#xff09;将其进行交换&#xff0c;即当前元素替换到前一位&#xff1b; 再将该元素与替换后位置的前一个元素进行交换&#xf…...

vue循环渲染动态展示内容案例(“更多”按钮功能)

当我们在网页浏览时&#xff0c;常常会有以下情况&#xff1a;要展示的内容太多&#xff0c;但展示空间有限&#xff0c;比如我们要在页面的一部分空间中展示较多的内容放不下&#xff0c;通常会有两种解决方式&#xff1a;分页&#xff0c;“更多”按钮。 今天我们的案例用于…...

好用的工具网址

代码类&#xff1a; 1,json解析&#xff1a;JSON在线解析及格式化验证 - JSON.cn 2.传参转化编码 在线url网址编码、解码器-BeJSON.com 日常&#xff1a; 1.莆田医院查询&#xff1a;滚蛋吧&#xff01;莆田系...

【Temporal】方法规范

在workflow或者childWorkflow的方法代码中&#xff0c;不能使用golang的一些库方法&#xff0c;比如sleep&#xff0c;go协程等&#xff0c;必须使用其对应的封装方法&#xff0c;比如对应关系如下&#xff1a; time.Sleep -> workflow.Sleepgo xx -> workflow.Go(xx) 这…...

Python实现图形学曲线和曲面的Bezier曲线算法

目录 使用Python实现图形学曲线和曲面的Bezier曲线算法引言Bezier曲线的数学原理1. Bezier曲线定义2. Bezier曲线的递归形式 Python实现Bezier曲线算法1. 代码实现 代码详解使用示例Bezier曲线的特点Bezier曲面的扩展Bezier曲面类实现 总结 使用Python实现图形学曲线和曲面的Be…...

Unity数据持久化4——2进制

概述 基础知识 各类型数据转字节数据 文件操作相关 文件相关 文件流相关 文件夹相关 练习题 using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEngine;public class Exercises1 : MonoBehaviour {/…...

经典sql题(八)SQL 查询详细指南总结一

SQL 查询详细指南 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系数据库的标准语言。本文将详细介绍 SQL 中的一些常见操作及其用法&#xff0c;包括 DISTINCT 去重、LIMIT 限制、排序、开窗函数、NULL 值替换、JOIN 与 UNION 等。 1. DISTI…...

用Python实现时间序列模型实战——Day 30: 学习总结与未来规划

在第30天&#xff0c;我们将对整个学习过程进行总结&#xff0c;复习关键知识点&#xff0c;并展望未来的学习与应用方向。我们将涵盖时间序列分析过程中涉及的主要模型、技术和工具&#xff0c;总结它们的优势和应用场景。此外&#xff0c;规划未来如何进一步深入学习&#xf…...

ChatGPT居然主动勾引用户,OpenAI又测试新功能? 一文教你学会订阅

有网友表示&#xff0c;他收到了ChatGPT主动给他发送的消息&#xff0c;询问“你高中的第一周过得怎么样&#xff1f;还适应吗&#xff1f;” 他很懵逼的回了一句“你刚才是给我发消息吗&#xff1f;”。也就是说&#xff0c;在没有任何先前文本提示下&#xff0c;ChatGPT主动…...

基于SpringBoot+Vue的考研百科网站系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目源码、Python精…...

深度之眼(三十)——pytorch(一)--深入浅出pytorch(附安装流程)

文章目录 一、前言一、pytoch二、六个部分三、如何学习四、学习路径&#xff08;重要)五、安装pytorch5.1 坑15.2 坑2 一、前言 我看了下目录 第一章和第二章都是本科学的数字图像处理。 也就是这一专栏&#xff1a;数字图像实验。 所以就不准备学习前两章了&#xff0c;直接…...

麒麟银河桌面版,成功安装cuda12.6,mysql

一、 要卸载并禁用 nouveau 驱动程序&#xff0c;可以按照以下步骤进行&#xff1a; 1. 确认 nouveau 驱动的当前状态&#xff1a; 首先&#xff0c;你可以使用以下命令查看 nouveau 驱动是否正在运行&#xff1a; lsmod | grep nouveau如果有输出&#xff0c;说明 nouveau …...

CentOS 7 YUM源不可用

CentOS 7 操作系统在2024年6月30日后将停止官方维护&#xff0c;并且官方提供的YUM源将不再可用。 修改&#xff1a;nano /etc/yum.repos.d/CentOS-Base.repo # CentOS-Base.repo [base] nameCentOS-$releasever - Base baseurlhttp://mirrors.aliyun.com/centos/$rel…...

Java反序列化利用链篇 | URLDNS链

文章目录 URLDNS链调用链分析Payload编写 系列篇其他文章&#xff0c;推荐顺序观看~ Java反序列化利用链篇 | JdbcRowSetImpl利用链分析Java反序列化利用链篇 | CC1链_全网最菜的分析思路Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链Java反序列化利用链篇 | URLD…...

Android 短信验证码自动填充

本文主要介绍国外google上线的app 短信自动填充方案。 本方案主要是使用google提出的&#xff0c;防止开发者使用SMS相关权限造成的用户信息泄露 目录 注意点&#xff1a; 1、本方式不适合华为手机&#xff0c;华为有自己的获取方式 2、本方式不需要添加任何短信权限 3、…...

数据库 MySQL 是否需要容器化?

容器的定义&#xff1a;容器是为了解决“在切换运行环境时&#xff0c;如何保证软件能够正常运行”这一问题。 目前&#xff0c;容器和 Docker 依旧是技术领域最热门的词语&#xff0c;无状态的服务容器化已经是大势所趋&#xff0c;同时也带来了一个热点问题被大家所争论不以…...

Kettle的安装及简单使用

Kettle的安装及简单使用一、kettle概述二、kettle安装部署和使用Windows下安装案例1&#xff1a;MySQL to MySQL案例2&#xff1a;使用作业执行上述转换&#xff0c;并且额外在表stu2中添加一条数据案例3&#xff1a;将hive表的数据输出到hdfs案例4&#xff1a;读取hdfs文件并将…...

Golang | Leetcode Golang题解之第420题强密码检验器

题目&#xff1a; 题解&#xff1a; func strongPasswordChecker(password string) int {hasLower, hasUpper, hasDigit : 0, 0, 0for _, ch : range password {if unicode.IsLower(ch) {hasLower 1} else if unicode.IsUpper(ch) {hasUpper 1} else if unicode.IsDigit(ch)…...