分布式知识整理

分布式锁

以商场系统超卖现象举例

 超卖现象一

现象:

商品卖出数量超出了库存数量。

产生原因:

扣减库存的动作在程序中进行,在程序中计算剩余库存,在并发场景下,导致库存计算错误。

代码复现

es.shutdown();

cyclicBarrier  作用是确保多个线程同时扣减库存。

countDownLatch  确保执行完之前,线程池不关闭

解决方法

注意,库存做个大于0的判断

超卖现象二

现象

系统中库存变为负数
 

产生原因

1  并发检验库存,造成库存充足的假象

2  update更新库存,导致库存为负数

1  检索商品库存,如果商品库存为负数,抛出异常,则更新操作回滚

2 加锁

单体加锁

synchronized 关键字

当使用 synchronized 关键字时,可以分别应用于实例方法、静态方法和代码块,以确保线程安全。以下是分别对这三种情况的加锁示例:

1. 实例方法加锁示例:

public class SynchronizedExample {private int count = 0;public synchronized void increment() {count++;}
}

在上面的示例中,increment 方法使用 synchronized 关键字修饰,因此在每次调用该方法时,会对当前对象进行加锁,确保同一时刻只有一个线程可以执行 increment 方法。

2. 静态方法加锁示例:

public class SynchronizedExample {private static int count = 0;public static synchronized void increment() {count++;}
}

在这个示例中,increment 方法被声明为静态方法并使用了 synchronized 关键字修饰。这会导致对类的 Class 对象进行加锁,确保同一时刻只有一个线程可以执行这个静态方法。

3. 代码块加锁示例:

public class SynchronizedExample {private static final Object lock = new Object();private int count = 0;public void increment() {synchronized (lock) {count++;}}
}

在这个示例中,使用了一个私有的静态对象 lock 作为锁,并在 increment 方法中使用 synchronized 块来对一段代码进行加锁,确保同一时刻只有一个线程可以执行这段代码块。

以上这些示例展示了 synchronized 关键字在不同场景下的应用,可以确保线程安全,并避免出现并发访问问题。

ReentrantLock

当需要更灵活地控制加锁和解锁的时候,ReentrantLock 是一种好的选择。下面是一个使用 ReentrantLock 加锁的示例:

import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private int count = 0;private ReentrantLock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}
}

在上面的示例中,首先创建了一个 ReentrantLock 对象,然后在 increment 方法中使用 lock() 来获取锁,在操作完成后使用 unlock() 来释放锁。这样可以确保在加锁的过程中发生异常时,锁仍然能够被正确释放,避免出现死锁的情况。

ReentrantLock 还提供了更多的灵活性,如可以实现公平锁和非公平锁、可以中断等待锁的线程等功能,更适用于复杂的并发控制场景。

单体加锁的局限性

上述示例中单体加锁的两种方式(synchronized 关键字和 ReentrantLock)虽然可以在某些情况下提供线程安全性,但也存在一些局限性,这些局限性包括:

1. 互斥性:单体加锁是一种悲观锁机制,当一个线程持有锁执行临界区代码时,其他线程必须等待释放锁才能执行。这可能导致性能问题,特别是在并发度较高的情况下。

2. 潜在的死锁风险:如果在加锁的过程中发生异常或逻辑错误,可能导致锁没有被正确释放,从而引发死锁问题。

3. 缺乏灵活性:synchronized 关键字和 ReentrantLock 的加锁范围仅限于方法或代码块内部,这可能限制了并发控制的粒度和灵活性。有些复杂的并发控制场景可能需要更细粒度的加锁或释放锁的控制,此时单体加锁机制可能无法满足要求。

5. 无法跨节点同步:单体加锁是基于进程内的锁机制,无法在分布式环境中实现跨节点的同步。在多个节点之间无法保证互斥性,并且无法实现全局的锁机制。

6. 性能瓶颈:在分布式环境中,如果使用单体加锁来保护共享资源,会导致性能瓶颈。由于加锁的范围扩大到整个服务实例或整个代码块,会造成并发度的降低,影响整体的吞吐量和性能。

7. 高开销和复杂性:由于需要维护全局一致的状态,单体加锁需要进行大量的网络通信和同步操作,增加了额外的开销和复杂性。

