广告
返回顶部
首页 > 资讯 > 数据库 >mysql中雪花算法是什么意思
  • 700
分享到

mysql中雪花算法是什么意思

2024-04-02 19:04:59 700人浏览 薄情痞子
摘要

Mysql中雪花算法是什么意思?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!一、为何要用雪花算法1、问题产生的背景现如今越

Mysql中雪花算法是什么意思?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!

一、为何要用雪花算法

1、问题产生的背景

现如今越来越多的公司都在用分布式微服务,那么对应的就会针对不同的服务进行数据库拆分,然后当数据量上来的时候也会进行分表,那么随之而来的就是分表以后id的问题。

例如之前单体项目中一个表中的数据主键id都是自增的,mysql是利用autoincrement来实现自增,而oracle是利用序列来实现的,但是当单表数据量上来以后就要进行水平分表,阿里java开发建议是单表大于500w的时候就要分表,但是具体还是得看业务,如果索引用的号的话,单表千万的数据也是可以的。水平分表就是将一张表的数据分成多张表,那么问题就来了如果还是按照以前的自增来做主键id,那么就会出现id重复,这个时候就得考虑用什么方案来解决分布式id的问题了。

2、解决方案

2.1、数据库

可以在某个库中专门维护一张表,然后每次无论哪个表需要自增id的时候都去查这个表的记录,然后用for update表,然后取到的值加一,然后返回以后把再把值记录到表中,但是这个方法适合并发量比较小的项目,因此每次都得锁表。

2.2、Redis

因为redis是单线程的,可以在redis中维护一个键值对,然后哪个表需要直接去redis中取值然后加一,但是这个跟上面一样由于单线程都是对高并发的支持不高,只适合并发量小的项目。

2.3、uuid

可以使用uuid作为不重复主键id,但是uuid有个问题就是其是无序的字符串,如果使用uuid当做主键,那么主键索引就会失效。

2.4、雪花算法

雪花算法是解决分布式id的一个高效的方案,大部分互联网公司都在使用雪花算法,当然还有公司自己实现其他的方案。

二、雪花算法

1、原理

mysql中雪花算法是什么意思

雪花算法就是使用64位long类型的数据存储id,最高位一位存储0或者1,0代表整数,1代表负数,一般都是0,所以最高位不变,41位存储毫秒级时间戳,10位存储机器码(包括5位datacenterId和5位workerId),12存储序列号。这样最大2的10次方的机器,也就是1024台机器,最多每毫秒每台机器产生2的12次方也就是4096个id。(下面有代码实现)

但是一般我们没有那么多台机器,所以我们也可以使用53位来存储id。为什么要用53位?

因为我们几乎都是跟WEB页面打交道,就需要跟js打交道,js支持最大的整型范围为53位,超过这个范围就会丢失精度,53之内可以直接由js读取,超过53位就需要转换成字符串才能保证js处理正确。53存储的话,32位存储秒级时间戳,5位存储机器码,16位存储序列化,这样每台机器每秒可以生产65536个不重复的id。

2、缺点

由于雪花算法严重依赖时间,所以当发生服务器时钟回拨的问题是会导致可能产生重复的id。当然几乎没有公司会修改服务器时间,修改以后会导致各种问题,公司宁愿新加一台服务器也不愿意修改服务器时间,但是不排除特殊情况。

如何解决时钟回拨的问题?可以对序列化的初始值设置步长,每次触发时钟回拨事件,则其初始步长就加1w,可以在下面代码的第85行来实现,将sequence的初始值设置为10000。

三、代码实现

64位的代码实现:

package com.yl.common;

public class SnowflakeIdWorker {

 // ==============================Fields===========================================
 
 private final long twepoch = 1577808000000L;

 
 private final long workerIdBits = 5L;

 
 private final long datacenterIdBits = 5L;

 
 private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

 
 private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

 
 private final long sequenceBits = 12L;

 
 private final long workerIdShift = sequenceBits;

 
 private final long datacenterIdShift = sequenceBits + workerIdBits;

 
 private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

 
 private final long sequenceMask = -1L ^ (-1L << sequenceBits);

 
 private long workerId;

 
 private long datacenterId;

 
 private long sequence = 0L;

 
 private long lastTimestamp = -1L;

 //==============================Constructors=====================================
 
 public SnowflakeIdWorker(long workerId, long datacenterId) {
 if (workerId > maxWorkerId || workerId < 0) {
 throw new IllegalArgumentException(String.fORMat("worker Id can't be greater than %d or less than 0", maxWorkerId));
 }
 if (datacenterId > maxDatacenterId || datacenterId < 0) {
 throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
 }
 this.workerId = workerId;
 this.datacenterId = datacenterId;
 }

 // ==============================Methods==========================================
 
