Redis学习(三)之 分布式锁详解

news2024/11/30 0:42:06

1、redis分布式锁相关的可以移步这篇文章redis做分布式锁实战案例详解_酒书的博客-CSDN博客

这里是对该篇文章的加深与补充

2.集群主从切换导致锁丢失问题:在redis主从架构中,写入都是写入到主redis中,主redis会同步数据到slave机器,比如一个A线程向redis实例中写入数据的时候来加了一个分布式锁,加锁后开始执行业务代码,这时如果主redis实例挂掉了,会选举出一个从redis实例成为master,如果刚刚加redis锁的key还没来得及同步到slave中,那么选举出来的新master中就没有这个key,这个时候线程B就可以进行加锁来获取分布式锁,然后执行业务代码,而这个时候线程A还没有执行结束,所以就会出现并发安全问题,这就是redis主从架构的分布式锁失效问题。

redis master收到数据之后就会返回ack ,而不是同步slave之后才返回ack,因此会有该问题。

 解决方案1:使用zookeeper代替redis解决分布式锁失效问题

zookeeper也是一种k-v形式的存储中间件,它内部结构是树形的,zk集群中主节点叫做leader,从节点叫做follower,使用zk就能解决主从同步引起的分布式锁失效问题,这是因为zk保证的是一致性,leader收到请求后会同步数据给follower,收到半数上的follower ack之后leader才会给线程返回ack,即使这个时候leader挂了,已经同步到数据的follower由于数据最新必然会被选为新的leader,因此zk不存在集群分布式锁失效问题。

解决方案2:RedLock解决分布式锁失效问题

如果非要用redis来解决,那可以用RedLock,RedLock底层逻辑和zk很类似。

首先要有多个(最好是奇数个)对等的(没有主从关系)redis节点,当进行加锁时(比如是用setnx),则这个设置key-value的命令会发给每个redis节点执行,当且仅当客户端收到超过半数的节点写成功的消息时,才认为加锁成功,才开始执行业务代码。

下图中,Client 1向Redis 1/2/3三个结点去写key-value,假设当前处在Redis 1和Redis 2写入成功了,Redis 3还没有写入成功的状态,这个时候Client 1就已经认为加锁成功了,实际上已经可以执行业务代码了。此时,假设有一个Redis结点挂了(最坏的情况就是已经写入了key的一个结点挂了,如下图所示Redis 1挂了),这个时候假设Client 2也要尝试加锁,此时Redis 2由于已经被Client 1写过了,没法写入成功,但是Redis 3可以写入成功。此时只有1个结点能写入成功,所以认为加锁不成功,这样Client 2就不会开始错误的执行业务代码,也就不会出现并发安全问题。

当时其实RedLock也存在问题,比如说redis2挂了,redis2的slave成为新的master,然后client2加锁,这个时候redis3和redis2新的master都会返回写入成功,依然可以加锁,当然如果不搞从节点是可以的,那client2此时是无法加锁的。

 redis实际应用中性能优化

1、我们在缓存秒杀商品的时候,比如秒杀商品product_iphone14pro_stock=1000,其实我们可以优化为将product_iphone14pro_stock 这个key给拆分为10个key,例如:

product_iphone14pro_stock_1=100

product_iphone14pro_stock_2=100

product_iphone14pro_stock_3=100

省略4、5、6、7、8、9

product_iphone14pro_stock_10=100

这样实现的话如果请求来了10个线程就不会出现并发问题,性能的话至少就提升了10倍,当然具体实现的话很多细节还是需要注意的。

 2、我们用缓存的意义就是使那些热点访问的数据尽量待在缓存里,减少数据库的访问压力,而一些冷门的数据其实就没必要一直待在缓存里面。

因此1:在数据放入缓存的时候,尽量都加入一个缓存过期时间,这样一些冷门数据不会一直待在              缓存里面。

因此2:在查询缓存的时候,如果查询到了缓存,就给缓存的时间做一个超时的延期,这样不至于               热门访问的数据缓存过期。

上面的做法其实就是商品缓存数据冷热分离

3、缓存击穿(失效)

高并发情况下,热点数据缓存过期,大量请求直接打到数据库,导致数据库负载过大

解决方案:1、设置热点数据永不过期,缺点就是热点数据量大的话缓存量就比较大;

                  2、热点数据快过期时,通过另一个异步线程重新设置key,缺点就是需要另外的逻辑                           去维护,会增加系统的复杂度

                  3、当缓存数据过期,重新从数据库加载数据到缓存的过程上互斥锁

4、缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和数据库都不会命中,通常出于容错的考虑,如果从数据库查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到数据库去查询,失去了缓存保护数据库的意义。造成缓存穿透的基本原因有两个:

第一:自身业务代码或者数据出现问题   第二:一些恶意攻击,爬虫等造成大量空命中

缓存穿透解决方案1:缓存空值,比如打到数据库也没有值,这个时候我将一个"{}"放到缓存里面,这样再次访问的时候就直接去缓存里面取"{}",当然设置缓存的时候记得要设置缓存过期的时间,因为如果遭到黑客攻击这个时候可能redis里面会被设置n 多个"{}",会占用我们的内存资源,设置短暂的过期时间使得黑客攻击后缓存的那些"{}"自动过期。

