Apache Seata基于改良版雪花算法的分布式UUID生成器分析2


title: 关于新版雪花算法的答疑
author: selfishlover
keywords: [Seata, snowflake, UUID, page split]
date: 2021/06/21

本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。

关于新版雪花算法的答疑

在上一篇关于新版雪花算法的解析中,我们提到新版算法所做出的2点改变:

  1. 时间戳不再时刻追随系统时钟。
  2. 节点ID和时间戳互换位置。由原版的:
    在这里插入图片描述

改成:在这里插入图片描述

有细心的同学提出了一个问题:新版算法在单节点内部确实是单调递增的,但是在多实例部署时,它就不再是全局单调递增了啊!因为显而易见,节点ID排在高位,那么节点ID大的,生成的ID一定大于节点ID小的,不管时间上谁先谁后。而原版算法,时间戳在高位,并且始终追随系统时钟,可以保证早生成的ID小于晚生成的ID,只有当2个节点恰好在同一时间戳生成ID时,2个ID的大小才由节点ID决定。这样看来,新版算法是不是错的?

这是一个很好的问题!能提出这个问题的同学,说明已经深入思考了标准版雪花算法和新版雪花算法的本质区别,这点值得鼓励!在这里,我们先说结论:新版算法的确不具备全局的单调递增性,但这不影响我们的初衷(减少数据库的页分裂)。这个结论看起来有点违反直觉,但可以被证明。

在证明之前,我们先简单回顾一下数据库关于页分裂的知识。以经典的mysql innodb为例,innodb使用B+树索引,其中,主键索引的叶子节点还保存了数据行的完整记录,叶子节点之间以双向链表的形式串联起来。叶子节点的物理存储形式为数据页,一个数据页内最多可以存储N条行记录(N与行的大小成反比)。如图所示:
在这里插入图片描述

B+树的特性要求,左边的节点应小于右边的节点。如果此时要插入一条ID为25的记录,会怎样呢(假设每个数据页只够存放4条记录)?答案是会引起页分裂,如图:
在这里插入图片描述

页分裂是IO不友好的,需要新建数据页,拷贝转移旧数据页的部分记录等,我们应尽量避免。

理想的情况下,主键ID最好是顺序递增的(例如把主键设置为auto_increment),这样就只会在当前数据页放满了的时候,才需要新建下一页,双向链表永远是顺序尾部增长的,不会有中间的节点发生分裂的情况。

最糟糕的情况下,主键ID是随机无序生成的(例如java中一个UUID字符串),这种情况下,新插入的记录会随机分配到任何一个数据页,如果该页已满,就会触发页分裂。

如果主键ID由标准版雪花算法生成,最好的情况下,是每个时间戳内只有一个节点在生成ID,这时候算法的效果等同于理想情况的顺序递增,即跟auto_increment无差。最坏的情况下,是每个时间戳内所有节点都在生成ID,这时候算法的效果接近于无序(但仍比UUID的完全无序要好得多,因为workerId只有10位决定了最多只有1024个节点)。实际生产中,算法的效果取决于业务流量,并发度越低,算法越接近理想情况。

那么,换成新版算法又会如何呢?
新版算法从全局角度来看,ID是无序的,但对于每一个workerId,它生成的ID都是严格单调递增的,又因为workerId是有限的,所以最多可划分出1024个子序列,每个子序列都是单调递增的。
对于数据库而言,也许它初期接收的ID都是无序的,来自各个子序列的ID都混在一起,就像这样:
在这里插入图片描述

如果这时候来了个worker1-seq2,显然会造成页分裂:
在这里插入图片描述

但分裂之后,有趣的事情发生了,对于worker1而言,后续的seq3,seq4不会再造成页分裂(因为还装得下),seq5也只需要像顺序增长那样新建页进行链接(区别是这个新页不是在双向链表的尾部)。注意,worker1的后续ID,不会排到worker2及之后的任意节点(因而不会造成后边节点的页分裂),因为它们总比worker2的ID小;也不会排到worker1当前节点的前边(因而不会造成前边节点的页分裂),因为worker1的子序列总是单调递增的。在这里,我们称worker1这样的子序列达到了稳态,意为这条子序列已经"稳定"了,它的后续增长只会出现在子序列的尾部,而不会造成其它节点的页分裂。

