最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis內(nèi)存管理之BigKey問題及解決過程

 更新時(shí)間:2025年07月22日 09:00:28   作者:紀(jì)元A夢(mèng)  
文章全面解析了Java中Redis?BigKey問題,涵蓋定義、危害(內(nèi)存不均、持久化阻塞等)、檢測(cè)方法(內(nèi)置工具與自定義掃描)、處理策略(分治拆分、漸進(jìn)刪除)及開發(fā)規(guī)范,結(jié)合案例與AI監(jiān)控優(yōu)化方案,提出系統(tǒng)化應(yīng)對(duì)措施,保障Redis高性能運(yùn)行

Java中的Redis BigKey問題解析

一、BigKey 定義與危害分析

1.1 核心定義

BigKey 是指 Redis 中 Value 體積異常大的 Key,通常表現(xiàn)為:

  • 字符串類型:Value 超過 10KB
  • 集合類型:元素?cái)?shù)量超過 1 萬(List/Set)或 5 千(Hash/ZSet)
  • 流類型:Stream 包含數(shù)萬條消息

1.2 危害全景圖

1.3 典型業(yè)務(wù)場(chǎng)景

場(chǎng)景錯(cuò)誤用法推薦方案
社交用戶畫像存儲(chǔ)單個(gè)Hash存儲(chǔ)用戶所有標(biāo)簽分片存儲(chǔ) + 二級(jí)索引
電商購(gòu)物車設(shè)計(jì)單個(gè)List存儲(chǔ)百萬級(jí)商品分頁(yè)存儲(chǔ) + 冷熱分離
實(shí)時(shí)消息隊(duì)列單個(gè)Stream累積數(shù)月數(shù)據(jù)按時(shí)間分片 + 定期歸檔

二、BigKey 檢測(cè)方法論

2.1 內(nèi)置工具檢測(cè)

2.1.1 redis-cli --bigkeys

# 掃描耗時(shí)型操作,建議在從節(jié)點(diǎn)執(zhí)行
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1

# 輸出示例
[00.00%] Biggest string found 'user:1024:info' has 12 bytes
[12.34%] Biggest hash   found 'product:8888:spec' has 10086 fields

2.1.2 MEMORY USAGE

// 計(jì)算Key內(nèi)存占用
Long memUsage = redisTemplate.execute(
    (RedisCallback<Long>) connection -> 
        connection.serverCommands().memoryUsage("user:1024:info".getBytes())
);

2.2 自定義掃描方案

2.2.1 SCAN + TYPE 組合掃描

public List<Map.Entry<String, Long>> findBigKeys(int threshold) {
    List<Map.Entry<String, Long>> bigKeys = new ArrayList<>();
    Cursor<byte[]> cursor = redisTemplate.execute(
        (RedisCallback<Cursor<byte[]>>) connection -> 
            connection.scan(ScanOptions.scanOptions().count(100).build())
    );

    while (cursor.hasNext()) {
        byte[] keyBytes = cursor.next();
        String key = new String(keyBytes);
        DataType type = redisTemplate.type(key);
        
        long size = 0;
        switch (type) {
            case STRING:
                size = redisTemplate.opsForValue().size(key);
                break;
            case HASH:
                size = redisTemplate.opsForHash().size(key);
                break;
            // 其他類型處理...
        }
        
        if (size > threshold) {
            bigKeys.add(new AbstractMap.SimpleEntry<>(key, size));
        }
    }
    return bigKeys;
}

2.2.2 RDB 文件分析

# 使用rdb-tools分析
rdb -c memory dump.rdb --bytes 10240 > bigkeys.csv

# 輸出示例
database,type,key,size_in_bytes,encoding,num_elements,len_largest_element
0,hash,user:1024:tags,1048576,hashtable,50000,128

2.3 監(jiān)控預(yù)警體系

2.3.1 Prometheus 配置

# redis_exporter配置
- name: redis_key_size
  rules:
  - record: redis:key_size:bytes
    expr: redis_key_size{job="redis"}
    labels:
      severity: warning

2.3.2 Grafana 看板指標(biāo)

監(jiān)控項(xiàng)查詢表達(dá)式報(bào)警閾值
大Key數(shù)量count(redis_key_size > 10240)>10
最大Key內(nèi)存占比max(redis_key_size) / avg(…)>5倍

三、BigKey 處理全流程

3.1 分治法處理

3.1.1 Hash 拆分

