成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

給你1億的Redis key,如何高效統計?

數據庫 Redis
今天這篇文章就跟大家一起聊聊如果給你1億個Redis key,如何高效統計這個話題,希望對你會有所幫助。

前言

有些小伙伴在工作中,可能遇到過這樣的場景:老板突然要求統計Redis中所有key的數量,你隨手執行了KEYS *命令,下一秒監控告警瘋狂閃爍——整個Redis集群徹底卡死,線上服務大面積癱瘓。

今天這篇文章就跟大家一起聊聊如果給你1億個Redis key,如何高效統計這個話題,希望對你會有所幫助。

1.為什么不建議使用KEYS命令?

Redis的單線程模型是其高性能的核心,但也是最大的軟肋。

當Redis執行 KEYS * 命令時,內部的流程如下:

圖片圖片

Redis的單線程模型是其高性能的核心,但同時也帶來一個關鍵限制:所有命令都是串行執行的。

當我們執行 KEYS * 命令時:

Redis必須遍歷整個key空間(時間復雜度O(N))

在遍歷完成前,無法處理其他任何命令

對于1億個key,即使每個key查找只需0.1微秒,總耗時也高達10秒!

致命三連擊

  • 時間復雜度:1億key需要10秒+(實測單核CPU 0.1μs/key)
  • 內存風暴:返回結果太多可能撐爆客戶端內存
  • 集群失效:在Cluster模式中只能查當前節點的數據。

如果Redis一次性返回的數據太多,可能會有OOM問題:

127.0.0.1:6379> KEYS *
(卡死10秒...)
(error) OOM command not allowed when used memory > 'maxmemory'

超過了最大內存。

那么,Redis中有1億key,我們要如何統計數據呢?

2.SCAN命令

SCAN命令通過游標分批遍歷,每次只返回少量key,避免阻塞。

Java版基礎SCAN的代碼如下:

public long safeCount(Jedis jedis) {
    long total = 0;
    String cursor = "0";
    ScanParams params = new ScanParams().count(500); // 每批500個
    
    do {
        ScanResult<String> rs = jedis.scan(cursor, params);
        cursor = rs.getCursor();
        total += rs.getResult().size();
    } while (!"0".equals(cursor)); // 游標0表示結束
    
    return total;
}

使用游標查詢Redis中的數據,一次掃描500條數據。

但問題來了:1億key需要多久?

  • 每次SCAN耗時≈3ms
  • 每次返回500key
  • 總次數=1億/500=20萬次
  • 總耗時≈20萬×3ms=600秒=10分鐘!

3.多線程并發SCAN方案

現代服務器都是多核CPU,單線程掃描是資源浪費。

看多線程優化方案如下:

圖片圖片

多線程并發SCAN代碼如下:

public long parallelCount(JedisPool pool, int threads) throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(threads);
    AtomicLong total = new AtomicLong(0);
    
    // 生成初始游標(實際需要更智能的分段)
    List<String> cursors = new ArrayList<>();
    for (int i = 0; i < threads; i++) {
        cursors.add(String.valueOf(i));
    }

    CountDownLatch latch = new CountDownLatch(threads);
    
    for (String cursor : cursors) {
        executor.execute(() -> {
            try (Jedis jedis = pool.getResource()) {
                String cur = cursor;
                do {
                    ScanResult<String> rs = jedis.scan(cur, new ScanParams().count(500));
                    cur = rs.getCursor();
                    total.addAndGet(rs.getResult().size());
                } while (!"0".equals(cur));
                latch.countDown();
            }
        });
    }
    
    latch.await();
    executor.shutdown();
    return total.get();
}

使用線程池、AtomicLong和CountDownLatch配合使用,實現了多線程掃描數據,最終將結果合并。

性能對比(32核CPU/1億key):

方案

線程數

耗時

資源占用

單線程SCAN

1

580s

CPU 5%

多線程SCAN

32

18s

CPU 800%

4.分布式環境的分治策略

如果你的系統重使用了Redis Cluster集群模式,該模式會將數據分散在16384個槽(slot)中,統計就需要節點協同。

流程圖如下:

圖片圖片

每一個Redis Cluster集群中的master服務節點,都負責統計一定范圍的槽(slot)中的數據,最后將數據聚合起來返回。

集群版并行統計代碼如下:

public long clusterCount(JedisCluster cluster) {
    Map<String, JedisPool> nodes = cluster.getClusterNodes();
    AtomicLong total = new AtomicLong(0);
    
    nodes.values().parallelStream().forEach(pool -> {
        try (Jedis jedis = pool.getResource()) {
            // 跳過從節點
            if (jedis.info("replication").contains("role:slave")) return; 
            
            String cursor = "0";
            do {
                ScanResult<String> rs = jedis.scan(cursor, new ScanParams().count(500));
                total.addAndGet(rs.getResult().size());
                cursor = rs.getCursor();
            } while (!"0".equals(cursor));
        }
    });
    
    return total.get();
}

