国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Redis實現廣告緩存、并完善緩存擊穿

KitorinZero / 2159人閱讀

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

“做人、做程序,變則通,不變只能一直死循環下去”      ————尼古斯拉
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);
        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("緩存未命中,執行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;
    }

方法二原理就第一個請求進來執行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相關問題

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

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

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

    canger 評論0 收藏0

發表評論

0條評論

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