分布式(6)

目录

26.雪花算法如何实现的?

27.雪花算法有什么问题?有哪些解决思路?

28.有哪些方案实现分布式锁?

29.基于数据库如何实现分布式锁?有什么缺陷?

30.基于Redis如何实现分布式锁?有什么缺陷?


26.雪花算法如何实现的?

Snowflake,雪花算法是由Twitter开源的分布式ID生成算法,以划分命名空间的方式将64位分隔成多个部分,每个部分代表不同的涵义。而Java中64位的整数是Long类型,所以在Java中SnowFlake算法生成的ID就是Long来存储的。

第1位占用1bit,其值始终是0,可看做事符号位不使用。

第2位开始的41位是时间戳,41bit位可表示2^41个数,每个数代表毫秒,那么雪花算法可用的时间年限是69年的时间。

中间的10bit位可以表示机器数,即2^10=1024台机器,但是一般情况下我们不会部署这么多台机器。如果我们对IDC(互联网数据中心)有需求,还可以将10bit分5bit给IDC,分5bit给工作机器。这样子就可以表示32个IDC,每个IDC下可以有32台机器,具体的划分可以根据自身需求定义。

最后12bit位是自增序列,可表示2^1=4096个数。

这样的划分之后相当于在一毫秒一个数据中心的一台机器上课产生4096个有序的不重复的ID。但是我们IDC和机器数肯定不止一个,所以毫秒内能生成的有序ID数是翻倍的。

27.雪花算法有什么问题?有哪些解决思路?

有哪些问题?

时钟回拨问题;

趋势递增,而不是绝对递增;

不能在一台服务器上部署多个分布式ID服务;

如何解决时钟回拨?

以百度的UidGenerator为例,CachedUidGenerator方式主要采取如下一些措施和方案规避了时钟回拨问题和增强唯一性:

自增列:UidGenerator的workerId在实例每次重启时初始化,且就是数据库的自增ID,从而完美的实现每个实例获取到的workId不会有任何冲突。

RingBuffer:UidGenerator不再在每次取ID时都实时计算分布式ID,而是利用RingBuffer数据结构预先生成若干个分布式ID并保存。

时间递增:传统的雪花算法实现都是通过System.currentTimeMills()来获取时间并与上一次时间进行比较,这样的实现严重依赖服务器的时间。而UidGenerator的时间类型是AtomicLong,且通过incrementAndGet()方法获取下一次的时间,从而脱离了对服务器时间的依赖,也就不会有时钟回拨问题

(这种做法也有一个小问题,即分布式ID中的时间信息可能并不是这个ID真正产生的时间点,例如:获取的某分布式ID的值为3200169789968523265,他的反解析结果为{"timestamp":"2019 05 02 23:26:39";"workId":"21";"sequenece":"1"},但是这个ID可能并不是在“2019 05 02 23:26:39:这个时间产生的)。

28.有哪些方案实现分布式锁?

使用场景

需要保证一个方法在同一时间内只能被同一个线程执行

实现方式:

加锁和解锁

方案,考虑因素(性能,稳定,实现难度,死锁)

基于数据库做分布式锁   乐观锁(基于版本号)和悲观锁(基于排他锁)

基于Redis做分布式锁:setnx(key,当前时间+过期时间)和redlock机制;

基于zookeeper做分布式锁:临时有序节点来实现的分布式锁,Curator

基于Consul做分布式锁

29.基于数据库如何实现分布式锁?有什么缺陷?

基于数据库表(锁表,很少使用)

最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。当我们想要获得锁的时候,就可以在该表中增加一条记录,想要释放锁的时候就删除这条记录。为了更好的延时,我们先创建一张数据库表,参考如下:

当我们想要获得锁时,可以插入一条数据:

当需要释放锁时,可以删除这条数据:

基于悲观锁

悲观锁实现思路?

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive  locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能等待或者抛出异常。具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或者加排他锁的操作,就会等待我们解锁或者直接抛出异常。

