摘要:完善緩存擊穿問題問題描述,分布式場景中,有時候存在高并發訪問,比如秒殺活動。在高并發訪問下請求全部懟到數據庫,可能導致數據庫掛掉,這就是緩存擊穿。緩存擊穿解決方案已經能解決日常情況,但還是有一定提升的空間的。
“做人、做程序,變則通,不變只能一直死循環下去” ————尼古斯拉Docker安裝官方Redis
參考文章:Docker安裝官方Redis鏡像并啟用密碼認證
拉取最新版的redis鏡像:docker pull redis:latest
啟動容器并帶密碼:
docker run --name redis-test -p 6379:6379 -d --restart=always redis:latest redis-server --appendonly yes --requirepass "your passwd"
查看容器、注意看id: docker ps
查看進程: ps -ef|grep redis
進入容器執行redis客戶端:
docker exec -it a126ec987cfe redis-cli -h yourhost -p 6379 -a "your passwd" 127.0.0.1:6379> ping PONG 127.0.0.1:6379> info ...
能ping通即可正常使用,這個例子比起原先方式,省去了編譯、配置、開機啟動服務一大堆麻煩。docker就是好,docker就是棒,docker頂呱呱。
廣告緩存功能的實現 添加依賴添加配置org.springframework.boot spring-boot-starter-data-redis 2.1.3.RELEASE
# Redis服務器地址 spring.redis.host=yourhost # Redis服務器連接端口 spring.redis.port=6379 # Redis服務器連接密碼(默認為空) spring.redis.password=xxxx # Redis數據庫索引(默認為0) spring.redis.database=0 # 連接池最大連接數(使用負值表示沒有限制) spring.redis.jedis.pool.max-active=8 # 連接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.jedis.pool.max-wait=-1 # 連接池中的最大空閑連接 spring.redis.jedis.pool.max-idle=8 # 連接池中的最小空閑連接 spring.redis.jedis.pool.min-idle=0 # 連接超時時間(毫秒) spring.redis.timeout=0緩存功能核心邏輯代碼
@Service public class ContentServiceImpl implements ContentService { @Autowired private ContentMapper contentMapper; @Autowired private StringRedisTemplate redis; @Override public Object contentList(Long cid) throws Exception { String test= (String) redis.opsForHash().get("ContentList", cid.toString()); if(test==null) { System.out.println("緩存未命中,執行SQL"); ContentExample example=new ContentExample(); example.createCriteria().andCategoryIdEqualTo(cid); List功能測試、調錯list=contentMapper.selectByExample(example); test=new ObjectMapper().writeValueAsString(list); redis.opsForHash().put("ContentList", cid.toString(), test); return test; } System.out.println("緩存命中,直接使用"); return test; } }
首次請求:
二次請求、多次請求:
Tips:
有時會報redis連接超時connect timed out,把鏈接超時時間改大一點就好了,建議200以上,一個小bug,不作過多闡述。完善緩存擊穿問題
問題描述,分布式場景中,有時候存在高并發訪問,比如秒殺活動。或是有黑客每次故意查詢一個在緩存內必然不存在的數據,導致每次請求都要去存儲層去查詢,這樣緩存就失去了意義。在高并發訪問下請求全部懟到數據庫,可能導致數據庫掛掉,這就是緩存擊穿。
場景如下圖所示:
方法一:使用synchronized
public Object contentList(Long cid) throws Exception { String test= null; synchronized (redis) { test=(String) redis.opsForHash().get("ContentList", cid.toString()); } if(test==null) { System.out.println("緩存未命中,執行SQL"); ContentExample example=new ContentExample(); example.createCriteria().andCategoryIdEqualTo(cid); Listlist=contentMapper.selectByExample(example); test=new ObjectMapper().writeValueAsString(list); redis.opsForHash().put("ContentList", cid.toString(), test); return test; } System.out.println("緩存命中,直接使用"); return test; }
方法二:使用互斥鎖
@Override public Object contentList(Long cid) throws Exception { String test= (String) redis.opsForHash().get("ContentList", cid.toString()); if(test==null) { System.out.println("緩存未命中,執行SQL"); if(redis.opsForValue().setIfAbsent("key", "value")){ redis.expire("key", 30000, TimeUnit.MILLISECONDS); ContentExample example=new ContentExample(); example.createCriteria().andCategoryIdEqualTo(cid); Listlist=contentMapper.selectByExample(example); test=new ObjectMapper().writeValueAsString(list); redis.opsForHash().put("ContentList", cid.toString(), test); redis.delete("key"); return test; } } System.out.println("緩存命中,直接使用"); return test; }
方法二原理就第一個請求進來執行redis.opsForValue().setIfAbsent("key", "value")沒有值為true才執行業務邏輯。如果沒有執行完業務邏輯、delete("key")。第二個請求就會查到有值為flase,那是進不去的,相當于被鎖住了。
使用redis.expire("key", 30000, TimeUnit.MILLISECONDS)為了防止調用setIfAbsent方法之后線程掛掉了,沒有執行到delete("key")這一步。這樣的話,如果沒有給鎖設置過期的時間,默認會永不過期。那么這個鎖就會一直存在,想查庫也查不到了。
評價:這兩個解決方案已經能應對日程大部分情況。方案一一存在一定性能損耗,方案二在極端情況下有死鎖的可能性,那么還是使用方案二吧。
完善數據同步的問題問題描述:如果廣告內容改變了,即數據庫內容已經改變的,但請求還是從原來的緩存里拿數據,這顯然是不對的,所以我們更改數據庫時要把緩存清一清。
public Object contentSave(Content content) { Date date =new Date(); content.setCreated(date); content.setUpdated(date); contentMapper.insert(content); redis.delete("ContentList"); return Result.of(200, "添加成功"); }總結
這個小案例碰到了不少問題,值得一提的是在云上安裝redis安裝了好幾次都不對,最后改用docker才安成了,做程序還是得學會靈活變通呀。緩存擊穿解決方案已經能解決日常99.9%情況,但還是有一定提升的空間的。加油吧,騷年。
最后,寫這樣一篇文章真的好費時間,有緣人記得點贊哦,筆芯!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/27689.html
摘要:分布式鎖的作用在單機環境下,有個秒殺商品的活動,在短時間內,服務器壓力和流量會陡然上升。分布式集群業務業務場景下,每臺服務器是獨立存在的。這里就用到了分布式鎖這里簡單介紹一下,以的事務機制來延生。 Redis 分布式鎖的作用 在單機環境下,有個秒殺商品的活動,在短時間內,服務器壓力和流量會陡然上升。這個就會存在并發的問題。想要解決并發需要解決以下問題 1、提高系統吞吐率也就是qps 每...
閱讀 540·2021-08-31 09:45
閱讀 1647·2021-08-11 11:19
閱讀 883·2019-08-30 15:55
閱讀 821·2019-08-30 10:52
閱讀 2845·2019-08-29 13:11
閱讀 2924·2019-08-23 17:08
閱讀 2833·2019-08-23 15:11
閱讀 3066·2019-08-23 14:33