当前位置: 首页 > news >正文

一文拿捏基于redis的分布式锁、lua、分布式性能提升

1.分布式锁

jdk的锁: 1、显示锁:Lock 2、隐式锁:synchronized

使用jdk锁保证线程的安全性要求:要求多个线程必须运行在同一个jvm中

但现在的系统基本都是分布式部署的,一个应用会被部署到多台服务器上,synchronized只能控制当前服务器自身的线程安全,并不能跨服务器控制并发安全。

所以在分布式环境下要解决线程安全问题就需要使用分布式锁

思想:需要在我们分布式应用的外面使用一个第三方组件(可以是数据库、Redis、Zookeeper等)进行全局锁的监控,由这个组件决定什么时候加锁,什么时候释放锁

原理:在获取锁的时候插入数据,如何数据可以存储成功那么就获取获取到了锁,如果数据插入不成功那么就说明获取锁失败了。在进行锁释放的时候只需要将数据删除掉。

1.🌟redis分布式锁实现业务流程:
  1. 首先我们项目中是基于原生redis实现分布式的就会涉及到一些redis原生命令

  2. 前置操作一定是缓存无数据,布隆判断之后可能有数据,才会在此处添动加商品自身分布式锁

  3. 使用set nx ex命令设置一个有效期为指定时间的锁,我记得当时是根据多次压测结果取的值

  4. 这样会有一个问题,万一在给定时间内未完成查询操作此时我们是通过后端代码自定义守护线程方式位锁进行自动续期

  5. 上面的操作如果都没有问题,表示上锁成功.回源查询数据库写入缓存,整个分布式锁的实现会涉及到锁的获取、判断、删除,需要保证这三个操作原子性,我们借助于lu脚本实现这个一般也不需要记用的时候,通过文档查阅即可

1.基础实现

基于setnx命令的特性,我们就可以实现一个最简单的分布式锁了。我们通过向Redis发送 setnx 命令,然后判断Redis返回的结果是否为1,结果是1就表示setnx成功了,那本次就获得锁了,可以继续执行业务逻辑;如果结果是0,则表示setnx失败了,那本次就没有获取到锁,可以通过循环的方式一直尝试获取锁,直至其他客户端释放了锁(delete掉key)后,就可以正常执行setnx命令获取到锁。流程如下:

2.lua原子性操作

针对上述Redis原始命令无法满足部分业务原子性操作的问题,Redis提供了Lua脚本的支持。

释放锁时:

Lua脚本是一种轻量小巧的脚本语言,它支持原子性操作,Redis将整个Lua脚本作为一个整体执行,中间不会被其他请求插入,因此Redis执行Lua脚本是一个原子操作。在上面的流程中,我们把get key value、判断value是否属于当前线程、删除锁这三步写到Lua脚本中,使它们变成一个整体交个Redis执行,改造后流程如下:

解决了释放锁时取值、判断值、删除锁等多个步骤无法保证原子操作的问题了

加锁时:

在使用set key value ex seconds nx命令加锁时,并不能做到重入锁的效果,也就是当一个线程获取到锁后,在没有释放这把锁之前,当前线程自己也无法再获得这把锁,这显然会影响系统的性能。使用Lua脚本就可以解决这个问题,我们可以在Lua脚本中先判断锁(key)是否存在,如果存在则再判断持有这把锁的线程是否是当前线程,如果不是则加锁失败,否则当前线程再次持有这把锁,并把锁的重入次数+1。在释放锁时,也是先判断持有锁的线程是否是当前线程,如果是则将锁的重入次数-1,直至重入次数减至0,即可删除该锁(key)。

2.🌟Aop-分布式锁(首页三级分类、详情页)

分布式锁实现、A0P在项目中的使用场景

本身咱们在不使用缓存和分布式锁的情况下,也可以实现详情页或者首页三级分类信息的展示,使用了缓存和分布式锁,只是对核心功能的一个增强,按照00P思想,会直接侵入代码不易维护,所以需要将这种从上到下的关系优化为从左到右的增强,即AOP思想AOP是spring提供的一个面向切面编程思想,其底层原理是动态代理,项目中是这样做的

  1. 自定了一个注解@MyCache包含redis使用的key的前缀、过期时间、分布式锁key值等信息

  2. 自定义一个切面类,就是一个被@Aspect注解修饰的一个普通类而己,在类中定义一个通知,其实就是方法名around在这个方法上需要加@Around注解表示,我们用的是spring5通知类型中的环绕通知,通过该注解的一个属性annotation对自定义注解进行增强

  3. 鉴于环绕通知的使用方法是固定的,所以在定义环绕通知的时候,需要注意方法返回值必须是Object类型,方法形参必须是ProceedingJoinPoint的,为了能够手动调用目标方法,另外还需要注意,环绕通知方法必须手动抛出异常信息

  4. 这样就完成了项目中对于A0P封装和使用,在需要用到缓存和分布式锁的场景,我们只需要将注解添加到使用的位置即可