为了解决这些问题,分布式环境中常用的并发控制机制是分布式锁。分布式锁是一种基于分布式协议和算法实现的锁机制,可以在分布式环境中保证互斥性和一致性。常见的分布式锁实现包括基于数据库的锁、基于缓存的锁(如 Redis 锁),以及基于 ZooKeeper 等分布式协调服务的锁。

使用分布式锁可以解决分布式环境中跨节点同步和锁竞争的问题,提高性能和可伸缩性。但是需要注意,分布式锁也可能引入其他问题,如死锁、性能瓶颈等。因此,在设计和使用分布式锁时需要谨慎考虑,并综合考虑系统的一致性、性能和可伸缩性需求。

常见分布式锁

当在分布式系统中实现分布式锁时,可以使用不同的技术作为后端存储和同步机制,常见的包括 Redis、数据库和 ZooKeeper。下面我们将分别讨论它们作为分布式锁的原理、优缺点等。

当在分布式系统中实现分布式锁时,可以使用不同的技术作为后端存储和同步机制,常见的包括 Redis、数据库和 ZooKeeper。下面我们将分别讨论它们作为分布式锁的原理、优缺点等。

 Redis 分布式锁

原理:


- 使用 Redis 作为后端存储,基于 Redis 的 SETNX(set if not exists)命令来实现分布式锁。当某个客户端成功获取锁时,会在 Redis 中创建一个对应的锁键,并设置合适的超时时间,其他客户端获取不到锁。

优点:


- **高性能:** Redis 是内存数据库,读写性能出色,适合作为分布式锁的后端存储。


- **支持阻塞和非阻塞式获取锁:** Redis 提供了支持阻塞以及非阻塞式的锁获取方式(通过 BLPOP 或者 SETNX 结合 EXPIRE 命令)。


- **支持可重入:** 可以通过为每个锁键加上唯一标识,实现可重入性。

缺点:


- **单点故障:** Redis 单节点故障时可能导致锁不可用,需要通过 Redis Sentinel 或 Redis Cluster 等方式解决高可用性问题。
- **并发数受限:** Redis 作为单机或者主从部署模式下,可能受限于单机的并发连接数。

数据库分布式锁

原理:


- 使用关系型数据库的乐观锁或者悲观锁来实现分布式锁,可以利用数据库的事务和唯一索引来保证原子性和唯一性。

优点:


- **成熟稳定:** 数据库作为企业级数据存储系统,具有成熟的高可用、一致性和持久性解决方案。
- **适用性广:** 已有的数据库系统可以直接用于存储锁信息,无需引入新的中间件。

缺点:


- **性能:** 与 Redis 相比,数据库的读写性能通常较差,可能影响锁的获取和释放性能。
- **数据库连接资源消耗:** 大量并发获取锁可能导致数据库连接池耗尽。
- **死锁风险:** 数据库锁对于跨事务并发控制必须慎重处理,避免出现死锁。

当使用 ZooKeeper 作为分布式系统中的分布式锁时,通常会利用 ZooKeeper 的顺序节点(Sequential ZNode)和 Watches 机制来实现分布式锁。下面是详细的介绍以及和 Redis 的对比:

ZooKeeper

工作原理

1. 创建锁节点: 客户端在尝试获取锁时,在 ZooKeeper 上创建一个临时的、有序的顺序节点,代表自己的锁请求。

2. 获取锁: 客户端检查自己创建的节点是否是当前序列中最小的节点,如果是,则表示获得了锁;如果不是,则注册前一个节点的 Watcher 监听,然后进入等待状态。

3. 释放锁:*当客户端不再需要锁时,直接删除自己创建的节点,其他等待的客户端会通过监听到节点删除事件来尝试获取锁。

优点

- 高可用性:*ZooKeeper 提供了高可用的分布式协调服务,适合作为分布式锁的后端存储,具有良好的稳定性和一致性。
- 顺序性:*ZooKeeper 的顺序节点可以使客户端获取锁的顺序有序,并且通过 Watches 机制实现高效的事件通知,避免了轮询导致的资源浪费。

缺点

- 复杂性:*使用 ZooKeeper 需要额外的运维成本和学习成本,部署和维护相对复杂。
- 性能: ZooKeeper 的性能可能不如 Redis 那样出色,尤其在高并发场景下可能受到影响。

 ZooKeeper 和 Redis 分布式锁的对比