缓存穿透解决方案2:布隆过滤器

对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,还可以用布隆过滤器先做一次过滤,对于不存在的数据布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在,当说某个值不存在时,那就肯定不存在。

5、缓存雪崩

在高并发场景下,缓存同一时刻失效(缓存挂了或者大量的key设置了相同的过期时间),所有请求都会读取数据库,数据库负载过大或者崩掉

解决方案:1、缓存失效的时间设置随机数,避免同时失效

                  2、保证缓存服务高可用,比如使用sentinel或者cluster架构

                  3、依赖隔离组件为后端限流熔断并降级

6、突发性热点缓存重建导致系统压力暴增问题:

比如说某个冷门商品很少有人访问,可能就不会放到缓存里面,只有当被访问的时候才会被放到缓存里面,可是有一种情况就是某个大V直播间带货某平台某个冷门商品,导致大量流量一下子来到某商城访问某个冷门商品,由于缓存里面还没有数据,就会全部打到数据库,使得其压力增大。

解决方案:分布式锁来解决,第一个抢到锁的线程去查询数据库,然后写入缓存,后面线程进来                      就可以直接去缓存里面获取值

 

7、 缓存与数据库双写不一致:在高并发下,同时操作数据库与缓存会存在数据不一致问题

 有一种方案是写入数据库之后删除缓存,其实这样也有问题,就是读写不一致的情况

 解决方案:

1、对于并发几率很小的数据几乎不用考虑这个问题,很少会发生缓存不一致,可以给缓存数据加上过期时间,每隔一段时间读取数据的时候更新缓存即可。

2、针对并发很高的情况且不能容忍缓存数据不一致的,可以通过加分布式读写锁保证并发读写或写写的时候按顺序排好队执行,读读的时候相当于无锁,提高了读的效率,推荐使用

3、当然也可以用阿里开源的canal通过监听数据库的binlog日志及时去修改缓存,但是引入了新的中间件,增加了系统复杂度。

4、当然也可以采用延时双删策略:如下图在修改数据库数据之前,需要先删除一次redis缓存,此时是为了保证在数据库修改和redis缓存数据被删除的间隔时间内如果有其他线程来读取使得缓存中无数据,因为如果缓存中有数据的话必然是旧数据,和数据库数据不一致,避免读取缓存旧数据;第二次删除是在修改数据库之后,此时需要再次删除redis中的缓存数据,这一次是为了删除 第一次redis删除和数据库数据修改之间,如果有请求,那么旧数据又会重新缓存到redis中,然而数据在数据库中在接下来就会被修改,如果没有这一次删除,redis中则会存在数据库中旧的数据。

  • 那么第二次为什么需要在数据库修改后延迟一定时间再删除redis呢?
  • 为了等待之前的一次读取数据库,并等待其数据写入到缓存,最后删除这次脏数据,所以是一次数据从数据库中发到服务器+缓存写入的时间

但是延迟双删,所延迟的时间非常的难以确定,所以并不推荐延迟双删

根据综合考虑,即使先修改数据库,在删除缓存,有一定的时间会导致读取到旧数据,这通常是可以被忍受的。只要及时将缓存删除,其他线程就可以读取到最新的值。或者直接上分布式锁

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

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

相关文章

Mybatis插件机制

什么是插件机制 插件插件, 就是能在执行某个方法之前加入一些功能代码, 有啥方法能够实现呢?当然是动态代理了, 为啥要使用动态代理应为他是为了写框架扩展性必备的东西。 只要定义一些接口 或者类 就行使用jdk自带的或者CGLIB之…

分布式NoSQL数据库HBase实践与原理剖析(二)

title: HBase系列 第五章 HBase核心原理 5.1 系统架构 注意,其实上图中的HLog应该在HRegionServer里面,而不是在HRegion里面。所以图有点点问题。其实通过后面的物理存储的图也能发现这个问题。 Client 职责 1、HBase 有两张特殊表: .meta.…

力扣 21. 合并两个有序链表 C语言实现

题目描述: 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 题目链接 方法1:遍历 新建一个链表 newList 用于存放合并后的链表,设置一个指针指向该链表最后一个位置的 next&#xff0c…

77.【JavaWeb文件上传和邮件发送04】

JavaWeb(二十五)、文件上传1.准备工作2.实用类介绍3.思维导图:4.正戏开始5.完整代码(二十六)、邮箱发送1.邮箱发送的原理:2.服务器的原理3.下载两个jar包4.基本类:5.全部代码(二十七)、网站注册发送邮件实现(二十五)、文件上传 1.首先创建一个empty项目 2.配置project项目中的…

【JVM】jvm中的栈简介

jvm中的栈简介一、JVM体系结构二、栈是什么?三、栈的特性四、栈帧五、栈的运行原理5.1 运行原理5.2 代码示例5.2.1 方法的入栈和出栈5.2.2 没有捕获异常5.2.3 捕获异常六、栈帧的内部结构七、运行时数据区,哪些部分存在Error和GC?八、本文源码…