3 如何提高分布式锁性能
1 优化分布式锁性能的关键因素

要提升分布式锁的性能,首先需要了解影响性能的关键因素。以下是一些影响分布式锁性能的关键因素:

  1. 锁的粒度:锁的粒度越小,性能通常越高。粒度较大的锁可能会导致锁争用,从而降低性能。

  2. 锁的持有时间:锁的持有时间越短,性能越高。长时间持有锁会限制其他节点的访问。

  3. 锁的实现方式:不同的分布式锁实现方式性能差异较大。使用缓存的速度比较快。

  4. 网络延迟:分布式锁通常需要跨越网络进行通信,网络延迟会影响性能。

  5. 锁的竞争情况:如果锁的竞争情况较少,性能通常较好。高度竞争的锁会导致性能下降。

2 优化技巧和最佳实践
1. 选择合适的分布式锁实现

选择合适的分布式锁实现是性能优化的关键。不同的实现方式有不同的性能特点。例如,基于

Redis的分布式锁通常性能较高,因为Redis是一个高性能的内存数据库,而基于ZooKeeper的锁可

能性能较低,因为它需要跨越网络进行通信。因此,根据需求选择合适的实现方式非常重要。

2. 减小锁的粒度

将锁的粒度尽量减小可以提高性能。例如,如果系统中有多个共享资源,可以为每个资源使用单独

的锁,而不是一个全局锁。这样可以减小锁的竞争情况,提高吞

吐量。

3. 限制锁的持有时间

尽量减小锁的持有时间可以提高性能。在获取锁后,尽快完成需要锁保护的操作,然后释放锁,让

其他节点有机会访问共享资源。

4. 使用非阻塞锁

非阻塞锁通常性能更高,因为它们不会阻塞线程或进程,而是会立即返回锁的状态。常见的非阻塞

锁包括乐观锁和基于CAS(比较并交换)的锁。

5. 考虑锁的超时和重试机制

在获取锁时,考虑设置锁的超时时间和重试机制,以避免出现死锁情况。如果获取锁失败,可以等

待一段时间后重试,或者使用指数退避策略。

6. 考虑分布式事务

在某些场景下,使用分布式事务可以代替分布式锁,从而提高性能。分布式事务通常比分布式锁更

高效,但需要谨慎设计,以确保数据一致性。

相关文章:

一文拿捏基于redis的分布式锁、lua、分布式性能提升

1.分布式锁 jdk的锁: 1、显示锁:Lock 2、隐式锁:synchronized 使用jdk锁保证线程的安全性要求:要求多个线程必须运行在同一个jvm中 但现在的系统基本都是分布式部署的,一个应用会被部署到多台服务器上,s…...

机器学习必修课 - 如何处理缺失数据

运行环境:Google Colab 处理缺失数据可简单分为两种方法:1. 删除具有缺失值的列 2. 填充 !git clone https://github.com/JeffereyWu/Housing-prices-data.git下载数据集 import pandas as pd from sklearn.model_selection import train_test_split导…...

阿里云服务器方升架构、自研硬件、AliFlash技术创新

阿里云服务器技术创新:服务器方升架构及自研硬件、自研存储硬件AliFlash和阿里云异构计算加速平台,阿里云百科分享阿里云服务器有哪些技术创新: 目录 服务器技术创新 服务器方升架构及自研硬件 自研存储硬件AliFlash 阿里云异构计算加速…...

知识工程---neo4j 5.12.0+GDS2.4.6安装

(已安装好neo4j community 5.12.0) 一. GDS下载 jar包下载地址:https://neo4j.com/graph-data-science-software/ 下载得到一个zip压缩包,解压后得到jar包。 二. GDS安装及配置 将解压得到的jar包放入neo4j安装目录下的plugi…...

BUUCTF reverse wp 81 - 85