以MySQL  InnoDB中使用悲观锁为例?

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交,set   autocommit=0;

上面的查询语句中,我们使用了select  ...  for  update的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在t  goods表中,id为1的那条数据被我们锁定了,其他的事务必须等本次事务提交后才能执行。这样我们就可以保证当前的数据不会被其他事务修改。

上面我们提到,使用select ... for  update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL  Innodb默认行级锁。行级锁是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。

基于乐观锁

乐观并发控制(又名:乐观锁,缩写OCC)是一种并发控制的方法。他假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务辉县检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。

以使用版本号实现乐观锁为例?

使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

需要注意的是,乐观锁机制往往基于系统中数据存储逻辑,因此也具备一定的局限性。由于乐观锁机制是在我们的系统中实现的,对于来自外部系统的用户数据更新操作不受我们系统控制,因此可能会造成脏数据被更新到数据库中。在系统设计阶段,我们应该宠妃考虑到这些情况,并进行相应的调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。

缺陷

对数据库依赖,开销问题,行锁变表锁问题,无法解决数据库单点和可重入的问题。

30.基于Redis如何实现分布式锁?有什么缺陷?

最基本的Jedis方案

加锁:  set  NX PX+重试+重试间隔

向Redis发起如下命令:SET   productid:lock  0xx9p03001  NX  PX  30000其中,”productId"由自己定义,可以是与本次业务有关的Id,"0xx9p03001"是一串随机值,必须保证全局唯一(原因在后文中会提到),“NX“指的是当且仅当key(也就是案例中的”productid:lock")在Redis中不存在时,返回执行成功,否则执行失败。“PX 30000”指的是在30秒后,key被自动删除。执行命令后返回成功,表名服务成功的获得了锁。

解锁:采用lua脚本:在删除Key之前,一定要判断服务A持有的Value与Redis内存储的Value是否一致。如果贸然使用服务A持有的key来删除锁,则会误将服务B的锁释放掉。

基于RedLock实现分布式锁

假设有两个服务A,B都希望获得锁,有一个包含了5个Redis Master的Redis Cluster,执行过程大致如下:

客户端获取当前时间戳,单位:毫秒

服务A轮询每个Master节点,尝试创建锁。(这里锁的过期时间比较短,一般就几十毫秒)RedLock算法会尝试在大多数节点上分别创建锁,假如节点总数为n,那么大多数节点指的是n/2+1。

客户端计算陈工建立完锁的时间,如果建锁时间小于超时时间,就可以判定锁创建成功。如果锁创建失败,则依次(遍历master节点)删除锁。

只要有其他服务创建过分布式锁,那么当前服务就必须轮询尝试获取锁。

基于Redisson实现分布式锁?

过程?

线程去获取锁,获得成功:执行lua脚本,保存数据到redis数据库。

线程去获取锁,获取失败:订阅了解锁消息,然后再尝试获取锁,获取成功后,执行Lua脚本,保存数据到redis数据库。

互斥?

如果这个时候客户端B来尝试加锁,执行了同样的一段Lua脚本。第一个if判断会执行“exists   myLock”,发现myLock这个锁key已经存在。接着第二个If判断,判断myLock锁key的hash数据结构中,是否包含客户端B的ID,但明显没有,那么客户端B会获取到pttl  myLock返回的一个数字,代表MyLock这个锁key的剩余生存时间。此时客户端B会进入一个while循环,不听的尝试加锁。

watch  dog 自动延时机制?

客户端A加锁的锁key默认生存时间只有30秒,如果超过了30秒,客户端A还想一直持有这把锁,怎么办?其实只要客户端A一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端A还持有锁Key,那么就会不断的延长锁key的生存时间。

可重入?

每次lock会调用incrby,每次unlock会减一。

方案比较