- 一致性和可靠性:ZooKeeper 提供了较高的一致性和可靠性,适合作为分布式锁的后端存储;而 Redis 虽然性能出色,但在一致性和可靠性方面略逊一筹。
- 部署复杂性:ZooKeeper 的部署和维护相对复杂,需要专门的运维人员进行管理;而 Redis 相对来说更加简单和容易上手。
- 性能: Redis 作为内存数据库,读写性能通常更优,适用于对性能要求较高的场景;ZooKeeper 在高并发场景下可能性能较为有限,需要权衡选择。

最终选择 ZooKeeper 还是 Redis 作为分布式锁的后端存储,需要根据具体的业务需求、系统的性能要求以及运维成本等方面进行综合考虑。

curator分布式锁和redisson分布式锁

Curator是Netflix开源的一组Apache ZooKeeper客户端库的高级API。Curator 提供了一套易用

基于分布式锁解决定时任务的重复问题

当使用 Redis 实现分布式锁来解决定时任务的重复问题时,可以通过以下步骤来实现:

1. 首先,实现一个定时任务,例如每隔一定时间执行某个任务。

2. 在任务执行之前,客户端尝试获取 Redis 中特定的锁,比如使用 SETNX 命令来设置一个特定的键。如果返回成功,即获取到了锁,就可以执行任务;否则,任务不应该被执行。

3. 在任务执行完毕后,释放锁,通过 DEL 命令来删除锁对应的键。

这是一个基本的使用 Redis 实现分布式锁解决定时任务重复问题的例子。然而,在实现过程中可能会遇到一些问题,如下所示:

- 锁竞争问题:*在高并发的情况下,多个客户端可能同时尝试获取同一个锁,从而导致竞争。只有一个客户端能够成功获取到锁,其他客户端则不能执行任务。

- 锁超时问题:如果设置的锁超时时间过长,那么在某个客户端执行任务期间,该客户端意外崩溃或失去连接,没有及时释放锁,就会导致其他客户端无法获取锁,进而无法执行任务。

为了解决这些问题,可以采取以下方案:

- 设置锁的有效期限制: 在获取锁的时候,使用 SETNX 命令设置一个过期时间,避免某个客户端崩溃或失去连接而不能释放锁。可以使用 PEXPIRE 命令来设置锁的过期时间。

- 添加唯一标识符:当某个客户端成功获取到锁时,在锁的键名中添加一个唯一标识符,使得只有拥有相应标识符的客户端才能释放该锁。这样可以避免其他客户端误释放锁。(当两个客户端在几乎相同的时间内向 Redis 请求锁时,根据 Redis 的单线程执行特性,Redis 会依次处理这两个客户端的请求。由于执行速度非常快,Redis 无法辨别两个请求的先后顺序,因此有可能会出现两个客户端同时获得锁的情况。)

- 使用 Redlock 或 RediLock 算法:Redlock 或 RediLock 是一种分布式锁算法,在 Redis 集群环境中使用多个 Redis 实例来实现分布式锁,提供更高的可靠性和鲁棒性。

红锁(Redlock)是一种分布式锁算法,被设计用于在Redis集群环境中实现分布式锁。它旨在提供更高的可靠性和鲁棒性,尤其针对网络分区和故障恢复的情况。

红锁算法的原理如下:

1. 客户端根据一致性哈希算法将锁映射到多个Redis实例上,形成一个由n个实例组成的锁集群。

2. 客户端尝试在每个Redis实例上获取锁。通过使用`SETNX`命令来设置一个特定键和值,如果返回成功则客户端获取到了锁。

3. 客户端记录获取锁成功的实例数量,并计算时间戳。

4. 客户端检查是否超过了超时时间(通常是锁的有效期的一半),以及是否获得了大部分实例锁的数量。如果是,则客户端认为成功获取到了锁。

5. 如果客户端无法获取到过半数的实例锁,或者超时了,则客户端尝试释放已经获取的锁。

红锁算法的优点是考虑了分布式环境可能出现的网络分区和故障恢复问题。通过使用多个Redis实例进行锁的获取和释放,能够提供更高的可靠性和鲁棒性,同时保证只有一个客户端能够获得锁。

针对定时任务的重复问题,可以使用红锁算法结合定时任务的处理方式来解决。具体实现步骤如下:

1. 在每个定时任务执行前,客户端使用红锁算法获取一个分布式锁。

2. 获取锁成功后,执行定时任务。

3. 定时任务执行完毕后,客户端释放分布式锁。