同样的事情,可以推广到各个子序列上。无论前期数据库接收到的ID有多乱,经过有限次的页分裂后,双向链表总能达到这样一个稳定的终态:
在这里插入图片描述

到达终态后,后续的ID只会在该ID所属的子序列上进行顺序增长,而不会造成页分裂。该状态下的顺序增长与auto_increment的顺序增长的区别是,前者有1024个增长位点(各个子序列的尾部),后者只有尾部一个。

到这里,我们可以回答开头所提出的问题了:新算法从全局来看的确不是全局递增的,但该算法是收敛的,达到稳态后,新算法同样能达成像全局顺序递增一样的效果。


扩展思考

以上只提到了序列不停增长的情况,而实践生产中,不光有新数据的插入,也有旧数据的删除。而数据的删除有可能会导致页合并(innodb若发现相邻2个数据页的空间利用率都不到50%,就会把它俩合并),这对新算法的影响如何呢?

经过上面的流程,我们可以发现,新算法的本质是利用前期的页分裂,把不同的子序列逐渐分离开来,让算法不断收敛到稳态。而页合并则恰好相反,它有可能会把不同的子序列又合并回同一个数据页里,妨碍算法的收敛。尤其是在收敛的前期,频繁的页合并甚至可以让算法永远无法收敛(你刚分离出来我就又把它们合并回去,一夜回到解放前~)!但在收敛之后,只有在各个子序列的尾节点进行的页合并,才有可能破坏稳态(一个子序列的尾节点和下一个子序列的头节点进行合并)。而在子序列其余节点上的页合并,不影响稳态,因为子序列仍然是有序的,只不过长度变短了而已。

以seata的服务端为例,服务端那3张表的数据的生命周期都是比较短的,一个全局事务结束之后,它们就会被清除了,这对于新算法是不友好的,没有给时间它进行收敛。不过已经有延迟删除的PR在review中,搭配这个PR,效果会好很多。比如定期每周清理一次,前期就有足够的时间给算法进行收敛,其余的大部分时间,数据库就能从中受益了。到期清理时,最坏的结果也不过是表被清空,算法从头再来。

如果您希望把新算法应用到业务系统当中,请务必确保算法有时间进行收敛。比如用户表之类的,数据本就打算长期保存的,算法可以自然收敛。或者也做了延迟删除的机制,给算法足够的时间进行收敛。

如果您有更好的意见和建议,也欢迎跟seata社区联系!

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

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

相关文章

Hive优化以及相关参数设置

1.表层面设计优化 1.1 表分区 分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要…

Apache Seata基于改良版雪花算法的分布式UUID生成器分析1

title: Seata基于改良版雪花算法的分布式UUID生成器分析 author: selfishlover keywords: [Seata, snowflake, UUID] date: 2021/05/08 本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 Seata基于改良版雪花算法的分布式UUID生成器分析…

10.JAVAEE之网络编程

