网站建设推荐公司,昆明seo关键词,mvc网站开发 案例视频,旅行网站排名前十名文章目录 #x1f339;什么是缓存击穿#x1f33a;基于互斥锁解决问题#x1f6f8;思路 #x1f3f3;️#x1f308;代码实现 #x1f339;什么是缓存击穿
缓存击穿是指在使用缓存系统时#xff0c;对一个热点数据的高并发请求导致缓存失效#xff0c;多个请求同时访… 文章目录 什么是缓存击穿基于互斥锁解决问题思路 ️代码实现 什么是缓存击穿
缓存击穿是指在使用缓存系统时对一个热点数据的高并发请求导致缓存失效多个请求同时访问数据库造成数据库压力过大性能下降。
具体来说缓存击穿通常发生在以下情况下
热点数据失效当某个热点数据的缓存过期或被删除时此时如果有大量的并发请求同时访问该数据缓存系统无法命中缓存每个请求都会直接访问数据库。频繁更新数据某个数据被频繁地修改导致缓存频繁失效而此时大量的请求同时访问该数据造成缓存击穿。
缓存击穿会严重影响系统的性能和可用性因为数据库无法处理如此高的并发请求导致系统响应变慢甚至崩溃。
但是对于缓存击穿我们有什么方法可以解决呢
基于互斥锁解决问题
互斥锁Mutex是一种并发编程中用于保护共享资源的机制它可以确保在同一时刻只有一个线程可以访问共享资源从而避免多个线程同时对共享资源进行读写操作而导致的数据竞争和不确定性行为。
互斥锁的主要特点包括
独占性当一个线程获得了互斥锁后其他线程就无法再获得该互斥锁直到持有该锁的线程释放它。阻塞和等待如果一个线程尝试获取已被其他线程持有的互斥锁那么它会被阻塞直到该互斥锁被释放。原子性互斥锁的获取和释放操作是原子的不会被打断。
互斥锁通常用于以下场景
在多线程环境下保护共享资源如共享变量、共享数据结构等防止多个线程同时修改造成数据不一致。控制对临界区的访问确保同一时间只有一个线程能够执行临界区代码以避免竞态条件Race Condition的发生。
思路
使用互斥锁来解决缓存击穿问题的思路是通过对关键代码块进行加锁保证在同一时间只有一个线程能够执行这段代码。这样可以有效地避免多个线程同时访问数据库减轻数据库的压力提高系统的性能和可用性。
在解决缓存击穿问题时通常会使用互斥锁锁住以下几个关键步骤
检查缓存首先检查缓存中是否存在所需数据。缓存失效处理如果缓存中不存在所需数据即缓存失效需要进行进一步处理。加锁在进行缓存失效处理之前获取互斥锁确保只有一个线程能够执行后续的数据库查询和缓存更新操作。数据查询和缓存更新在成功获得互斥锁之后执行数据库查询操作获取所需数据并将数据更新到缓存中。释放锁缓存更新完成后释放互斥锁允许其他等待的线程获得锁并从缓存中获取数据。
通过加锁的方式保证了同一时间只有一个线程能够执行关键代码块避免了缓存击穿问题。其他线程在等待期间可以从缓存中获取旧数据而不会直接访问数据库。这样可以减少数据库的并发访问压力提升了系统的并发能力和性能。
需要注意的是互斥锁的使用应该谨慎避免持有锁的时间过长否则可能会导致其他线程的延迟和性能下降。在设计时要权衡锁的粒度和性能需求确保互斥锁的使用场景合理并根据具体情况选择合适的锁机制如读写锁、分布式锁等进行优化。
️代码实现
我们看下面的例子 Service
public class ShopServiceImpl extends ServiceImplShopMapper, Shop implements IShopService {Resourceprivate StringRedisTemplate stringRedisTemplate;Overridepublic Result queryById(Long id) {//缓存穿透
// Shop shopqueryWithPassThrough(id);//互斥锁解决缓存击穿Shop shopqueryWithMutex(id);if(shopnull){return Result.fail(店铺不存在);}//返回return Result.ok(shop);}public Shop queryWithMutex(Long id){String keyCACHE_SHOP_KEY:id;//从redis中查询缓存String shopJsonstringRedisTemplate.opsForValue().get(key);//判断是否存在if(StrUtil.isNotBlank(shopJson)){//存在直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断命中的是否是空值if(shopJson!null){//返回一个错误信息return null;}//实现缓存重建//获取互斥锁String lockKeylock:shopid;Shop shopnull;try {boolean isLocktryLock(lockKey);//判断是否获取成功if (!isLock){//失败那么休眠并且重试Thread.sleep(100);return queryWithMutex(id);}//成功则根据id查询数据库shopgetById(id);//不存在返回错误if(shopnull){//将空值写入到redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);return null;}//存在写入到redis里面stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);}catch (Exception e){throw new RuntimeException(e);}finally {//释放互斥锁unlock(lockKey);}//返回return shop;}//存在写入到redis里面stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);//返回return shop;}//获取锁private boolean tryLock(String key){Boolean flag stringRedisTemplate.opsForValue().setIfAbsent(key, 1, 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}//释放锁private void unlock(String key){stringRedisTemplate.delete(key);}
}在技术的道路上我们不断探索、不断前行不断面对挑战、不断突破自我。科技的发展改变着世界而我们作为技术人员也在这个过程中书写着自己的篇章。让我们携手并进共同努力开创美好的未来愿我们在科技的征途上不断奋进创造出更加美好、更加智能的明天