 public synchronized long nextId() {
 long timestamp = timeGen();

 //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
 if (timestamp < lastTimestamp) {
 throw new RuntimeException(
  String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
 }

 //如果是同一时间生成的,则进行毫秒内序列
 if (lastTimestamp == timestamp) {
 sequence = (sequence + 1) & sequenceMask;
 //毫秒内序列溢出
 if (sequence == 0) {
 //阻塞到下一个毫秒,获得新的时间戳
 timestamp = tilNextMillis(lastTimestamp);
 }
 }
 //时间戳改变,毫秒内序列重置
 else {
 sequence = 0L;
 }

 //上次生成ID的时间截
 lastTimestamp = timestamp;

 //移位并通过或运算拼到一起组成64位的ID
 return ((timestamp - twepoch) << timestampLeftShift) //
 | (datacenterId << datacenterIdShift) //
 | (workerId << workerIdShift) //
 | sequence;
 }

 
 protected long tilNextMillis(long lastTimestamp) {
 long timestamp = timeGen();
 while (timestamp <= lastTimestamp) {
 timestamp = timeGen();
 }
 return timestamp;
 }

 
 protected long timeGen() {
 return System.currentTimeMillis();
 }

 //==============================Test=============================================
 
 public static void main(String[] args) {
 SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
 
 for (int i = 0; i < 100; i++) {
 long id = idWorker.nextId();
 System.out.println(id);
 }
 }
}

补充知识:雪花算法实现分布式自增长ID

我就废话不多说了,大家还是直接看代码吧~


public class IdWorker {
 // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
 private final static long twepoch = 1288834974657L;
 // 机器标识位数
 private final static long workerIdBits = 5L;
 // 数据中心标识位数
 private final static long datacenterIdBits = 5L;
 // 机器ID最大值
 private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
 // 数据中心ID最大值
 private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
 // 毫秒内自增位
 private final static long sequenceBits = 12L;
 // 机器ID偏左移12位
 private final static long workerIdShift = sequenceBits;
 // 数据中心ID左移17位
 private final static long datacenterIdShift = sequenceBits + workerIdBits;
 // 时间毫秒左移22位
 private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

 private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
 
 private static long lastTimestamp = -1L;
 // 0,并发控制
 private long sequence = 0L;

 private final long workerId;
 // 数据标识id部分
 private final long datacenterId;

 public IdWorker(){
 this.datacenterId = getDatacenterId(maxDatacenterId);
 this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
 }
 
 public IdWorker(long workerId, long datacenterId) {
 if (workerId > maxWorkerId || workerId < 0) {
  throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
 }
 if (datacenterId > maxDatacenterId || datacenterId < 0) {
  throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
 }
 this.workerId = workerId;
 this.datacenterId = datacenterId;
 }
 
 public synchronized long nextId() {
 long timestamp = timeGen();
 if (timestamp < lastTimestamp) {
  throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
 }

 if (lastTimestamp == timestamp) {
  // 当前毫秒内,则+1
  sequence = (sequence + 1) & sequenceMask;
  if (sequence == 0) {
  // 当前毫秒内计数满了,则等待下一秒
  timestamp = tilNextMillis(lastTimestamp);
  }
 } else {
  sequence = 0L;
 }
 lastTimestamp = timestamp;
 // ID偏移组合生成最终的ID,并返回ID
 long nextId = ((timestamp - twepoch) << timestampLeftShift)
  | (datacenterId << datacenterIdShift)
  | (workerId << workerIdShift) | sequence;

 return nextId;
 }

 private long tilNextMillis(final long lastTimestamp) {
 long timestamp = this.timeGen();
 while (timestamp <= lastTimestamp) {
  timestamp = this.timeGen();
 }
 return timestamp;
 }

 private long timeGen() {
 return System.currentTimeMillis();
 }

 
 protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
 StringBuffer mpid = new StringBuffer();
 mpid.append(datacenterId);
 String name = ManagementFactory.getRuntimeMXBean().getName();
 if (!name.isEmpty()) {
  
  mpid.append(name.split("@")[0]);
 }
 