public void splitBigHash(String originalKey, int batchSize) {
    Map<Object, Object> entries = redisTemplate.opsForHash().entries(originalKey);
    List<List<Map.Entry<Object, Object>>> batches = Lists.partition(
        new ArrayList<>(entries.entrySet()), 
        batchSize
    );
    
    for (int i = 0; i < batches.size(); i++) {
        String shardKey = originalKey + ":shard_" + i;
        redisTemplate.opsForHash().putAll(shardKey, 
            batches.get(i).stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
        );
    }
    redisTemplate.delete(originalKey);
}

3.1.2 List 分頁(yè)

public List<Object> getPaginatedList(String listKey, int page, int size) {
    long start = (page - 1) * size;
    long end = page * size - 1;
    return redisTemplate.opsForList().range(listKey, start, end);
}

3.2 漸進(jìn)式刪除

3.2.1 非阻塞刪除方案

public void safeDeleteBigKey(String key) {
    DataType type = redisTemplate.type(key);
    
    switch (type) {
        case HASH:
            redisTemplate.execute(
                "HSCAN", key, "0", "COUNT", "100", 
                (result) -> {
                    // 分批刪除字段
                    return null;
                });
            break;
        case LIST:
            while (redisTemplate.opsForList().size(key) > 0) {
                redisTemplate.opsForList().trim(key, 0, -101);
            }
            break;
        // 其他類型處理...
    }
    redisTemplate.unlink(key);
}

3.2.2 Lua 腳本控制

-- 分批次刪除Hash字段
local cursor = 0
repeat
    local result = redis.call('HSCAN', KEYS[1], cursor, 'COUNT', 100)
    cursor = tonumber(result[1])
    for _, field in ipairs(result[2]) do
        redis.call('HDEL', KEYS[1], field)
    end
until cursor == 0

3.3 數(shù)據(jù)遷移方案

3.3.1 集群環(huán)境下處理

public void migrateBigKey(String sourceKey, String targetKey) {
    RedisClusterConnection clusterConn = redisTemplate.getConnectionFactory()
        .getClusterConnection();
    
    int slot = ClusterSlotHashUtil.calculateSlot(sourceKey);
    RedisNode node = clusterConn.clusterGetNodeForSlot(slot);
    
    try (Jedis jedis = new Jedis(node.getHost(), node.getPort())) {
        // 分批遷移數(shù)據(jù)
        ScanParams params = new ScanParams().count(100);
        String cursor = "0";
        do {
            ScanResult<Map.Entry<String, String>> scanResult = 
                jedis.hscan(sourceKey, cursor, params);
            List<Map.Entry<String, String>> entries = scanResult.getResult();
            
            // 分批寫入新Key
            Map<String, String> batch = entries.stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            jedis.hmset(targetKey, batch);
            
            cursor = scanResult.getCursor();
        } while (!"0".equals(cursor));
    }
}

四、Java 開發(fā)規(guī)范與最佳實(shí)踐

4.1 數(shù)據(jù)建模規(guī)范

數(shù)據(jù)類型反例正例
String存儲(chǔ)10MB的JSON字符串拆分成多個(gè)Hash + Gzip壓縮
Hash存儲(chǔ)用戶所有訂單信息按訂單日期分片存儲(chǔ)
List存儲(chǔ)10萬條聊天記錄按時(shí)間分片+消息ID索引

4.2 客戶端配置優(yōu)化

4.2.1 JedisPool 配置

JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(200);         // 最大連接數(shù)
config.setMaxWaitMillis(1000);   // 最大等待時(shí)間
config.setTestOnBorrow(true);    // 獲取連接時(shí)驗(yàn)證

4.2.2 Lettuce 調(diào)優(yōu)

ClientOptions options = ClientOptions.builder()
    .autoReconnect(true)
    .publishOnScheduler(true)
    .timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(1)))
    .build();

4.3 監(jiān)控與熔斷

@CircuitBreaker(name = "redisService", fallbackMethod = "fallback")
public Object getData(String key) {
    return redisTemplate.opsForValue().get(key);
}

private Object fallback(String key, Throwable t) {
    return loadFromBackup(key);
}

五、生產(chǎn)環(huán)境案例

5.1 社交平臺(tái)用戶關(guān)系案例

問題:?jiǎn)蝹€(gè)Set存儲(chǔ)50萬粉絲導(dǎo)致節(jié)點(diǎn)內(nèi)存溢出

解決方案

  1. 按粉絲ID范圍拆分成100個(gè)Set
  2. 使用SINTERSTORE合并多個(gè)Set查詢
  3. 新增反向索引(粉絲 -> 關(guān)注列表)

5.2 電商商品屬性案例

問題:Hash存儲(chǔ)10萬條商品規(guī)格導(dǎo)致HGETALL阻塞

