Redis進階-如何從海量的 key 中找出特定的key列表

在這裏插入圖片描述


需求

假設你需要從 Redis 實例成千上萬的 key 中找出特定前綴的 key 列表來手動處理數據,可能是修改它的值,也可能是刪除 key。那該如何從海量的 key 中找出滿足特定前綴的 key 列表來?

我們可以用 keys 來列出所有滿足特定正則字符串規則的 key .

192.168.18.131:8001> set artisan 1
OK
192.168.18.131:8001> set artisan2 2
-> Redirected to slot [6066] located at 192.168.18.132:8002
OK
192.168.18.132:8002> set artisan3 3
-> Redirected to slot [1939] located at 192.168.18.131:8001
OK
192.168.18.131:8001> set artisan4 4
-> Redirected to slot [14196] located at 192.168.18.132:8005
OK
192.168.18.132:8005> set artisan5 5
-> Redirected to slot [10069] located at 192.168.18.132:8002
OK
192.168.18.132:8002> 

192.168.18.132:8002> keys *
1) "artisanKey"
2) "clusterArtisan"
3) "artisan2"
4) "ar"
5) "test"
6) "artisan5"
192.168.18.132:8002> keys artisan*
1) "artisanKey"
2) "artisan2"
3) "artisan5"
192.168.18.132:8002> 

我這個是集羣環境,有幾個key被分到了其他的slot上去了,所以看到的數據僅僅是當前slot的數據。

keys 優點呢 ,使用簡單

當然了,也有缺點

  • 一次性列出所有滿足條件的 key. keys 算法是遍歷算法,複雜度是 O(n) ,如果數據量很大,會導致 Redis 服務卡頓,所有讀寫 Redis 的其它的指令都會被延後甚至會超時報錯,因爲Redis 是單線程程序,順序執行所有指令,其它指令必須等到當前的 keys 指令執行完了纔可以繼續。

咋辦呢? ---------------> Redis在 2.8 版本中加入了scan指令.


scan

scan 相比keys 具備有以下特點:

  • 複雜度雖然也是 O(n),但是它是通過遊標分步進行的,不會阻塞線程;
  • 提供 limit 參數,可以控制每次返回結果的最大條數,limit 只是一個 hint,返回的結果可多可少;
  • 同 keys 一樣,它也提供模式匹配功能;
  • 服務器不需要爲遊標保存狀態,遊標的唯一狀態就是 scan 返回給客戶端的遊標整數;
  • 返回的結果可能會有重複,需要客戶端去重複,這點非常重要;
  • 遍歷的過程中如果有數據修改,改動後的數據能不能遍歷到是不確定的;
  • 單次返回的結果是空的並不意味着遍歷結束,而要看返回的遊標值是否爲零

scan基本使用

批量寫入一批模擬數據


import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;


public class JedisClusterDemo {
    public static void main(String[] args) throws IOException {

        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(20);
        config.setMaxIdle(10);
        config.setMinIdle(5);

        Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
        jedisClusterNode.add(new HostAndPort("192.168.18.131", 8001));
        jedisClusterNode.add(new HostAndPort("192.168.18.131", 8004));
        jedisClusterNode.add(new HostAndPort("192.168.18.132", 8002));
        jedisClusterNode.add(new HostAndPort("192.168.18.132", 8005));
        jedisClusterNode.add(new HostAndPort("192.168.18.133", 8003));
        jedisClusterNode.add(new HostAndPort("192.168.18.133", 8006));

        JedisCluster jedisCluster = null;
        try {
            //connectionTimeout:指的是連接一個url的連接等待時間
            //soTimeout:指的是連接上一個url,獲取response的返回等待時間
            jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "artisan", config);
            for (int i = 0; i < 10000; i++) {
                jedisCluster.set("{art}:clusterArtisan:" + i, "artisanValue:" + i);
            }
            System.out.println("DONE");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedisCluster != null)
                jedisCluster.close();
        }
    }
}


在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章