網站首頁 編程語言 正文
緩存擊穿
和緩存穿透不同的是,緩存擊穿是指:緩存中沒有,但是數據庫中存在的熱點數據。
例如:首頁的熱點新聞,并發訪問量非常大的熱點數據,如果緩存過期失效,服務器會去查詢DB,這時候如果大量的并發去查詢DB,可能會瞬間壓垮DB。
畫了個簡圖,如下所示:
解決方案:DB查詢加分布式鎖。
未加鎖的情況
解決問題之前,先看一下不做處理的代碼和運行情況。
根據商品ID查詢商品詳情代碼
清空Redis緩存,開啟5個線程去并發訪問測試,測試代碼如下:
我們預期希望DB只查詢一次,后面4個查詢從Redis緩存中取就行,但是結果:
沒有加分布式鎖,結果也在意料之中,但是這樣容器給DB造成很大壓力。
如果是單臺服務器,直接使用Java的同步鎖即可
遺憾的是,通常后端是會部署集群的,Java的同步鎖可沒辦法實現分布式鎖。
Redis分布式鎖解決緩存擊穿
Java的內置鎖只能應用在單臺機器上,無法實現分布式,可以巧用Redis來實現分布式鎖。
加了分布式鎖后的代碼
//根據ID查詢商品 @GetMapping("/{id}") public R id(@PathVariable String id){ //先查Redis緩存 Object o = redisTemplate.opsForValue().get(id); if (o != null) { //命中緩存 System.err.println("id:"+id+",命中redis緩存..."); return R.success(o); } //緩存未命中 查詢數據庫 String lockKey = "lock" + id; //加鎖,10s后過期 for (;;) { if (redisTemplate.opsForValue().setIfAbsent(lockKey, System.currentTimeMillis(), 10L, TimeUnit.SECONDS)) { //加鎖成功的線程,再次檢查 o = redisTemplate.opsForValue().get(id); if (o != null) { //命中緩存 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:"+id+",命中redis緩存..."); //釋放鎖 redisTemplate.delete(lockKey); return R.success(o); } //仍未命中 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:" + id + ",查詢DB..."); Goods goods = goodsMapper.selectById(id); //結果存入Redis redisTemplate.opsForValue().set(id, goods); //釋放鎖 redisTemplate.delete(lockKey); return R.success(goods); } //競爭不到鎖,暫時讓出CPU資源 Thread.yield(); } }
啟動5個線程,并發訪問,結果如下圖:
這里介紹的只是最簡單的方案,實際情況要考慮復雜的多,例如:不能誤解鎖、鎖超時等問題。
原文鏈接:https://blog.csdn.net/qq_32099833/article/details/103848016
- 上一篇:C#實現簡單的計算器功能_C#教程
- 下一篇:C#實現計算器精簡版_C#教程
相關推薦
- 2022-06-06 uniApp、API ‘offCompassChange‘ is not yet implement
- 2022-07-01 Go官方限流器的用法詳解_Golang
- 2022-04-30 python的正則表達式和re模塊詳解_python
- 2022-05-06 Linq中ToList()和CopyToDataTable()用法詳解_實用技巧
- 2022-03-14 golang實現子網掩碼和網絡位長度相互轉換
- 2022-05-24 Python?6種基本變量操作技巧總結_python
- 2022-05-17 Spring Cloud Ribbon詳解
- 2022-03-19 基于React?Hooks的小型狀態管理詳解_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支