这样可以确保在分布式环境中,同一时间只有一个客户端能够获取到锁,从而避免了定时任务的重复执行问题。同时,红锁算法的可靠性和鲁棒性能够应对网络分区和故障恢复的情况,提供更强大的分布式锁功能。

需要注意的是,使用 Redis 实现分布式锁时,仍然需要保证 Redis 的高可用性和故障恢复能力,可以通过 Redis Sentinel 或 Redis Cluster 来实现。同时,还需要谨慎处理 Redis 连接池的资源管理,以避免资源耗尽的问题。

常见面试题

如何解决分布式事务

在解决分布式事务问题时,可以采用以下几种常见的解决思路:

1. 强一致性分布式事务(Two-Phase Commit,2PC):2PC 是一种经典的解决方案,基于协调者和参与者之间的协议来保证所有参与者要么全部提交,要么全部回滚。协调者负责协调参与者的状态,并决定是否进行提交。然而,2PC 存在单点故障问题,并且在分布式系统规模较大时性能和可扩展性会受到限制。

2. 最终一致性分布式事务(Saga Pattern):Saga Pattern 将一个大事务拆分为多个小事务,并通过补偿操作来保证最终一致性。每个小事务可以独立执行,并且在失败时可以执行相应的补偿操作。Saga Pattern 对于长时间运行的分布式事务和异步消息的处理非常有用。但需要注意,Saga Pattern 的设计和实现可能会增加系统的复杂性。

3. 基于消息的分布式事务(Transactional Messaging):在分布式系统中,可以将事务性操作与消息传递相结合。通过消息队列来确保事务的一致性。当一个服务完成其本地事务后,会向消息队列发送消息,其他服务在接收到消息后执行相应的操作。这种方法可以实现比较灵活的事务处理,但需要考虑消息队列的可靠性和幂等性。

4. 分布式事务中间件:一些开源和商业的分布式事务中间件,如Seata、TCC-Transaction、Hmily等,提供了分布式事务的解决方案,可以简化分布式事务的开发和管理。这些中间件通常提供了一致性协议、分布式事务管理和补偿机制等功能。

需要根据具体的业务场景、系统规模和性能要求来选择合适的分布式事务解决方案。同时,需注意分布式事务的设计和实现可能会增加系统的复杂性,并需要充分考虑事务一致性、性能、可靠性和开发复杂度等因素之间的权衡。

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

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

相关文章

二分算法(c++版)

二分的本质是什么? 很多人会认为单调性是二分的本质,但其实其本质并非单调性,只是说,有单调性的可以进行二分,但是有些题目没有单调性我们也可以进行二分。其本质其实是一个边界问题,给定一个条件&#xf…

2.WEB渗透测试-前置基础知识-web基础知识和操作系统

web基础知识 1.http协议 超文本传输协议是互联网上应用最广泛的一种网络协议。所有www文件都必须遵守的一个标准,是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范,通俗点说就是一种固定的通讯规则。 2、网络的三种架构及特点 网络应…

【C++STL】迭代器分类 失效问题

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

堆排序、快速排序和归并排序

堆排序、快速排序和归并排序是所有排序中最重要的三个排序&#xff0c;也是难度最大的三个排序&#xff1b;所以本文单独拿这三个排序来讲解 目录 一、堆排序 1.建堆 2.堆排序 二、快速排序 1.思想解析 2.Hoare版找基准 3.挖坑法找基准 4.快速排序的优化 5.快速排序非…

自定义神经网络二之模型训练推理

文章目录 前言模型概念模型是什么&#xff1f;模型参数有哪些神经网络参数案例 为什么要生成模型模型的大小什么是大模型 模型的训练和推理模型训练训练概念训练过程训练过程中的一些概念 模型推理推理概念推理过程 总结 前言 自定义神经网络一之Tensor和神经网络 通过上一篇…

IOBR2 更新(学习自备)

IOBR查看其收录的相关基因集(自备)_肿瘤 tme特征 iobr-CSDN博客 IOBR2&#xff1a;多维度解析肿瘤微环境 - 知乎 (zhihu.com) 学习手册&#xff1a;https://iobr.github.io/book/ &#xff08;里面有详细教程&#xff09; 系统综合的分析工具&#xff08;Immuno-Oncology Bi…

学习python的第7天,她不再开放她的听歌榜单