1.网络编程 通过网络,让两个主机之间能够进行通信 >基于这样的通信来完成一定的功能进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程(API 可以认为是 应用层 和 传输层 之间交互的路径)(API:Socket API相当…

NDK 基础(一)—— C 语言知识汇总

本系列文章主要是介绍一些 NDK 开发所需的基础知识,目录如下: NDK 基础(一)—— C 语言知识汇总 NDK 基础(二)—— C 语言基础与特性1 NDK 基础(三)—— C 语言基础与特性2 NDK 基础…

比较美观即将跳转html源码

源码介绍 比较美观即将跳转html源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面 源码截图 比较美观的一个跳转界面,修改方法如上&…

FreeRTOS-系统时钟节拍和时间管理

一、前言 任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时,超时等与时间相关的事件。时钟节拍是特定的周期性中断, 这个中断可以看做是系统心跳。 中断之间的时间间隔取决于不同的应用,一般是 1ms – 100ms。时钟的节拍…

【C++ —— 多态】

C —— 多态 多态的概念多态的定义和实现多态的构成条件虚函数虚函数的重写虚函数重写的两个例外协变:析构函数的重写 C11 override和final重载、覆盖(重写)、隐藏(重定义)的对比 抽象类概念接口继承和实现继承 多态的继承虚函数表多态的原理动态绑定和静态绑定 单继…

BERT一个蛋白质-季军-英特尔创新大师杯冷冻电镜蛋白质结构建模大赛-paipai

关联比赛: “创新大师杯”冷冻电镜蛋白质结构建模大赛 解决方案 团队介绍 paipai队、取自 PAIN AI,核心成员如我本人IvanaXu(IvanaXu GitHub),从事于金融科技业,面向银行信用贷款的风控、运营场景。但我们团队先后打过很多比赛&#xf…

算法系列--BFS解决拓扑排序

💕"请努力活下去"💕 作者:Lvzi 文章主要内容:算法系列–算法系列–BFS解决拓扑排序 大家好,今天为大家带来的是算法系列--BFS解决拓扑排序 前言:什么是拓扑排序 拓扑排序–解决有顺序的排序问题(要做事情的先后顺序) …

docker各目录含义

目录含义builder构建docker镜像的工具或过程buildkit用于构建和打包容器镜像,官方构建引擎,支持多阶段构建、缓存管理、并行化构建和多平台构建等功能containerd负责容器生命周期管理,能起、停、重启,确保容器运行。负责镜管理&am…

Java设计模式 _结构型模式_组合模式

一、组合模式 1、组合模式 组合模式(Composite Pattern)是这一种结构型设计模式。又叫部分整体模式。组合模式依据树形结构来组合对象,用来表示部分以及整体层次关系。即:创建了一个包含自己对象组的类,该类提供了修改…

Idea报错:无法访问org.springframework.boot.SpringApplication

在开发项目时,常常会遇到这种问题,报错信息如下图所示 版本号与jdk版本号存在对应关系,61.0对应jdk17,52.0对应jdk8 所以是某个依赖的版本太高,降低该依赖的版本即可 具体步骤: ①修改pom.xml中spring b…

ASP.NET实验室预约系统的设计

摘 要 实验室预约系统的设计主要是基于B/S模型,在Windows系统下,运用ASP.NET平台和SQLServer2000数据库实现实验室预约功能。该设计主要实现了实验室的预约和管理功能。预约功能包括老师对实验室信息、实验项目和实验预约情况的查询以及对实验室的预约…

ubuntu系统搭建pytorch环境详细步骤【笔记】

实践设备:华硕FX-PRO(NVIDIA GeForce GTX 960M) 搭建PyTorch环境的详细步骤如下: 1.安装Ubuntu系统: 下载Ubuntu的镜像文件并制作启动盘。将启动盘插入计算机,启动计算机并按照提示安装Ubuntu系统。 2.…

Linux内核之原子操作:atomic_long_dec用法实例(六十七)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

一起Talk Android吧(第五百五十八回:lombok用法)

文章目录 1. 概述2. 使用方法3. 内容总结 各位看官们大家好,上一回中介绍了如何获取文件读写权限的知识,本章回中将介绍lombok相关的知识。闲话休提,言归正转,让我们一起Talk Android吧! 1. 概述 这是一个java库,用来…

ES全文检索支持拼音和繁简检索

ES全文检索支持拼音和繁简检索 1. 实现目标2. 引入pinyin插件2.1 编译 elasticsearch-analysis-pinyin 插件2.2 安装拼音插件 3. 引入ik分词器插件3.1 已有作者编译后的包文件3.2 只有源代码的版本3.3 安装ik分词插件 4. 建立es索引5.测试检索6. 繁简转换 1. 实现目标 ES检索时…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release,发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

Pandas入门篇(二)-------Dataframe篇4(进阶)(Dataframe的进阶用法)(机器学习前置技术栈)

目录 概述一、复合索引(一)创建具有复合索引的 DataFrame1. 使用 set_index 方法:2.在创建 DataFrame 时直接指定索引: (二)使用复合索引进行数据选择和切片(三)重置索引&#xff08…

rabbitMq 0 到1

前言 工作中MQ的使用场景是数不胜数,每个公司的技术选型又不太一样,用的哪个MQ,我们必须要先玩起来,RabbitMQ在windows安装遇到很多问题,博客也是五花八门,算了还是自己搞吧,记录一下&#xff…