1.借助Redis实现分布式锁时,有一个共同的缺陷:当获取锁被拒绝后,需要不断地循环,重新发送获取锁(创建key)的请求,直到请求成功。这就造成空转,良妃宝贵的CPU资源。

2.RedLock算法本身有争议,并不能保证健壮性。

3.Redisson实现分布式锁时,除了将key新增到某个指定的Master节点外,还需要由master自动异步的将key和Value等数据同步至绑定的slave节点上。那么问题来了,如果master没来得及同步数据,突然发生宕机,那么通过故障转移和主备切换,slave节点被迅速升级为Master节点,新的客户端加锁成功,旧的客户端的watch dog发现key存在,误以为旧客户端仍然持有这把锁,这就导致同时存在多个客户端持有同名锁的问题了。

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

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

相关文章

GitHub Copilot 最佳免费平替:阿里通义灵码

之前分享了不少关于 GitHub Copilot 的文章,不少粉丝都评论让我试试阿里的通义灵码,这让我对通义灵码有了不少的兴趣。 今天,阿七就带大家了解一下阿里的通义灵码,我们按照之前 GitHub Copilot 的顺序分享通义灵码在相同场景下的…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -小程序首页实现

锋哥原创的uniapp微信小程序投票系统实战: uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

[蓝桥杯学习] 树状树组

lowbit操作 数字二进制表达中的最低位1以及后面所有的0,函数写法如下: int lowbit(int x){return x&-x;} 例如说,lowbit(0101100100) (100) lowbit(4) 4 lowbit(6) 2 时间复杂度o(1) 树状数组 应用 进行单点修改和区间查询…

本地计算机 上的 My5OL808 服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止

客户反馈说mysql启动不了,报错信息: 本地计算机 上的 My5OL808 服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止。 查了不少资料,最后分析问题是这样的,手动或者重复安装mysql时,创建了多个…

tp8/6 插件PhpOffice\PhpSpreadsheet导入表格

一、安装 composer require phpoffice/phpspreadsheet 官网&#xff1a;phpoffice/phpspreadsheet - Packagist 二、代码 <?php namespace app\services\upload\model; use app\services\BaseServices; use \PhpOffice\PhpSpreadsheet\Spreadsheet; use \PhpOffice\Php…

iOS苹果和Android安卓测试APP应用程序的区别差异

在移动应用开发中&#xff0c;测试是一个至关重要的环节。无论是iOS苹果还是Android安卓&#xff0c;测试APP应用程序都需要注意一些差异和细节。本文将详细介绍iOS和Android的测试差异&#xff0c;包括操作系统版本、设备适配、测试工具和测试策略&#xff0c;并回答一些新手容…

面部识别技术的突破:IP-Adapter-FaceID实现上传照片秒变多面人生

IP-Adapter-FaceID通过上传个人照片&#xff0c;仅需几分钟即可克隆一个高度真实的个性化面部图像。IP-Adapter-FaceID的独特之处在于&#xff0c;它不仅捕捉到个体的基本外貌特征&#xff0c;更深入地嵌入了面部识别模型的面部ID&#xff0c;使生成的图像在细节上更为准确和逼…

认识SpringBoot项目中的Starter

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

