在生產(chǎn)時不要使用哪些redis指令

這篇文章將為大家詳細(xì)講解有關(guān)在生產(chǎn)時不要使用哪些redis指令,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)建站服務(wù)項目包括思明網(wǎng)站建設(shè)、思明網(wǎng)站制作、思明網(wǎng)頁制作以及思明網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,思明網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到思明省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

問題原因

小黑哥負(fù)責(zé)的應(yīng)用是一個管理后臺應(yīng)用,權(quán)限管理使用 Shiro 框架,由于存在多個節(jié)點,需要使用分布式 Session,于是這里使用 Redis 存儲 Session 信息。

畫外音:不知道分布式 Session ,可以看看小黑哥之前寫的 一口氣說出 4 種分布式一致性 Session 實現(xiàn)方式,面試杠杠的~

由于 Shiro 并沒有直接提供 Redis 存儲 Session 組件,小黑哥不得不使用 Github 一個開源組件 shiro-redis。

由于 Shiro 框架需要定期驗證 Session 是否有效,于是 Shiro 底層將會調(diào)用 SessionDAO#getActiveSessions 獲取所有的 Session 信息。

shiro-redis 正好繼承 SessionDAO 這個接口,底層使用用 keys 命令查找 Redis 所有存儲的 Session key。

public Set<byte[]> keys(byte[] pattern){
    checkAndInit();
    Set<byte[]> keys = null;
    Jedis jedis = jedisPool.getResource();
    try{
        keys = jedis.keys(pattern);
    }finally{
        jedis.close();
    }
    return keys;
}

找到問題原因,解決辦法就比較簡單了,github 上查找到解決方案,升級一下 shiro-redis 到最新版本。

在這個版本,shiro-redis 采用 scan命令代替 keys,從而修復(fù)這個問題。

