用互斥锁解决缓存击穿问题
创作时间:
作者:
@小白创作中心
用互斥锁解决缓存击穿问题
引用
CSDN
1.
https://blog.csdn.net/hguhbh/article/details/139521951
缓存击穿是高并发系统中常见的问题之一,它通常发生在热点数据的缓存失效时,导致大量请求直接打到数据库,造成数据库压力剧增。本文将详细介绍如何使用互斥锁(Mutex)来解决缓存击穿问题,并通过实际代码和性能测试验证解决方案的有效性。
在高并发场景下,一个被频繁访问的缓存数据(热点key)突然失效,如果没有有效的防护措施,大量请求会直接冲击数据库,导致数据库负载激增,甚至引发系统崩溃。为了解决这一问题,本文将介绍使用互斥锁(Mutex)的解决方案。
缓存击穿问题概述
缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务复杂的存储在redis中的key突然失效,无数请求就会瞬间打到数据库造成巨大冲击。
解决方案:互斥锁
互斥锁是一种常用的解决方案,其核心思想是:当一个线程获取到互斥锁时,其他线程必须等待,直到锁被释放。这样可以确保在缓存重建期间,只有一个线程负责查询数据库并更新缓存,其他线程则等待或返回旧数据。
代码实现
我们使用Redis的setnx命令来实现互斥锁,该命令只有在key不存在时才会创建成功,若key已存在就会创建失败。
private boolean tryLock(String key) {
//参数分别是,key,value,过期时间,过期时间的单位
//这里过期时间用事先写的静态变量,10L
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", LOCK_SHOP_TTL, TimeUnit.SECONDS);
return BooleanUtil.isTrue(flag); //如果直接返回flag,当flag为null时,会做拆箱,报错空指针。
}
private void UnLock(String key) {
stringRedisTemplate.delete(key);
}
接下来,我们在服务层实现具体的缓存重建逻辑:
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public Result queryById(Long id) {
//用互斥锁解决缓存击穿
Shop shop = queryWithMutex(id);
if (shop == null) {
return Result.fail("店铺不存在");
}
return Result.ok(shop);
}
public Shop queryWithMutex(Long id) {
//1.从redis查询数据缓存
String key = CACHE_SHOP_KEY + id;
String shopJson = stringRedisTemplate.opsForValue().get(key);
//2.判断是否存在
if (StrUtil.isNotBlank(shopJson)) { //isNotBlank方法只有有值字符串才会返回true,null和空值都会返回false
//3.存在,返回
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return shop;
}
//shopJson不存在
//判断查到的数据是否为空值(这个空值指的不是null,是空字符串)
if (shopJson != null) {
//返回错误信息
return null;
}
//4实现缓存重建
//4.1获取互斥锁
String lockKey = LOCK_SHOP_KEY + id;
boolean lock = tryLock(lockKey);
//4.2判断是否获取成功
Shop shop = null;
try {
if (!lock) {
//4.3失败,休眠并重试
Thread.sleep(50);
return queryWithMutex(id);
}
//4.4成功,根据id查询数据库
shop = getById(id);
//模拟数据库重建的延时
Thread.sleep(200);
//5.不存在,返回错误
if (shop == null) {
//将空值缓存到redis
stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
return null;
}
//6.存在,写入redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//7.释放互斥锁
UnLock(lockKey);
}
//8.返回
return shop;
}
}
性能测试
为了验证解决方案的有效性,我们使用JMeter进行压力测试。开启100个线程进行测试,结果所有请求都成功了。通过查看控制台日志,可以发现只查询了一次数据库,这说明互斥锁机制成功地防止了缓存击穿。
总结
通过使用互斥锁,我们可以有效地解决缓存击穿问题。虽然这种方法可能会带来一定的性能开销,但在高并发场景下,它能够显著降低数据库的压力,保障系统的稳定运行。在实际应用中,还可以结合其他策略(如逻辑过期时间)来进一步优化解决方案。
热门推荐
刹车油真假辨别攻略,保障你的行车安全!
DOT4刹车油检查,守护行车安全
真假刹车油大揭秘:保障行车安全
索纳塔车主必看:刹车油更换秘籍
葫芦娃能力暗合五行,蛇精竟是佛门弟子?
简单几步做出美味炒墨鱼,家庭聚餐必备佳肴
从炒到炖:四种墨鱼家常菜的详细制作教程
墨鱼汤养生正当时:从脾胃调理到女性养颜全覆盖
1952年伦敦烟雾事件致4000死,泰晤士报揭示真相推动环保觉醒
欧元特性与汇率决定因素详解
补体C4偏低的五种治疗方案,医生这样建议
免疫球蛋白与补体:解读人体重要免疫指标的临床意义
王守国医生教你:冬季骨折康复的饮食指南
李伟骨折康复食疗秘籍大公开
大坪周治如骨科教你骨折康复饮食
冬季骨折高发,这份康复食谱请收好!
集合:高考数学的基础概念与解题要点
康托尔集合论开创现代数学,连续统假设影响百年
集合概念详解:从基础理论到高考实战
从命题逻辑到人工智能:集合论的跨学科应用
央行开展1200亿国库现金定存,中标利率降至2.16%
国库现金定存利率再降12个bp,央行释放降准信号
望梅止渴等30个成语,带你读懂世说新语
商务眼神交流完全指南:场景应用与文化差异
美国人的“OK”手势,在其他国家可能很“冒犯”
热情但不逾矩:美国人的肢体语言特点
石门栈道景区:汉中最美的自然景观推荐
孙俪都市剧《蛮好的人生》来袭,汪俊执导,但看到男主我心情复杂
为何中国父母的爱,总让孩子痛苦和愧疚?
懂比爱更重要:如何缓解青春期孩子的逆反心理?