我下午登录上小号&#xff0c;打开聊天消息看到了她的回复&#xff0c;我很开心兴奋&#xff0c;可是她不再开放她的听歌榜单了&#xff0c;我感觉得到&#xff0c;我要失恋了。 “因为当年电视上看没有王菲版本的” “行”。 “那你以后还会开放听歌榜单吗&#xff1f;”我…

opencv基础 python与c++

question: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib Opencv 一、读取图片 (1).imshow Mat imread(const string& filename, intflags1 );flags: enum { /* 8bit, color or not */CV_LOAD_IMAGE_UNCHANGED -1, /* 8bit, gray */CV_LOAD_I…

基于springboot+vue的大型商场应急预案管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

应用回归分析:非参数回归

非参数回归是一种统计方法&#xff0c;它在建模和分析数据时不假设固定的模型形式。与传统的参数回归模型不同&#xff0c;如线性回归和多项式回归&#xff0c;非参数回归不需要预先定义模型的结构&#xff08;例如&#xff0c;模型是否为线性或多项式&#xff09;。这使得非参…

小米标准模组+MCU 快速上手开发(一)——之固件下载

小米标准模组+MCU 开发笔记之固件下载 背景技术名词简介● 小米IoT开发者平台● 小米IoT 模组● ESP系列简介问题描述 + 解决方式问题1:固件下载是否有示例,如何下载到硬件板卡中?问题2:固件下载的官方程序是什么?在哪里?该如何使用?问题3:固件下载时,Flash和Ram 有什…

VCRUNTIME140_1.dll丢失是怎么回事,如何解决

当计算机系统中找不到vcruntime140_1.dll文件时&#xff0c;运行依赖于该文件的软件通常会显示错误消息&#xff0c;这类错误消息可能会包含以下几种形式&#xff1a; 明确提示缺失文件&#xff1a;错误信息可能直接指出“无法找到vcruntime140_1.dll”或“vcruntime140_1.dll…

怎么自学python,大概要多久?python多久上手?

无限时长~~~~技术不断在更新&#xff0c;你的自学不也需要一直进行吗&#xff1f; 但如果是问&#xff1a;自学多长时间可以入门&#xff1f;或者可以找到工作&#xff1f;那我可以告诉你答案。 从零基础开始自学Python&#xff0c;依照每个人理解能力的不同&#xff0c;大致…

no main manifest attribute, in app.jar

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

软件工程复习笔记

一、软件工程概述 软件 = 程序 + 数据 + 相关文档 软件危机(Software Crisis) 指由于落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重问题的现象。 软件工程三要素 方法、工具、过程 软件工程目标 在给定成本、进度的…

目标检测新SOTA:YOLOv9 问世,新架构让传统卷积重焕生机

在目标检测领域&#xff0c;YOLOv9 实现了一代更比一代强&#xff0c;利用新架构和方法让传统卷积在参数利用率方面胜过了深度卷积。 继 2023 年 1 月 YOLOv8 正式发布一年多以后&#xff0c;YOLOv9 终于来了&#xff01; 我们知道&#xff0c;YOLO 是一种基于图像全局信息进行…

[HTML]Web前端开发技术30(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 网页标题:手机批发业务-商品备选区<

解析OOM的三大场景,原因及实战解决方案

目录 一、什么是OOM 二、堆内存溢出&#xff08;Heap OOM&#xff09; 三、方法区内存溢出&#xff08;Metaspace OOM&#xff09; 四、栈内存溢出&#xff08;Stack OOM&#xff09; 一、什么是OOM OOM 是 Out Of Memory 的缩写&#xff0c;意思是内存耗尽。在计算机领域…

【Spring MVC】处理器映射器:AbstractHandlerMethodMapping源码分析

目录 一、继承体系 二、HandlerMapping 三、AbstractHandlerMapping 四、AbstractHandlerMethodMapping 4.1 成员属性 4.1.1 MappingRegistry内部类 4.2 AbstractHandlerMethodMapping的初始化 4.3 getHandlerInternal()方法&#xff1a;根据当前的请求url&#xff0c;…

Java基于物联网技术的智慧工地云管理平台源码 依托丰富的设备接口标准库,快速接入工地现场各类型设备

目录 风险感知全面化 项目进度清晰化 环境监测实时化 人员管理高效化 工地数字化 数据网络化 管理智慧化 智慧工地平台整体架构 1个可扩展监管平台 2个应用端 3方数据融合 N个智能设备 智慧工地的远程监管&#xff0c;是工地负责人掌握施工现场情况的必要手段&…