改造方案

  1. 按屬性類別拆分Hash
  2. 使用HMGET獲取指定字段
  3. 增加緩存版本號(hào)控制

六、開發(fā)方向

  1. AI 智能分片:基于機(jī)器學(xué)習(xí)預(yù)測(cè)數(shù)據(jù)增長(zhǎng)趨勢(shì)
  2. Serverless 存儲(chǔ):自動(dòng)彈性伸縮的Key分片服務(wù)
  3. 新型數(shù)據(jù)結(jié)構(gòu):使用RedisJSON模塊處理大文檔
  4. 內(nèi)存壓縮算法:ZSTD 壓縮算法集成優(yōu)化

通過全流程的預(yù)防、檢測(cè)、處理體系建設(shè),結(jié)合智能化的監(jiān)控預(yù)警,可有效應(yīng)對(duì) BigKey 挑戰(zhàn),保障 Redis 高性能服務(wù)能力。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn)

    redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn)

    本文主要介紹了redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn),億級(jí)數(shù)據(jù)規(guī)模下實(shí)現(xiàn)高效的數(shù)據(jù)讀取成為了許多企業(yè)和開發(fā)者面臨的重大挑戰(zhàn),下面就來介紹一下,感興趣的可以了解一下
    2024-08-08
  • Redis 鍵值設(shè)計(jì)使用總結(jié)

    Redis 鍵值設(shè)計(jì)使用總結(jié)

    這篇文章主要介紹了Redis鍵值設(shè)計(jì)的使用總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 詳解Redis集群搭建的三種方式

    詳解Redis集群搭建的三種方式

    Redis是一個(gè)開源的key-value存儲(chǔ)系統(tǒng),大部分互聯(lián)網(wǎng)企業(yè)都用來做服務(wù)器端緩存。Redis在3.0版本前只支持單實(shí)例模式,雖然支持主從模式、哨兵模式部署來解決單點(diǎn)故障,但是現(xiàn)在互聯(lián)網(wǎng)企業(yè)動(dòng)輒大幾百G的數(shù)據(jù),沒法滿足業(yè)務(wù)的需求,所以Redis在3.0版本以后就推出了集群模式。
    2021-05-05
  • 阿里Tair分布式鎖與Redis分布式鎖的實(shí)現(xiàn)區(qū)別

    阿里Tair分布式鎖與Redis分布式鎖的實(shí)現(xiàn)區(qū)別

    本文給大家介紹阿里Tair分布式鎖與Redis分布式鎖的實(shí)現(xiàn)區(qū)別解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2026-04-04
  • redis?for?windows?6.2.6安裝包最新步驟詳解

    redis?for?windows?6.2.6安裝包最新步驟詳解

    這篇文章主要介紹了redis?for?windows?6.2.6安裝包全網(wǎng)首發(fā),使用Windows計(jì)劃任務(wù)自動(dòng)運(yùn)行redis服務(wù),文章給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 為啥懶 Redis 是更好的 Redis

    為啥懶 Redis 是更好的 Redis

    本文是由zicode, 李中凱, 無若翻譯的英文文章Lazy Redis is better Redis,小編認(rèn)為非常不錯(cuò),這里推薦給大家
    2018-07-07
  • Redis基本數(shù)據(jù)類型示例詳解

    Redis基本數(shù)據(jù)類型示例詳解

    本文給大家介紹了Redis基本數(shù)據(jù)類型示例詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-09-09
  • redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?directory

    redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?d

    這篇文章主要介紹了redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?directory問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 如何高效使用Redis作為L(zhǎng)RU緩存

    如何高效使用Redis作為L(zhǎng)RU緩存

    這篇文章主要介紹了如何高效使用Redis作為L(zhǎng)RU緩存,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • redis4.0入門小結(jié)

    redis4.0入門小結(jié)

    這篇文章主要介紹了redis4.0入門小結(jié),文中通過示例和概念介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11

最新評(píng)論

岗巴县| 娱乐| 蛟河市| 莆田市| 齐齐哈尔市| 方正县| 津南区| 广元市| 富源县| 汤阴县| 高雄县| 麻城市| 融水| 天全县| 五河县| 梁山县| 顺义区| 青州市| 若尔盖县| 兴城市| 大渡口区| 清徐县| 马鞍山市| 临沭县| 营山县| 大宁县| 清丰县| 观塘区| 松桃| 县级市| 黄山市| 阆中市| 九龙城区| 清原| 建德市| 九龙城区| 万宁市| 阳春市| 莎车县| 平湖市| 高密市|