public Set<byte[]> keys(byte[] pattern) {
    Set<byte[]> keys = null;
    Jedis jedis = jedisPool.getResource();

    try{
        keys = new HashSet<byte[]>();
        ScanParams params = new ScanParams();
        params.count(count);
        params.match(pattern);
        byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
        ScanResult<byte[]> scanResult;
        do{
            scanResult = jedis.scan(cursor,params);
            keys.addAll(scanResult.getResult());
            cursor = scanResult.getCursorAsBytes();
        }while(scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
    }finally{
        jedis.close();
    }
    return keys;

}

雖然問題成功解決了,但是小黑哥心里還是有點不解。

為什么 keys 指令會導(dǎo)致其他命令執(zhí)行變慢?

為什么 Keys 指令查詢會這么慢?

為什么 Scan 指令就沒有問題?

Redis 執(zhí)行命令的原理

首先我們來看第一個問題,為什么 keys 指令會導(dǎo)致其他命令執(zhí)行變慢?

回答這個問題,我們首先看下 Redis 客戶端執(zhí)行一條命令的情況:

在生產(chǎn)時不要使用哪些redis指令

站在客戶端的視角,執(zhí)行一條命令分為三步:

  1. 發(fā)送命令

  2. 執(zhí)行命令

  3. 返回結(jié)果

但是這僅僅客戶端自己以為的過程,但是實際上同一時刻,可能存在很多客戶端發(fā)送命令給 Redis,而 Redis 我們都知道它采用的是單線程模型。

為了處理同一時刻所有的客戶端的請求命令,Redis 內(nèi)部采用了隊列的方式,排隊執(zhí)行。

在生產(chǎn)時不要使用哪些redis指令

于是客戶端執(zhí)行一條命令實際需要四步:

  1. 發(fā)送命令

  2. 命令排隊

  3. 執(zhí)行命令

  4. 返回結(jié)果

由于 Redis 單線程執(zhí)行命令,只能順序從隊列取出任務(wù)開始執(zhí)行。

只要 3 這個過程執(zhí)行命令速度過慢,隊列其他任務(wù)不得不進(jìn)行等待,這對外部客戶端看來,Redis 好像就被阻塞一樣,一直得不到響應(yīng)。

所以使用 Redis 過程切勿執(zhí)行需要長時間運行的指令,這樣可能導(dǎo)致 Redis 阻塞,影響執(zhí)行其他指令。

KEYS 原理

接下來開始回答第二個問題,為什么 Keys 指令查詢會這么慢?

回答這個問題之前,請大家回想一下 Redis 底層存儲結(jié)構(gòu)。

不太清楚朋友的也沒關(guān)系,大家可以回看一下小黑哥之前的文章「阿里面試官:HashMap 熟悉吧?好的,那就來聊聊 Redis 字典吧!」。

這里小黑哥復(fù)制之前文章內(nèi)容,Redis 底層使用字典這種結(jié)構(gòu),這個結(jié)構(gòu)與 Java HashMap 底層比較類似。

在生產(chǎn)時不要使用哪些redis指令

keys命令需要返回所有的符合給定模式 pattern 的 Redis 中鍵,為了實現(xiàn)這個目的,Redis 不得不遍歷字典中 ht[0]哈希表底層數(shù)組,這個時間復(fù)雜度為 O(N)(N 為 Redis 中 key 所有的數(shù)量)。

如果 Redis 中 key 的數(shù)量很少,那么這個執(zhí)行速度還是也會很快。等到 Redis key 的數(shù)量慢慢更加,上升到百萬、千萬、甚至上億級別,那這個執(zhí)行速度就會很慢很慢。

下面是小黑哥本地做的一次實驗,使用 lua 腳本往 Redis 中增加 10W 個 key,然后使用 keys 查詢所有鍵,這個查詢大概會阻塞十幾秒的時間。

eval "for i=1,100000  do redis.call('set',i,i+1) end" 0

這里小黑哥使用 Docker 部署 Redis,性能可能會稍差。

SCAN 原理

最后我們來看下第三個問題,為什么 scan 指令就沒有問題?

這是因為 scan命令采用一種黑科技-基于游標(biāo)的迭代器。

每次調(diào)用 scan 命令,Redis 都會向用戶返回一個新的游標(biāo)以及一定數(shù)量的 key。下次再想繼續(xù)獲取剩余的 key,需要將這個游標(biāo)傳入 scan 命令, 以此來延續(xù)之前的迭代過程。

簡單來講,scan 命令使用分頁查詢 redis 。

下面是一個 scan 命令的迭代過程示例:

scan 命令使用游標(biāo)這種方式,巧妙將一次全量查詢拆分成多次,降低查詢復(fù)雜度。

雖然 scan 命令時間復(fù)雜度與 keys一樣,都是 O(N),但是由于 scan 命令只需要返回少量的 key,所以執(zhí)行速度會很快。

最后,雖然scan 命令解決 keys不足,但是同時也引入其他一些缺陷:

  • 同一個元素可能會被返回多次,這就需要我們應(yīng)用程序增加處理重復(fù)元素功能。

  • 如果一個元素在迭代過程增加到 redis,或者說在迭代過程被刪除,那個這個元素會被返回,也可能不會。

以上這些缺陷,在我們開發(fā)中需要考慮這種情況。

除了 scan以外,redis 還有其他幾個用于增量迭代命令:

  • sscan:用于迭代當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù)庫鍵,用于解決 smembers 可能產(chǎn)生阻塞問題

  • hscan命令用于迭代哈希鍵中的鍵值對,用于解決 hgetall 可能產(chǎn)生阻塞問題。

  • zscan:命令用于迭代有序集合中的元素(包括元素成員和元素分值),用于產(chǎn)生 zrange 可能產(chǎn)生阻塞問題。

關(guān)于“在生產(chǎn)時不要使用哪些redis指令”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

文章名稱:在生產(chǎn)時不要使用哪些redis指令
文章出自:http://www.muchs.cn/article38/piegsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)服務(wù)器托管、面包屑導(dǎo)航、營銷型網(wǎng)站建設(shè)企業(yè)建站、網(wǎng)站設(shè)計公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計公司