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

详细分析Python模块中的雪花算法(附模板)

目录

  • 前言
  • 1. 基本知识
  • 2. 模板
  • 3. Demo

前言

分布式ID的生成推荐阅读:分布式ID生成方法的超详细分析(全)

1. 基本知识

Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法,最初由 Twitter 设计并开源

它被设计用于解决分布式系统中生成唯一 ID 的需求,特别是在微服务架构和大规模分布式系统中

Snowflake 算法的核心思想是利用时间戳、工作机器 ID 和序列号来生成全局唯一的 64 位长整型 ID

其核心的组成部分如下:

  • 时间戳(Timestamp):通常以毫秒为单位,用于标识生成 ID 的时间点。时间戳的精度对 ID 的唯一性至关重要

  • 工作机器 ID(Worker ID):用于标识不同的工作机器或节点。在分布式系统中,每个节点需要有唯一的标识

  • 数据中心 ID(Datacenter ID):用于标识不同的数据中心。在大规模分布式系统中,可能存在多个数据中心,每个数据中心需要有唯一的标识

  • 序列号(Sequence Number):用于解决同一时间戳下生成多个 ID 的冲突问题。序列号通常是一个自增的数字,通过与一定的位数掩码进行位运算来确保不会溢出

Snowflake 算法的作用:

  • 生成全局唯一 ID:Snowflake 算法可以在分布式系统中生成全局唯一的 ID,确保不同节点生成的 ID 不会冲突

  • 适用于分布式环境:由于Snowflake算法只依赖于机器的时钟和网络通信,因此非常适合在分布式环境中使用

  • 简单且高效:Snowflake 算法的实现相对简单,且性能高效,可以快速生成唯一 ID

2. 模板

以下模板带有注释

实现了一个 Snowflake 类,通过调用 generate 方法可以生成唯一的 Snowflake ID

Snowflake ID 是一个 64 位长整型,包含了时间戳、数据中心 ID、工作机器 ID 和序列号等信息

import timeclass SnowFlake(object):def __init__(self, worker_id, datacenter_id, sequence=0):self.worker_id = worker_id  # 用于标识不同的工作机器self.datacenter_id = datacenter_id  # 用于标识不同的数据中心self.sequence = sequence  # 序列号,用于解决并发生成的 ID 冲突self.tw_epoch = 1288834974657  # Twitter Snowflake epoch (in milliseconds),Snowflake 算法的起始时间点# Bit lengths,用于计算位数self.worker_id_bits = 5  # 5位,最大值为31self.datacenter_id_bits = 5  # 5位,最大值为31self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)  # 最大工作机器 IDself.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)  # 最大数据中心 IDself.sequence_bits = 12  # 12位,支持的最大序列号数self.sequence_mask = -1 ^ (-1 << self.sequence_bits)  # 序列号掩码,用于生成序列号# Create initial timestamp,初始化上一次生成 ID 的时间戳self.last_timestamp = self.current_timestamp()# Check worker_id and datacenter_id values,检查工作机器 ID 和数据中心 ID 的取值范围if self.worker_id > self.max_worker_id or self.worker_id < 0:raise ValueError(f"Worker ID must be between 0 and {self.max_worker_id}")if self.datacenter_id > self.max_datacenter_id or self.datacenter_id < 0:raise ValueError(f"Datacenter ID must be between 0 and {self.max_datacenter_id}")@staticmethoddef current_timestamp():return int(time.time() * 1000)  # 获取当前时间戳,单位为毫秒def generate(self):timestamp = self.current_timestamp()  # 获取当前时间戳if timestamp < self.last_timestamp:  # 如果当前时间戳小于上一次生成 ID 的时间戳raise ValueError("Clock moved backwards. Refusing to generate ID for {} milliseconds".format(self.last_timestamp - timestamp))  # 抛出异常,时钟回拨if timestamp == self.last_timestamp:  # 如果当前时间戳等于上一次生成 ID 的时间戳self.sequence = (self.sequence + 1) & self.sequence_mask  # 增加序列号,并与序列号掩码进行与运算,防止溢出if self.sequence == 0:  # 如果序列号归零timestamp = self.wait_next_millis(self.last_timestamp)  # 等待下一毫秒else:self.sequence = 0  # 时间戳变化,序列号重置为零self.last_timestamp = timestamp  # 更新上一次生成 ID 的时间戳# Generate Snowflake ID,生成 Snowflake ID_id = ((timestamp - self.tw_epoch) << (self.worker_id_bits + self.datacenter_id_bits)) | (self.datacenter_id << self.worker_id_bits) | self.worker_id << self.sequence_bits | self.sequence  # 使用时间戳、数据中心 ID、工作机器 ID 和序列号生成 IDreturn f"{_id:016d}"  # 返回 64 位长整型 ID 的字符串表示,补齐到16位长度def wait_next_millis(self, last_timestamp):timestamp = self.current_timestamp()  # 获取当前时间戳while timestamp <= last_timestamp:  # 循环直到获取到下一毫秒的时间戳timestamp = self.current_timestamp()return timestamp  # 返回下一毫秒的时间戳

3. Demo

结合以上模板,放一个调用的过程:

# 示例用法
if __name__ == "__main__":# 假设有两个数据中心,每个数据中心有两个工作机器worker_id = 1datacenter_id = 1snowflake = SnowFlake(worker_id, datacenter_id)# 生成10个IDfor i in range(10):print(snowflake.generate())

截图如下:

在这里插入图片描述

相关文章:

  • Django框架的全面指南:从入门到高级【第128篇—Django框架】
  • 24计算机考研调剂 | 温州大学
  • C# 连接neo4j数据库,包括非默认的neo4j默认库
  • 基于ssm+layui的图书管理系统
  • C语言分析基础排序算法——归并排序
  • jwt以及加密完善博客系统
  • 第八阶段:uni-app小程序 --首页开发(2)
  • macOS - 获取硬件设备信息
  • 分布式ID(8):分布式ID生成方法
  • 【测试知识】业务面试问答突击版3---bug、测试用例设计
  • [蓝桥杯 2015 省 B] 生命之树
  • Python和Java哪一个更适合初学者?
  • 比特币,区块链及相关概念简介(二)
  • 数据结构的概念大合集02(线性表)
  • mysql转达梦的python脚本
  • 【译】理解JavaScript:new 关键字
  • 11111111
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • Angular2开发踩坑系列-生产环境编译
  • Apache的80端口被占用以及访问时报错403
  • ES2017异步函数现已正式可用
  • es6(二):字符串的扩展
  • ES学习笔记(12)--Symbol
  • If…else
  • JavaScript函数式编程(一)
  • Java反射-动态类加载和重新加载
  • JS学习笔记——闭包
  • learning koa2.x
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • php面试题 汇集2
  • 关于extract.autodesk.io的一些说明
  • 码农张的Bug人生 - 初来乍到
  • 实习面试笔记
  • 线上 python http server profile 实践
  • 协程
  • 用jQuery怎么做到前后端分离
  • 与 ConTeXt MkIV 官方文档的接驳
  • NLPIR智能语义技术让大数据挖掘更简单
  • 数据可视化之下发图实践
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (10)ATF MMU转换表
  • (java)关于Thread的挂起和恢复
  • (附源码)ssm码农论坛 毕业设计 231126
  • (九)信息融合方式简介
  • (强烈推荐)移动端音视频从零到上手(上)
  • (区间dp) (经典例题) 石子合并
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)基于IDEA的JAVA基础10
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net 高效开发之不可错过的实用工具