成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Redis實(shí)現(xiàn)廣告緩存、并完善緩存擊穿

KitorinZero / 2185人閱讀

摘要:完善緩存擊穿問題問題描述,分布式場景中,有時(shí)候存在高并發(fā)訪問,比如秒殺活動。在高并發(fā)訪問下請求全部懟到數(shù)據(jù)庫,可能導(dǎo)致數(shù)據(jù)庫掛掉,這就是緩存擊穿。緩存擊穿解決方案已經(jīng)能解決日常情況,但還是有一定提升的空間的。

“做人、做程序,變則通,不變只能一直死循環(huán)下去”      ————尼古斯拉
Docker安裝官方Redis

參考文章:Docker安裝官方Redis鏡像并啟用密碼認(rèn)證

拉取最新版的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

查看進(jìn)程: ps -ef|grep redis

進(jìn)入容器執(zhí)行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通即可正常使用,這個(gè)例子比起原先方式,省去了編譯、配置、開機(jī)啟動服務(wù)一大堆麻煩。docker就是好,docker就是棒,docker頂呱呱。

廣告緩存功能的實(shí)現(xiàn) 添加依賴

    org.springframework.boot
    spring-boot-starter-data-redis
    2.1.3.RELEASE
添加配置
# Redis服務(wù)器地址
spring.redis.host=yourhost
# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=xxxx
# Redis數(shù)據(jù)庫索引(默認(rèn)為0)
spring.redis.database=0
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
spring.redis.jedis.pool.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.jedis.pool.max-idle=8
# 連接池中的最小空閑連接
spring.redis.jedis.pool.min-idle=0
# 連接超時(shí)時(shí)間(毫秒)
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("緩存未命中,執(zhí)行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;
    }
}
功能測試、調(diào)錯(cuò)

首次請求:

二次請求、多次請求:

Tips:

有時(shí)會報(bào)redis連接超時(shí)connect timed out,把鏈接超時(shí)時(shí)間改大一點(diǎn)就好了,建議200以上,一個(gè)小bug,不作過多闡述。
完善緩存擊穿問題

問題描述,分布式場景中,有時(shí)候存在高并發(fā)訪問,比如秒殺活動?;蚴怯泻诳兔看喂室獠樵円粋€(gè)在緩存內(nèi)必然不存在的數(shù)據(jù),導(dǎo)致每次請求都要去存儲層去查詢,這樣緩存就失去了意義。在高并發(fā)訪問下請求全部懟到數(shù)據(jù)庫,可能導(dǎo)致數(shù)據(jù)庫掛掉,這就是緩存擊穿。
場景如下圖所示:

方法一:使用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("緩存未命中,執(zhí)行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;
}

方法二:使用互斥鎖

@Override    
    public Object contentList(Long cid) throws Exception {        
        String test= (String) redis.opsForHash().get("ContentList", cid.toString());        
        if(test==null) {
            System.out.println("緩存未命中,執(zhí)行SQL");
            if(redis.opsForValue().setIfAbsent("key", "value")){ 
                redis.expire("key", 30000, TimeUnit.MILLISECONDS);
                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);
                redis.delete("key");
                return test;
            }
        }
        System.out.println("緩存命中,直接使用");
        return test;
    }

方法二原理就第一個(gè)請求進(jìn)來執(zhí)行redis.opsForValue().setIfAbsent("key", "value")沒有值為true才執(zhí)行業(yè)務(wù)邏輯。如果沒有執(zhí)行完業(yè)務(wù)邏輯、delete("key")。第二個(gè)請求就會查到有值為flase,那是進(jìn)不去的,相當(dāng)于被鎖住了。
使用redis.expire("key", 30000, TimeUnit.MILLISECONDS)為了防止調(diào)用setIfAbsent方法之后線程掛掉了,沒有執(zhí)行到delete("key")這一步。這樣的話,如果沒有給鎖設(shè)置過期的時(shí)間,默認(rèn)會永不過期。那么這個(gè)鎖就會一直存在,想查庫也查不到了。

評價(jià):這兩個(gè)解決方案已經(jīng)能應(yīng)對日程大部分情況。方案一一存在一定性能損耗,方案二在極端情況下有死鎖的可能性,那么還是使用方案二吧。

完善數(shù)據(jù)同步的問題

問題描述:如果廣告內(nèi)容改變了,即數(shù)據(jù)庫內(nèi)容已經(jīng)改變的,但請求還是從原來的緩存里拿數(shù)據(jù),這顯然是不對的,所以我們更改數(shù)據(jù)庫時(shí)要把緩存清一清。

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, "添加成功");
    }
總結(jié)

這個(gè)小案例碰到了不少問題,值得一提的是在云上安裝redis安裝了好幾次都不對,最后改用docker才安成了,做程序還是得學(xué)會靈活變通呀。緩存擊穿解決方案已經(jīng)能解決日常99.9%情況,但還是有一定提升的空間的。加油吧,騷年。
最后,寫這樣一篇文章真的好費(fèi)時(shí)間,有緣人記得點(diǎn)贊哦,筆芯!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/27689.html

相關(guān)文章

  • redis相關(guān)問題

    摘要:若其他線程發(fā)現(xiàn)獲取鎖失敗,則睡眠后重試。容易造成死鎖問題布隆過濾器,迅速判斷一個(gè)元素是否在一個(gè)集合中。將已存在的緩存放到布隆過濾器中,當(dāng)黑客訪問不存在的緩存時(shí)迅速返回避免緩存及掛掉。 redis理解 A.執(zhí)行流程 showImg(https://user-gold-cdn.xitu.io/2019/1/11/1683aabdeb2fcc3a); 緩存雪崩 showImg(https:/...

    mist14 評論0 收藏0
  • Redis 分布式鎖--PHP

    摘要:分布式鎖的作用在單機(jī)環(huán)境下,有個(gè)秒殺商品的活動,在短時(shí)間內(nèi),服務(wù)器壓力和流量會陡然上升。分布式集群業(yè)務(wù)業(yè)務(wù)場景下,每臺服務(wù)器是獨(dú)立存在的。這里就用到了分布式鎖這里簡單介紹一下,以的事務(wù)機(jī)制來延生。 Redis 分布式鎖的作用 在單機(jī)環(huán)境下,有個(gè)秒殺商品的活動,在短時(shí)間內(nèi),服務(wù)器壓力和流量會陡然上升。這個(gè)就會存在并發(fā)的問題。想要解決并發(fā)需要解決以下問題 1、提高系統(tǒng)吞吐率也就是qps 每...

    canger 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<