分布式(6)

news2025/2/27 22:58:01

目录

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.coloradmin.cn/o/1361561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二刷Laravel 教程(用户注册)总结Ⅳ

一、显示用户信息 1)resource Route::resource(users, UsersController); 相当于下面这7个路由 我们先用 Artisan 命令查看目前应用的路由: php artisan route:list 2) compact 方法 //我们将用户对象 $user 通过 compact 方法转化为一个关联…

thingsboard规则节点功能记录(自用)

本文是对【ThingsBoard源码级分析规则节点使用第一季】 https://www.bilibili.com/video/BV1CT411e7vt/?p4&share_sourcecopy_web&vd_source9a5ca7ed3cff97385fdab4b6188e485c 学习的一些记录,加深自己的理解,在此声明。 asset profile switch…

Zookeeper之Java客户端实战

ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。可供选择的Java客户端API有: ZooKeeper官方的Java客户端API。第三方的Java客户端API,比如Curator。 接下来我们将逐一学习一下这两个java客户端是如何操作zookeeper的。 1. ZooKe…

redis复习笔记03(小滴课堂)

Redis6常见数据结构概览 0代表存在,1代表不存在。 1表示删除成功,0表示失败。 查看类型,默认string类型。 也可以设置set类型。 list类型。 查看key的过期时间: Redis6数据结构之String类型介绍和应用场景 批量设置: …

studio3T mongodb 根据查询条件更新字段 或 删除数据

1. mongodb 等于、不等于$ne、不包含 $nin 以及批量更新数据的使用。 业务场景: 在集合中,根据查询条件,更新数据状态。 实现代码: 1. 部门名称为XXX、状态不等于“完好”的、并且不包含这些编码的数据先查询出来2. 再把状态更…

GUI设计基础

层次结构 要学GUI,大概先知道它的层次结构,如下图所示,我们要设计的就是下面这个几个东西。 菜单uimenu 建立一级菜单项的函数调用格式: hmuimenu(h_parent,PropertyNamel,valuel,propertyName2,value2,...); hm 是…

ssm基于Java Web的怀旧唱片售卖系统论文

摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装怀旧唱片售卖系统软件来发挥其高效地信息处理的作用&#x…

UICollection Compositional Layout全详解

本文字数:8325字 预计阅读时间:45分钟 01 Collection View Layout全详解 UICollectionView在iOS中是构建复杂布局的强大工具。iOS13中引入的 UICollectionViewCompositionalLayout为创建自定义布局提供了全新的可能性。本文将深入探讨Compositional Lay…

SSH 密钥身份验证和管理

安全外壳协议(Security Shell Protocol)是一种应用于计算机网络的安全通信协议,其提供的服务可用于保护网络上的连接和数据传输安全性,其核心思想是为网络上的两台计算机之间搭建一个安全的外壳,以保护数据传输的安全性…

场景识别与词袋模型

目录 1. 任务要求2. 数据集3. 实现算法3.1 目标实现3.2 Tiny images representation3.3 SIFT特征词袋表示3.4 相关算法 4. 实验结果4.1 基础结果展示4.2 算法超参的影响4.2.1 Tiny images size4.2.2 Vocabulary size 4.3 其他结果 5. 源代码 1. 任务要求 输入:给定…

抖音字幕视频怎么做能滚动 抖音个性字幕怎么做 抖音短视频用什么软件剪辑

不管是抖音短视频,还是其他影视网站的影视剧,字幕基本都是必不可少的,字幕本身就能加强观众对视频的理解,而且像一些滚动字幕,会更加吸引观众的注意力,那抖音字幕视频怎么做能滚动?抖音个性字幕…

Yokowaga横河WT3000高精度功率分析仪

Yokogawa WT3000高精度功率分析仪,作为理想的测量解决方案,其精准度和卓越的性能使其在多 种应用场景中都表现出色。这款仪表是工程研发和产品效率测试的理想选择,尤其在变频器、电机 驱动器、照明系统和电子镇流器、UPS系统、飞机电力系统、…

2023版本QT学习记录 -11- 多线程的使用(QT的方式)

———————多线程的使用(QT方式)——————— 🎄效果演示 两个线程都输出一些调试信息 🎄创建多线程的流程 🎄头文件 #include "qthread.h"🎄利用多态重写任务函数 class rlthread1 : public QThread {Q_OBJE…

Erupt即开即用的后台管理系统【告别前端代码】

一、引子 【零前端代码,几行Java注解,搞定后台管理系统】 如果只是自己内部公司使用的话,大多数功能都可以满足,剩下的就是自己添砖加瓦了。 我用这个主要是简单快捷,10分钟搭建一个简易的后台管理系统。 二、基本…

设计模式之外观模式【结构型模式】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某…

MYSQL多种提权方式

🐙MYSQL-提权条件 - 数据库的最高权限用户的密码 - secure-file-priv没进行目录限制 - 拿下了网站的权限(通过webshell或者其他方式) - 获取到了数据库的账号密码 (获取密码:D:/phpstudy/MySQL/data/mysql/user.MYD…

【论文阅读笔记】Mip-NeRF 360: Unbounded Anti-Aliased Neural Radiance Fields

目录 概述摘要引言参数化效率歧义性 mip-NeRF场景和光线参数化从粗到细的在线蒸馏基于区间的模型的正则化实现细节实验限制总结:附录退火膨胀采样背景颜色 paper:https://arxiv.org/abs/2111.12077 code:https://github.com/google-research/…

实战经验分享,Python 连接 Oracle 踩坑实录

最近的一个测试任务需要测试 oracle 同步 hive 数据库的性能,那就需要对 oracle 数据库灌注测试数据。我就又打开了我的IDE,准备把我之前一下可以灌50w数据到 MySQL 的代码,改一改,直接用。 因为我在网上看到,语法上也…

PHP 基础编程 1

文章目录 前后端交互尝试php简介php版本php 基础语法php的变量前后端交互 - 计算器体验php数据类型php的常量和变量的区别php的运算符算数运算符自增自减比较运算符赋值运算符逻辑运算 php的控制结构ifelseelse if 前后端交互尝试 前端编程语言:JS (Java…

Linux驱动开发(1)-最简单的字符设备驱动开发例子

1.简介 字符设备驱动:按照字节流进行读写操作的设备,例如点灯、按键、IIC、SPI、LCD。 Linux系统中一切皆文件,驱动加载成功,就会在/dev目录生成文件,对文件操作,则可实现对硬件操作。应用程序运行在用户…