boot 创建 https

需要在配置文件中:加入 server:ssl:key-store: classpath:https.keystorekey-store-type: JKSkey-alias: tomcatkey-password: 123456key-store-password: 123456port: 8089 这样原本请求的http,就需要变成https,其他类似 RestController p…

深度学习入门(五十六)循环神经网络——循环神经网络RNN

深度学习入门(五十六)循环神经网络——循环神经网络RNN前言循环神经网络——循环神经网络RNN课件潜变量自回归模型循环神经网络使用循环神经网络的语言模型困惑度(perplexity)梯度裁剪更多的应用RNNs总结教材1 无隐状态的神经网络…

周赛总结--LeetCode单周赛321场 AcWing79场

1. LeetCode单周赛321场 1.1 找出中枢整数 1.1.1 原题链接:力扣https://leetcode.cn/problems/find-the-pivot-integer/ 1.1.2 解题思路: 1、先保存 1-n 的和sum; 2、从 1 开始枚举,判断前 i 项和 cmp 与 sum - cmp i 是否相等…

MySQL第二弹

目录​​​​​​​ 一、数据库基本操作 1、查看数据库信息 2、查看数据库中的表信息 3、显示数据表的结构(字段) 4、常见的数据类型 4.1 数值类型 4.2 日期和时间类型 4.3 字符串类型 二、SQL语言概述 1、SQL语言 2、SQL分类 2.1 DDL:数据定…

【强化学习论文合集】NeurIPS-2021 强化学习论文

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现…

js——高阶函数、闭包、递归以及浅拷贝和深拷贝

目录 一、高阶函数 1、什么是高阶函数 2、把一个函数作为参数 3、return 返回的也是一个函数 二、闭包 1、闭包是什么 2、变量的作用域 3、案例 4、结果展示: 5、总结: 三、递归 1、什么是递归 2、案例一 3、分析 4、问题 5、栈溢出又是什…

【Unity Shader​】 屏幕后处理5.0:讨论双重模糊的Bloom

接上一篇基于高斯模糊的Bloom继续进行接下来的学习。 1 一些必要的思考* 1.1 关于高质量Bloom 前面提到了,Bloom对于游戏必不可少的效果之一,于是我们不仅仅要把Bloom效果实现出来,效果的质量好坏就更加是我们需要关注的点了。高质量泛光&a…

面试宝典之C++多态灵魂拷问

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸 文章目录一、重载,隐藏/重定义,覆盖/重写二、多态的原理三、inline可以是虚函数吗四、静态成员函数可以是虚函数吗五、构造函…

海丝一号-中国-2020

2020年12月22日,由中国电科38所和天仪研究院联合研制的我国首颗商业SAR卫星“海丝一号”搭载长征八号运载火箭在文昌卫星发射中心成功发射。海丝一号历时一年完成研制,整星重量小于185kg,成像最高分辨率1m,可以全天时、全天候对陆…

章节5 文件与目录管理

5-Linux文件和目录管理 (Linux操作系统-2022的前面章节都为铺垫) 常见命令格式 Command Options Arguments 命令 选项 参数 rm -rf /* -一个字母或字母组合,此选项为短选项,–单词,此选项为长选项 Options选项&…

因果推断 | 双重差分法笔记补充

换了新的环境后,一直在适应(其实是一直被推着走),所以停更了笔记好久啦。这一周周末终于有点得空,当然也是因为疫情,哪里都不能去,哈哈,所以来冒个泡~ 整理了最近pre的作业&#xf…

ESP32-CAM初始篇:Arduino环境搭建-->实现局域网推流

ESP32-CAM初始篇:Arduino环境搭建–>实现局域网推流 入手产品:安信可科技:ESP32-CAM摄像头开发板: 相关产品特性请访问安信可ESP32-CAM官网:https://docs.ai-thinker.com/esp32-cam 第一步:下载Ardui…

基于51单片机数字频率计的设计

目录 前 言 1 第一章 总体设计方案 2 1.1 总设计框图 2 1.2 硬件设计分析 2 1.2.1 电源的设计 2 (4):LCD1602的指令说明及时序 10 (5): LCD1602的RAM地址映射及标准字库表 13 第二章 软件设计与分析 15 2.1…

谷粒商城十一商城系统及整合thymeleaf渲染商城首页

我们的商城系统本应该也是前后端分离的,就像后台管理系统那样,然而出于教学考虑,前后端分离的话就会屏蔽掉很多细节,所以我们进行服务端的页面渲染式开发(有点儿类似freemarker) 这些页面直接粘贴到微服务…

含论文基于JSP的零食销售商城【数据库设计、源码、开题报告】

数据库脚本下载地址: https://download.csdn.net/download/itrjxxs_com/86500759 主要使用技术 ServletJSPcssjsMysqlTomcat 功能介绍 (1)前台功能模块: 注册登陆:顾客可以通过填写注册信息成为会员,登陆后才能进行购物车的管…