分布式(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.mfbz.cn/a/297301.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LIDAR激光雷达反射板

LIDAR(Light Detection And Ranging)系统是一种集激光、全球定位系统(GPS)和惯性导航系统(INS)三种技术于一身的系统,用于获得点云数据并生成精确的数字化三维模型。 LIDAR系统包括一个单束窄带…

Pycharm打包程序为exe文件

Pycharm打包程序为exe文件 【一】导入模块pyinstaller 【1】图片说明 【2】文字说明 根据图片顺序执行 首先点击file进入settings界面,在setting界面找到Project下面的Python Interpretor,点击号进行模块的添加在搜索框中输入pyinstaller,…

【Proteus仿真】【Arduino单片机】水箱液位监控系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器,使用LCD1602液晶、按键、蜂鸣器、液位传感器、ADC转换器、水泵等。 主要功能: 系统运行后,LCD1602显示当前水位、上下限阈…

正交投影矩阵与透视投影矩阵的推导

正交投影矩阵 正交投影矩阵的视锥体是一个长方体 [ l , r ] [ b , t ] [ f , n ] [l,r][b,t][f,n] [l,r][b,t][f,n],我们要把这个长方体转换到一个正方体 [ − 1 , 1 ] [ − 1 , 1 ] [ − 1 , 1 ] [-1,1][-1,1][-1,1] [−1,1][−1,1][−1,1]中,如下图所…

【KD】知识蒸馏(knowledge distillation)简单介绍

最近学到了知识蒸馏的相关知识,来简单总结一下૮꒰ ˶• ༝ •˶꒱ა。 知识蒸馏 知识蒸馏,是一种模型压缩的手段。通过训练学生模仿教师的行为,将嵌入在大的教师模型中的知识迁移到小的学生模型。 例如,TinyBERT(Jiao et al.,2…

C++结合OpenCV:图像的基本表示方法

1.二值图像 二值图像是指仅仅包含黑色和白色两种颜色的图像。在计算机中,通过一个栅格状排列的数据集(矩阵)来表示和处理图像。例如,图1是一个字母A的图像,计算机在处理该图像时,会首先将其划分为一个个的小…

Mysql show Profiles详解

1.简介 show profile 和 show profiles 命令用于展示SQL语句的资源使用情况,包括CPU的使用,CPU上下文切换,IO等待,内存使用等,这个命令对于分析某个SQL的性能瓶颈非常有帮助,借助于show profile的输出信息&…

jenkins+selenium+python实现web自动化测试

jenkinsselenium可以做到对web自动化的持续集成。 Jenkins的基本操作: 一、新建视图及job 新建视图: 新建job: 可以选择构建一个自由风格的软件项目或者复制已有的item 二、准备工作: 安装Jenkins插件,SSH plugin …

快速入门Visual Studio 2022开发.Net Framework研发环境指南

IDE工具 Visual Studio 2022 Vs2022企业版 - VisualStudioSetup.exe Visual Studio Code VSCodeUserSetup-x64-1.66.2.exeVSCodeUserSetup-x64-1.67.0-insider.exe IDE环境 编程字体YaHei.Consolas YaHei.Consolas.1.12.ttf IDE插件 Visual Studio Code常用插件 Chinese…

分布式锁3: zk实现分布式锁4 使用临时顺序节点+watch监听+可重入(threadLocal)

一 zk实现分布式锁的可重入性 1.1 使用ThreadLocal属性 引入ThreadLocal线程局部变量保证zk分布式锁的可重入性。 1.2 关键代码说明 1.3 代码 1.3.1 初始化客户端 1.3.2 分布式锁代码 package com.atguigu.distributed.lock.config;import com.baomidou.mybatisplus.core…

Java:Lambda表达式、方法引用

文章目录 1、Lambda表达式1.1 Lambda表达式体验1.2 Lambda表达式的省略形式1.3 Lambda表达式练习 2、方法引用体验3、方法引用符4、引用静态方法5、引用对象的实例方法6、引用类的实例方法7、引用构造方法8、引用数组的构造方法9、方法引用练习9.1 练习19.2 练习29.3 练习3 10、…

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

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

函数——系统函数2(c++)

这次主要就只有一个系统函数: (注:a为变量名) 名称 用法 用处 sqrt sqrt(a) 算出变量a的平方根 (注:使用sqrt函数时,需要用到头文件 #i…

leetcode算法题之递归--综合练习(一)

此专题对我们之前所学的关于递归的内容进行一个整合,大家可以自行练习,提升自己的编码能力。 本章目录 1.找出所有子集的异或总和在求和2.全排列II3.电话号码的字母组合4.括号生成5.组合6.目标和7.组合总和8.字母大小写全排列9.优美的排列 1.找出所有子…

Python自动点击器

一、如何制作一个Python自动点击器? 当用户单击开始键时,代码将从键盘获取输入,并在用户单击退出键时终止自动点击器,自动点击器开始单击指针放置在屏幕上的任何位置。我们将在这里使用pynput模块。 二、什么是自动点击器&#…

FineBI实战(1):mysql实战案例简介

下面我通过案例来介绍FineBI的使用。 1 业务背景介绍 本案例围绕某个互联网小型电商的订单业务来开发。某电商公司,每天都有一些的用户会在线上采购商品,该电商公司想通过数据分析,查看每一天的电商经营情况。例如:电商公司的运…

并发(2)

目录 6.通常线程有哪几种使用方式? 7.基础线程机制有哪些? 8.线程的中断方式有哪些? 9.线程的互斥同步方式有哪些?如何比较和选择? 10.Synchronized可以作用在哪里? 6.通常线程有哪几种使用方式&#x…

Python基础知识总结3-面向对象进阶知识

面向对象三大特征介绍 继承子类扩展父类语法格式关于构造函数:类成员的继承和重写查看类的继承层次结构 object根类dir() 查看对象属性重写 __str__() 方法 多重继承MRO方法解析顺序super()获得父类定义多态特殊方法和运算符重载特殊属性 对象的浅拷贝和深拷贝组合_…

【提示学习论文五】Conditional Prompt Learning for Vision-Language Models论文原理及复现工作

Conditional Prompt Learning for Vision-Language Models 视觉语言模型的条件提示学习 文章介绍 这篇文章于2022年发表在CVPR(Conference on Computer Vision and Pattern Recognition),作者是kaiyang.zhou, jingkang001, ccloy, ziwei.li…

PostgreSQL的常见错误和解决方法

转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 在学习新的东西时,会犯很多的错误,会遇到很多坑。我们在填坑与犯错中不断进步成长。 以下是在学习pgsql中…
最新文章