這里使用了parallelStream,會并發統計Redis不同的master節點中的數據。

5.毫秒統計方案

方案1:使用內置計數器

如果只想統計一個數量,可以使用Redis內置計數器,瞬時但非精確。

127.0.0.1:6379> info keyspace
# Keyspace
db0:keys=100000000,expires=20000,avg_ttl=3600

優點:毫秒級返回。

缺點:包含已過期未刪除的key,法按模式過濾數據。

方案2:實時增量統計

實時增量統計方案精準但復雜。

基于鍵空間通知的實時計數器,具體代碼如下:

@Configuration
publicclass KeyCounterConfig {
    
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory factory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        
        container.addMessageListener((message, pattern) -> {
            String event = new String(message.getBody());
            if(event.startsWith("__keyevent@0__:set")) {
                redisTemplate.opsForValue().increment("total_keys", 1);
            } elseif(event.startsWith("__keyevent@0__:del")) {
                redisTemplate.opsForValue().decrement("total_keys", 1);
            }
        }, new PatternTopic("__keyevent@*"));
        
        return container;
    }
}

使用監聽器統計數量。

成本分析

  • 內存開銷:額外存儲計數器
  • CPU開銷:增加5%-10%處理通知
  • 網絡開銷:集群模式下需跨節點同步

6.如何選擇方案?

本文中列舉出了多個統計Redis中key的方案,那么我們在實際工作中如何選擇呢?

下面用一張圖給大家列舉了選擇路線:

圖片圖片

各方案的時間和空間復雜度如下:

方案

時間復雜度

空間復雜度

精度

KEYS命令

O(n)

O(n)

精確

SCAN遍歷

O(n)

O(1)

精確

內置計數器

O(1)

O(1)

不精確

增量統計

O(1)

O(1)

精確

硬件法則:

  • CPU密集型:多線程數=CPU核心數×1.5
  • IO密集型:線程數=CPU核心數×3
  • 內存限制:控制批次大小(count參數)

常見的業務場景:

  • 電商實時大屏:增量計數器+RedisTimeSeries
  • 離線數據分析:SCAN導出到Spark
  • 安全審計:多節點并行SCAN

終極箴言:? 精確統計用分治? 實時查詢用增量? 趨勢分析用采樣? 暴力遍歷是自殺

真正的高手不是能解決難題的人,而是能預見并規避難題的人

在海量數據時代,選擇比努力更重要——理解數據本質,才能駕馭數據洪流。


責任編輯:武曉燕 來源: 蘇三說技術
相關推薦

2021-08-04 17:55:38

keysRedis數據庫

2025-06-26 02:23:00

2025-02-21 08:20:33

2023-12-08 07:55:37

MySQL數據統計InnoDB

2015-10-23 10:39:21

2021-08-08 22:08:41

Redis開發網頁

2025-05-28 03:10:00

2020-03-31 17:05:39

Redis熱 key代理

2020-07-29 09:54:35

帖子中心數據架構

2019-04-01 08:19:38

搜索系統美團

2024-11-04 16:01:01

2021-09-13 07:46:06

Kubectl Kubernetes 工具

2021-05-24 08:58:34

Redis Bitmap 數據統計

2025-03-05 08:40:00

RedisJava開發

2025-01-14 16:14:10

2024-11-21 16:47:55

2021-04-15 11:37:47

NumpyPython代碼

2019-12-02 09:58:04

2024-05-29 12:47:27

2024-06-04 15:53:12

Python數組
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久亚洲欧美日韩精品专区 | 欧美激情精品久久久久久变态 | 国产精品视频久久 | 欧美a级成人淫片免费看 | 精品国产精品三级精品av网址 | 日韩精品在线播放 | 国产亚洲精品一区二区三区 | 日韩精品999 | 日本久久www成人免 成人久久久久 | 97人人澡人人爽91综合色 | 欧美成人一区二区 | 国产高清一区二区三区 | 国产精品国产精品国产专区不卡 | 亚洲一区二区av | 一区二区三区不卡视频 | 国产精品毛片无码 | 亚洲国产成人精品女人久久久 | 欧美在线日韩 | 亚洲自拍偷拍av | 北条麻妃av一区二区三区 | 一区二区精品 | 成人免费看黄 | 欧美一区二区三区高清视频 | 欧美精品综合在线 | 午夜精品在线观看 | 日本一区二区三区四区 | 中国一级特黄真人毛片免费观看 | 日韩午夜影院 | 欧美乱大交xxxxx另类电影 | 91短视频网址 | 国产在线观看一区二区三区 | 特黄毛片视频 | 日韩高清黄色 | 免费一级网站 | 欧美一级欧美三级在线观看 | 天堂资源 | 欧美中文字幕一区二区三区亚洲 | 99精品视频免费观看 | 国产乱码精品一区二区三区忘忧草 | 国产在线视频在线观看 | 久草网址|