[SCTF2019]babyre 反编译失败, 有花指令 有一个无用字节, 阻止反编译, patch成0x90 所有标红的地方nop掉之后按p重申函数main和loc_C22, F5成功 int __cdecl main(int argc, const char **argv, const char **envp) {char v4; // [rspFh] [rbp-151h]int v5; // [rsp10h] [rb…...

数据结构-哈希表

系列文章目录 1.集合-Collection-CSDN博客​​​​​​ 2.集合-List集合-CSDN博客 3.集合-ArrayList源码分析(面试)_喜欢吃animal milk的博客-CSDN博客 4.数据结构-哈希表_喜欢吃animal milk的博客-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一 . 什么是哈希表&a…...

深度学习在图像识别领域还有哪些应用?

深度学习在图像识别领域的应用非常广泛,除了之前提到的图像分类、目标检测、语义分割和图像生成,还有其他一些应用。 图像超分辨率重建:深度学习技术可以用于提高图像的分辨率,例如通过使用生成对抗网络(GAN&#xff…...

前端项目练习(练习-005-webpack-03)

学习前,首先,创建一个web-005项目,内容和web-004一样。(注意将package.json中的name改为web-005) 前面的代码中,打包工作已经基本完成了,下面开始在本地启动项目。这里需要用到webpack-dev-serv…...

『力扣每日一题10』:字符串中的单词数

因为身体原因,再加上学校的 DeadLine 比较多,太忙太累,拖更了半个月。现在开始重拾日更,期待我们一起遇见更好的自己! 一、题目 统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。 请注意&a…...

初级篇—第三章多表查询

文章目录 为什么需要多表查询一个案例引发的多表连接初代查询笛卡尔积(或交叉连接)的理解 多表查询分类等值连接 vs 非等值连接自连接 vs 非自连接内连接VS外连接 SQL99语法实现多表查询内连接的实现外连接的实现左外连接右外连接满外连接 UNION的使用7种…...

<Xcode> Xcode IOS无开发者账号打包和分发

关于flutter我们前边聊到的初入门、数据解析、适配、安卓打包、ios端的开发和黑苹果环境部署,但是对于苹果的打包和分发,我只是给大家了一个链接,作为一个顶级好男人,我认为这样是对大家的不负责任,那么这篇就主要是针…...

vertx的学习总结2

一、什么是verticle verticle是vertx的基本单元,其作用就是封装用于处理事件的技术功能单元 (如果不能理解,到后面的实战就可以理解了) 二、写一个verticle 1. 引入依赖(这里用的是gradle,不会吧&#…...

网络安全内网渗透之DNS隧道实验--dnscat2直连模式

目录 一、DNS隧道攻击原理 二、DNS隧道工具 (一)安装dnscat2服务端 (二)启动服务器端 (三)在目标机器上安装客户端 (四)反弹shell 一、DNS隧道攻击原理 在进行DNS查询时&#x…...

探索ClickHouse——连接Kafka和Clickhouse

安装Kafka 新增用户 sudo adduser kafka sudo adduser kafka sudo su -l kafka安装JDK sudo apt-get install openjdk-8-jre下载解压kafka 可以从https://downloads.apache.org/kafka/下找到希望安装的版本。需要注意的是,不要下载路径包含src的包,否…...

基于监督学习的多模态MRI脑肿瘤分割,使用来自超体素的纹理特征(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

【RocketMQ】(八)Rebalance负载均衡

消费者负载均衡,是指为消费组下的每个消费者分配订阅主题下的消费队列,分配了消费队列消费者就可以知道去消费哪个消费队列上面的消息,这里针对集群模式,因为广播模式,所有的消息队列可以被消费组下的每个消费者消费不…...

线性筛和埃氏筛

线性筛&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<ut…...

【Java 进阶篇】JDBC ResultSet 类详解

在Java应用程序中&#xff0c;与数据库交互通常涉及执行SQL查询以检索数据。一旦执行查询&#xff0c;您将获得一个ResultSet对象&#xff0c;该对象包含查询结果的数据。本文将深入介绍ResultSet类&#xff0c;它是Java JDBC编程中的一个核心类&#xff0c;用于处理查询结果。…...

Centos7常用服务脚本(.service)

Centos7常用服务脚本&#xff08;.service&#xff09; 注意&#xff1a;[Service]中配置路径必须使用绝对路径。 启停&#xff1a; systemctl { start | stop | restart | reload } xxx.service 自启动&#xff1a; systemctl { enable | disable } xxx.service nginx.se…...

MySQL 视图View的SQL语法和更新(视图篇 二)

视图语法基本操作 创建 -- [ ]表示可选 create [or replace] view 视图名称[(列名列表)] as select语句 [ with [cascaded | local ] check option ]; 添加&#xff08;虽然视图是虚拟表&#xff0c;但是向视图操作的数据实际上会影响到实际关联的表数据&#xff09; -- 视图添…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器&#xff0c;用于保存可变的数据值。在Java中&#xff0c;变量必须先声明后使用&#xff0c;声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例&#xff1a;声明与初始化 public class VariableDemo {publi…...

智警杯备赛--excel模块

数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中&#xff0c;点击确定 这是最终结果&#xff0c;但是由于环境启不了&#xff0c;这里用的是自己的excel&#xff0c;真实的环境中的excel根据实训…...

VASP软件在第一性原理计算中的应用-测试GO

VASP软件在第一性原理计算中的应用 VASP是由维也纳大学Hafner小组开发的一款功能强大的第一性原理计算软件&#xff0c;广泛应用于材料科学、凝聚态物理、化学和纳米技术等领域。 VASP的核心功能与应用 1. 电子结构计算 VASP最突出的功能是进行高精度的电子结构计算&#xff…...

记一次spark在docker本地启动报错

1&#xff0c;背景 在docker中部署spark服务和调用spark服务的微服务&#xff0c;微服务之间通过fegin调用 2&#xff0c;问题&#xff0c;docker容器中服务器来后&#xff0c;注册中心都有&#xff0c;调用服务也正常&#xff0c;但是调用spark启动任务后报错&#xff0c;报错…...