[C#]yolov8-onnx在winform部署手势识别模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 YOLOv8 是一个 SOTA 模型&#xff0c;它建立在以前 YOLO 版本的成功基础上&#xff0c;并引入了新的功能和改进&#xff0c;以进一步提升性能和灵活性。具体创新包括一个新的骨干网络、一个新…

OpenCV图像处理——C++实现亚像素尺寸标定板边缘轮廓提取

前言 标定模板&#xff08;Calibration Target&#xff09;在机器视觉、图像测量、摄影测量以及三维重建等应用中起着重要的作用。它被用于校正相机的畸变&#xff0c;确定物理尺寸和像素之间的换算关系&#xff0c;并建立相机成像的几何模型。通过使用相机拍摄带有固定间距图…

商智C店H5性能优化实战

前言 商智C店&#xff0c;是依托移动低码能力搭建的一个应用&#xff0c;产品面向B端商家。随着应用体量持续增大&#xff0c;考虑产品定位及用户体验&#xff0c;我们针对性能较差页面做了一次优化&#xff0c;并取得了不错的效果&#xff0c;用户体验值&#xff08;UEI&…

五步解决Ubuntu界面太小的问题

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 对于20版本及以上的unbuntu我们可以通过安装open-vm-tools来解决界面大小的问题&#xff0c;具体步骤如…

深度学习中的自动化标签转换:对数据集所有标签做映射转换

在机器学习中&#xff0c;特别是在涉及图像识别或分类的项目中&#xff0c;标签数据的组织和准确性至关重要。本文探讨了一个旨在高效转换标签数据的 Python 脚本。该脚本在需要更新或更改类标签的场景中特别有用&#xff0c;这是正在进行的机器学习项目中的常见任务。我们将逐…

差分电路原理以及为什么输出电压要偏移

我们在使用放大器芯片的时候&#xff0c;除了对放大器芯片本身应用外&#xff0c;通常还需要搭建一些外围电路来满足放大器芯片的使用条件&#xff0c;最终满足应用的功能&#xff0c;下面通过一个差分电路来熟悉这些应用。 差分运算放大电路&#xff0c;对共模信号得到有效抑…

Mac打包Unix可执行文件为pkg

Mac打包Unix可执行文件为pkg 方式一&#xff1a;通过packages页面打包 1.下载packages app Distribution&#xff1a;自定义化更高&#xff0c;包括修改安装页面的内容提示 我这里主要演示Distribution模式的项目&#xff1a;通过unix可执行文件postinstall.sh脚本实现通过ma…

关于java栈和堆

关于java栈和堆 在上一篇文章中我们了解了数组的声明和创建&#xff0c;本篇文章中我们了解一下声明数组&#xff0c;创建数组&#xff0c;给数组赋值以后&#xff0c;栈和堆都是怎么样子分配的&#xff0c;了解一下底层的逻辑知识&#xff0c;让大家可以更好的理解数组&#…

【Unity 实用工具篇】| 游戏多语言解决方案,官方插件Localization 实现本地化及多种语言切换

前言 【Unity 实用工具篇】| 游戏多语言解决方案&#xff0c;官方插件Localization 实现本地化及多种语言切换一、多语言本地化插件 Localization1.1 介绍1.2 效果展示1.3 使用说明 二、 插件导入并配置2.1 安装 Localization2.2 全局配置 三、多语言映射表3.1 创建多语言文本配…

el-form点击提交后把验证失败的数据传给了后端

问题&#xff1a;版本号需要根据后端返回的结果查看是否可用&#xff0c;在这里1.0.0是不可用的&#xff0c;如果点击其他地方则会报红&#xff0c;可是直接点击提交&#xff0c;则会把1.0.0这个错误的数据也提交给后端。 解决方案&#xff1a; html代码&#xff1a; <el…

C++上位软件通过LibModbus开源库和西门子S7-1200/S7-1500/S7-200 PLC进行ModbusTcp 和ModbusRTU 通信

前言 一直以来上位软件比如C等和西门子等其他品牌PLC之间的数据交换都是大家比较头疼的问题&#xff0c;尤其是C上位软件程序员。传统的方法一般有OPC、Socket 等&#xff0c;直到LibModbus 开源库出现后这种途径对程序袁来说又有了新的选择。 Modbus简介 Modbus特点 1 &#…

C# Attribute特性实战(1):Swtich判断优化

文章目录 前言简单Switch问题无参Swtich方法声明Swtich Attribute声明带有Swtich特性方法主方法结果 有参Switch修改代码修改运行过程运行结果 总结 前言 在经过前面两章内容的讲解&#xff0c;我们已经简单了解了如何使用特性和反射。我们这里解决一个简单的案例 C#高级语法 …