 return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
 }

 
 protected static long getDatacenterId(long maxDatacenterId) {
 long id = 0L;
 try {
  InetAddress ip = InetAddress.getLocalHost();
  NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  if (network == null) {
  id = 1L;
  } else {
  byte[] Mac = network.getHardwareAddress();
  id = ((0x000000FF & (long) mac[mac.length - 1])
   | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  id = id % (maxDatacenterId + 1);
  }
 } catch (Exception e) {
  System.out.println(" getDatacenterId: " + e.getMessage());
 }
 return id;
 }


}

感谢各位的阅读!看完上述内容,你们对mysql中雪花算法是什么意思大概了解了吗?希望文章内容对大家有所帮助。如果想了解更多相关文章内容,欢迎关注编程网数据库频道。

您可能感兴趣的文档:

--结束END--

本文标题: mysql中雪花算法是什么意思

本文链接: https://www.lsjlt.com/news/50218.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • mysql中雪花算法是什么意思
    mysql中雪花算法是什么意思?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!一、为何要用雪花算法1、问题产生的背景现如今越...
    99+
    2022-10-18
  • MySQL中的/*是什么意思
    在MySQL中,/ /用于多行注释。它可以在SQL语句中的任何位置使用,用于注释掉一段代码或提供对代码的解释。多行注释可以跨越多个行...
    99+
    2023-10-20
    MySQL
  • MySQL中DDL是什么意思
    这篇文章将为大家详细讲解有关MySQL中DDL是什么意思,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。MySQL中的DDL代表着数据库定义语句,用来创建数据库中的表、索引...
    99+
    2022-10-18
  • mysql中proxy是什么意思
    小编给大家分享一下mysql中proxy是什么意思,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!mysql proxy是mysql官方提供的mysql中间件服务,上游可接入若干个【mysql-...
    99+
    2022-10-18
  • MySQL中的/*是什么意思?
    这是一种评论。 是评论的结束。让我们实现并展示如何创建评论mysql> MySQL 将忽略上面的注释。让我们看一个例子。在这里,我们用 编写了注释mysql> mysql> create table DemoTabl...
    99+
    2023-10-22
  • mysql中server_id是什么意思
    MySQL中的server_id是用于标识唯一服务器的一个设置选项,每个MySQL服务器都需要具有唯一的server_id值,以确保在复制和集群环境中正确地识别和处理数据,主要用于两个功能:1、主从复制,用于标识主服务器和从服务器;2、My...
    99+
    2023-07-28
  • mysql 是什么意思
    MySQL是一种开源的关系型数据库管理系统(RDBMS),它是由瑞典MySQL AB公司开发的,现在属于Oracle公司。MySQL...
    99+
    2023-09-05
    mysql
  • MySQL SHOW INDEX语法是什么意思
    这篇文章主要介绍“MySQL SHOW INDEX语法是什么意思”,在日常操作中,相信很多人在MySQL SHOW INDEX语法是什么意思问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望...
    99+
    2022-10-18
  • mysql中的pid是什么意思
    mysql中的pid是指进程ID“Process ID”,用于标识正在运行的进程的唯一标识符,进程是操作系统中正在执行的程序的实例,每个进程都有一个唯一的进程ID,对于跟踪和管理进程非常重要。本教程操作系统:Windows10系统、MySQ...
    99+
    2023-08-02
  • mysql中的optimizer是什么意思
    mysql中的optimizer是什么意思?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。mysql optimizer指的是查...
    99+
    2022-10-18
  • mysql中大表是什么意思
    这篇文章主要介绍mysql中大表是什么意思,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!前言相对来说,什么情况下的数据库表能够称为“大表”呢?当一个表的数据超过千万行的时候,就会对数...
    99+
    2022-10-18
  • MySQL中事务是什么意思
    小编给大家分享一下MySQL中事务是什么意思,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、事务的概念  ...
    99+
    2022-10-19
  • mysql中的hint是什么意思
    mysql中的hint是一种用于向查询优化器提供额外信息或指导的特殊注释或语法结构,可以在SQL查询语句中使用,以影响查询的执行计划或优化器的行为,常见的Hint包括:1、STRAIGHT_JOIN,强制使用连接顺序中指定的表顺序进行连接操...
    99+
    2023-07-25
  • mysql中的queries是什么意思
    在MySQL中的"queries"指的是查询语句的数量,表示在一定时间段内执行的查询的次数或次数统计,通过观察和分析"queries"的值,可以了解数据库的负载情况、查询频率以及是否存在潜在的性能瓶颈...
    99+
    2023-07-28
  • 云计算是什么意思
    云计算是一种通过互联网提供计算资源和服务的方式。它通过将计算任务和数据存储在远程的服务器上,使用户能够通过网络访问和使用这些资源,而...
    99+
    2023-09-07
    云计算
  • mysql in是什么意思
    mysql in是什么意思,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。mysql in常用于where表达式中,其...
    99+
    2022-10-19
  • mysql null是什么意思
    小编给大家分享一下mysql null是什么意思,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!mysql null的含义:1、如在普通的字段中,空值就是表示空值;2、如果将一个空值的数据插入到...
    99+
    2022-10-18
  • MySQL Shell是什么意思
    本篇文章为大家展示了MySQL Shell是什么意思,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。  MySQL She...
    99+
    2022-10-19
  • python中的Prewitt算子是什么意思
    本篇内容主要讲解“python中的Prewitt算子是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python中的Prewitt算子是什么意思”吧!说明Prewitt算子是一阶微分算子...
    99+
    2023-06-20
  • python中的Roberts算子是什么意思
    这篇文章主要讲解了“python中的Roberts算子是什么意思”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“python中的Roberts算子是什么意思”吧!说明Roberts算子又称罗伯...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作