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

谷粒商城-redis分布式锁系列

1.压力测试出的内存泄漏及解决(可跳过)

使用jmeter对查询产品分类列表接口进行压力测试,出现了堆外内存溢出异常。
在这里插入图片描述
我们设置的虚拟机堆内存100m,并不是堆外内存100m
在这里插入图片描述
产生堆外内存溢出:OutOfDirectMemoryError
原因是因为:
springboot2.0以后默认使用lettuce作为操作redis的客户端。它使用netty进行网络通信。
lettuce的bug导致netty堆外内存溢出,-Xmx300m, netty如果没有指定堆外内存,默认使用-Xmx300m作为堆外内存。
由于在高并发的时候,获取的数据量非常大,高并发一进来,由于数据在传输期间都要占内存,导致内存分配不足,堆外内存溢出。

解决方案:不能使用-Dio.netty.maxDirectoryMemory只去调大堆外内存(只是延缓了问题的出现)
1)、升级lettuce客户端, 2)、切换使用Jedis
lettuce,jedis操作redis的底层客户端,spring再次封装redisTemplate

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

2.高并发下缓存失效的问题

2.1.缓存穿透

缓存穿透: 指查询一个一定不存在的数据,由于缓存是不命中,将去查询数据库,但是 数据库也无此记录,我们没有将这次查询的null写入缓存,这将导致这个不 存在的数据每次请求都要到存储层去查询,失去了缓存的意义
在这里插入图片描述

风险: 利用不存在的数据进行攻击,数据库瞬时压力增大,最终导致崩溃

解决: null结果缓存,并加入短暂过期时间

2.2.缓存雪崩

缓存雪崩: 缓存雪崩是指在我们设置缓存时key采用了相同的过期时间, 导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时 压力过重雪崩。
在这里插入图片描述

解决: 原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这 样每一个缓存的过期时间的重复率就会降低,就很难引发集体 失效的事件。

2.3.缓存击穿

缓存穿透:

  • 对于一些设置了过期时间的key,如果这些key可能会在某些 时间点被超高并发地访问,是一种非常“热点”的数据。
  • 如果这个key在大量请求同时进来前正好失效,那么所有对 这个key的数据查询都落到db,我们称为缓存击穿。
    在这里插入图片描述

解决: 加锁大量并发只让一个去查,其他人等待,查到以后释放锁,其他 人获取到锁,先查缓存,就会有数据,不用去db

 * 1.空结果缓存,解决缓存穿透
 * 2.设置过期时间(加随机值),解决缓存雪崩
 * 3.加锁,解决缓存击穿

前两个都好解决,对于加锁的问题,如果锁没加好,又会有新的问题

直接加synchronized锁

// 只要是同一把锁,就能锁住需要这个锁的所有线程
// 1.synchronized(this):,springboot所有组件(这里是CategoryServiceImpl)在容器中都是单例的
// TODO 本地锁,syncrhonized, JUC(Lock) 分布式情况下,想要锁住所有,必须使用分布式锁
synchronized (this) {
   return getDataFromDb();
}

得到锁以后,应该再去缓存中确定一次,如果没有才需要继续查询。

String catelogJSON = stringRedisTemplate.opsForValue().get("catelogJSON");
if (!StringUtils.isEmpty(catelogJSON)) {
    // 如果缓存不为空,直接返回
    Map<String, List<Catelog2Vo>> result = JSON.parseObject(catelogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() {});
    return result;
}

分布式下如何加锁
在这里插入图片描述
TODO 本地锁,syncrhonized, JUC(Lock) 分布式情况下,想要锁住所有,必须使用分布式锁

注意锁的时序问题
在这里插入图片描述
要保证查数据库和把结果放入缓存是原子操作,是在同一把锁内进行的,否则就会导致释放锁的时序问题,导致多次查询数据库。
开启多个服务的时候只能锁住本地服务
在这里插入图片描述

3.分布式锁的原理与使用

分布式锁演进-基本原理
在这里插入图片描述
我们可以同时去一个地方“占坑”,如果占到,就执行逻辑。否则就必须等待,直到释放锁。 “占坑”可以去redis,可以去数据库,可以去任何大家都能访问的地方。 等待可以自旋的方式。

占坑在redis中通常使用set命令,set的介绍如下:
https://www.cnblogs.com/zhouj850/p/10949359.html
SET key value [EX seconds] [PX milliseconds] [NX|XX]
设置k-v值
EX过期时间,PX毫秒,NX指的是Not Exist,不存在才给里面放。
所以使用SETNX命令可以进行占坑操作。

在这里插入图片描述


http://www.kler.cn/a/6202.html

相关文章:

  • Windows 11 系统中npm-cache优化
  • WeNet:面向生产的流式和非流式端到端语音识别工具包
  • 吾杯网络安全技能大赛——Misc方向WP
  • HAL 库------中断相关函数
  • LeetCode-最长公共前缀(014)
  • 机械臂的各种标定
  • Linux环境变量、Linux自定义设置环境变量
  • 核心 Android 调节音量的过程
  • 关于层序遍历的九道题
  • Linux命令·wc
  • 蓝桥杯3月刷题集训-A 【枚举模拟】Day3
  • 【基础算法】哈希表
  • 定点乘法器----部分积压缩(华为杯)
  • volatile、synchronize的特点和区别
  • python_接口自动化测试框架
  • 都说IT行业饱和了,2023年成为程序员还有发展前景吗?
  • 《Effective Objective-C 2.0 》 阅读笔记 item10
  • 从大到小排序-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第3章-课后作业)
  • 第6章 封装组件高级篇(下) - table
  • 【经验】PCB拼板,不得不注意的10个问题,要收藏哦!
  • MySQL-事务
  • spark sql(五)sparksql支持查询哪些数据源,查询hive与查询mysql的区别
  • 【新2023Q2模拟题JAVA】华为OD机试 - 二叉树层次遍历
  • Linux下 lsof 命令详解
  • 文件系统设计详解
  • 蓝桥杯第21天(Python)(疯狂刷题第4天)