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

Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn)

 更新時(shí)間:2024年06月28日 11:17:42   作者:是誰(shuí)偷吃了奶酪  
本文主要介紹了Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1 優(yōu)雅的key結(jié)構(gòu)

Redis的Key雖然可以自定義,但最好遵循下面的幾個(gè)最佳實(shí)踐約定:

  • 遵循基本格式:[業(yè)務(wù)名稱]:[數(shù)據(jù)名]:[id]
  • 長(zhǎng)度不超過44字節(jié)
  • 不包含特殊字符

例如:我們的登錄業(yè)務(wù),保存用戶信息,其key可以設(shè)計(jì)成如下格式:

在這里插入圖片描述

這樣設(shè)計(jì)的好處:

  • 可讀性強(qiáng)
  • 避免key沖突
  • 方便管理
  • 更節(jié)省內(nèi)存: key是string類型,底層編碼包含int、embstr和raw三種。embstr在小于44字節(jié)使用,采用連續(xù)內(nèi)存空間,內(nèi)存占用更小。當(dāng)字節(jié)數(shù)大于44字節(jié)時(shí),會(huì)轉(zhuǎn)為raw模式存儲(chǔ),在raw模式下,內(nèi)存空間不是連續(xù)的,而是采用一個(gè)指針指向了另外一段內(nèi)存空間,在這段空間里存儲(chǔ)SDS內(nèi)容,這樣空間不連續(xù),訪問的時(shí)候性能也就會(huì)收到影響,還有可能產(chǎn)生內(nèi)存碎片

在這里插入圖片描述

2 拒絕BigKey

BigKey通常以Key的大小和Key中成員的數(shù)量來(lái)綜合判定,例如:

  • Key本身的數(shù)據(jù)量過大:一個(gè)String類型的Key,它的值為5 MB
  • Key中的成員數(shù)過多:一個(gè)ZSET類型的Key,它的成員數(shù)量為10,000個(gè)
  • Key中成員的數(shù)據(jù)量過大:一個(gè)Hash類型的Key,它的成員數(shù)量雖然只有1,000個(gè)但這些成員的Value(值)總大小為100 MB

那么如何判斷元素的大小呢?redis也給我們提供了命令

在這里插入圖片描述

推薦值:

  • 單個(gè)key的value小于10KB
  • 對(duì)于集合類型的key,建議元素?cái)?shù)量小于1000

2.1 BigKey的危害

網(wǎng)絡(luò)阻塞

  • 對(duì)BigKey執(zhí)行讀請(qǐng)求時(shí),少量的QPS就可能導(dǎo)致帶寬使用率被占滿,導(dǎo)致Redis實(shí)例,乃至所在物理機(jī)變慢

數(shù)據(jù)傾斜

  • BigKey所在的Redis實(shí)例內(nèi)存使用率遠(yuǎn)超其他實(shí)例,無(wú)法使數(shù)據(jù)分片的內(nèi)存資源達(dá)到均衡

Redis阻塞

  • 對(duì)元素較多的hash、list、zset等做運(yùn)算會(huì)耗時(shí)較舊,使主線程被阻塞

CPU壓力

  • 對(duì)BigKey的數(shù)據(jù)序列化和反序列化會(huì)導(dǎo)致CPU的使用率飆升,影響Redis實(shí)例和本機(jī)其它應(yīng)用

2.2 如何發(fā)現(xiàn)BigKey

①redis-cli --bigkeys

利用redis-cli提供的–bigkeys參數(shù),可以遍歷分析所有key,并返回Key的整體統(tǒng)計(jì)信息與每個(gè)數(shù)據(jù)的Top1的big key

命令:redis-cli -a 密碼 --bigkeys

在這里插入圖片描述

②scan掃描

自己編程,利用scan掃描Redis中的所有key,利用strlen、hlen等命令判斷key的長(zhǎng)度(此處不建議使用MEMORY USAGE)

在這里插入圖片描述

scan 命令調(diào)用完后每次會(huì)返回2個(gè)元素,第一個(gè)是下一次迭代的光標(biāo),第一次光標(biāo)會(huì)設(shè)置為0,當(dāng)最后一次scan 返回的光標(biāo)等于0時(shí),表示整個(gè)scan遍歷結(jié)束了,第二個(gè)返回的是List,一個(gè)匹配的key的數(shù)組

import com.heima.jedis.util.JedisConnectionFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanResult;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JedisTest {
    private Jedis jedis;

    @BeforeEach
    void setUp() {
        // 1.建立連接
        // jedis = new Jedis("192.168.150.101", 6379);
        jedis = JedisConnectionFactory.getJedis();
        // 2.設(shè)置密碼
        jedis.auth("123321");
        // 3.選擇庫(kù)
        jedis.select(0);
    }

    final static int STR_MAX_LEN = 10 * 1024;
    final static int HASH_MAX_LEN = 500;

    @Test
    void testScan() {
        int maxLen = 0;
        long len = 0;

        String cursor = "0";
        do {
            // 掃描并獲取一部分key
            ScanResult<String> result = jedis.scan(cursor);
            // 記錄cursor
            cursor = result.getCursor();
            List<String> list = result.getResult();
            if (list == null || list.isEmpty()) {
                break;
            }
            // 遍歷
            for (String key : list) {
                // 判斷key的類型
                String type = jedis.type(key);
                switch (type) {
                    case "string":
                        len = jedis.strlen(key);
                        maxLen = STR_MAX_LEN;
                        break;
                    case "hash":
                        len = jedis.hlen(key);
                        maxLen = HASH_MAX_LEN;
                        break;
                    case "list":
                        len = jedis.llen(key);
                        maxLen = HASH_MAX_LEN;
                        break;
                    case "set":
                        len = jedis.scard(key);
                        maxLen = HASH_MAX_LEN;
                        break;
                    case "zset":
                        len = jedis.zcard(key);
                        maxLen = HASH_MAX_LEN;
                        break;
                    default:
                        break;
                }
                if (len >= maxLen) {
                    System.out.printf("Found big key : %s, type: %s, length or size: %d %n", key, type, len);
                }
            }
        } while (!cursor.equals("0"));
    }
    
    @AfterEach
    void tearDown() {
        if (jedis != null) {
            jedis.close();
        }
    }

}

③第三方工具

④網(wǎng)絡(luò)監(jiān)控

  • 自定義工具,監(jiān)控進(jìn)出Redis的網(wǎng)絡(luò)數(shù)據(jù),超出預(yù)警值時(shí)主動(dòng)告警
  • 一般阿里云搭建的云服務(wù)器就有相關(guān)監(jiān)控頁(yè)面

在這里插入圖片描述

2.3 如何刪除BigKey

BigKey內(nèi)存占用較多,即便時(shí)刪除這樣的key也需要耗費(fèi)很長(zhǎng)時(shí)間,導(dǎo)致Redis主線程阻塞,引發(fā)一系列問題。

redis 3.0 及以下版本

  • 如果是集合類型,則遍歷BigKey的元素,先逐個(gè)刪除子元素,最后刪除BigKey

在這里插入圖片描述

Redis 4.0以后

  • Redis在4.0后提供了異步刪除的命令:unlink

3 恰當(dāng)?shù)臄?shù)據(jù)類型

例1:比如存儲(chǔ)一個(gè)User對(duì)象,我們有三種存儲(chǔ)方式:

①方式一:json字符串

user:1{“name”: “Jack”, “age”: 21}

優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單粗暴

缺點(diǎn):數(shù)據(jù)耦合,不夠靈活

②方式二:字段打散

user:1:nameJack
user:1:age21

優(yōu)點(diǎn):可以靈活訪問對(duì)象任意字段

缺點(diǎn):占用空間大、沒辦法做統(tǒng)一控制

③方式三:hash(推薦)

user:1namejack
age21

優(yōu)點(diǎn):底層使用ziplist(壓縮列表),空間占用小,可以靈活訪問對(duì)象的任意字段

缺點(diǎn):代碼相對(duì)復(fù)雜(有工具類可以方便實(shí)現(xiàn))

例2:假如有hash類型的key,其中有100萬(wàn)對(duì)field和value,field是自增id,這個(gè)key存在什么問題?如何優(yōu)化?

keyfieldvalue
someKeyid:0value0
..........
id:999999value999999

存在的問題:

hash的entry數(shù)量超過500時(shí),會(huì)使用哈希表而不是ZipList,內(nèi)存占用較多

在這里插入圖片描述

可以通過hash-max-ziplist-entries配置entry上限。但是如果entry過多就會(huì)導(dǎo)致BigKey問題

方案一

拆分為string類型

keyvalue
id:0value0
..........
id:999999value999999

存在的問題:

string結(jié)構(gòu)底層沒有太多內(nèi)存優(yōu)化,內(nèi)存占用較多

在這里插入圖片描述

想要批量獲取這些數(shù)據(jù)比較麻煩

方案二

拆分為小的hash,將 id / 100 作為key, 將id % 100 作為field,這樣每100個(gè)元素為一個(gè)Hash

keyfieldvalue
key:0id:00value0
..........
id:99value99
key:1id:00value100
..........
id:99value199
....
key:9999id:00value999900
..........
id:99value999999

在這里插入圖片描述

package com.heima.test;

import com.heima.jedis.util.JedisConnectionFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ScanResult;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JedisTest {
    private Jedis jedis;

    @BeforeEach
    void setUp() {
        // 1.建立連接
        // jedis = new Jedis("192.168.150.101", 6379);
        jedis = JedisConnectionFactory.getJedis();
        // 2.設(shè)置密碼
        jedis.auth("123321");
        // 3.選擇庫(kù)
        jedis.select(0);
    }

    @Test
    void testSetBigKey() {
        Map<String, String> map = new HashMap<>();
        for (int i = 1; i <= 650; i++) {
            map.put("hello_" + i, "world!");
        }
        jedis.hmset("m2", map);
    }

    @Test
    void testBigHash() {
        Map<String, String> map = new HashMap<>();
        for (int i = 1; i <= 100000; i++) {
            map.put("key_" + i, "value_" + i);
        }
        jedis.hmset("test:big:hash", map);
    }

    @Test
    void testBigString() {
        for (int i = 1; i <= 100000; i++) {
            jedis.set("test:str:key_" + i, "value_" + i);
        }
    }

    @Test
    void testSmallHash() {
        int hashSize = 100;
        Map<String, String> map = new HashMap<>(hashSize);
        for (int i = 1; i <= 100000; i++) {
            int k = (i - 1) / hashSize;
            int v = i % hashSize;
            map.put("key_" + v, "value_" + v);
            if (v == 0) {
                jedis.hmset("test:small:hash_" + k, map);
            }
        }
    }

    @AfterEach
    void tearDown() {
        if (jedis != null) {
            jedis.close();
        }
    }
}

4 總結(jié)

Key的最佳實(shí)踐

固定格式:[業(yè)務(wù)名]:[數(shù)據(jù)名]:[id]

足夠簡(jiǎn)短:不超過44字節(jié)

不包含特殊字符

Value的最佳實(shí)踐:

  • 合理的拆分?jǐn)?shù)據(jù),拒絕BigKey
  • 選擇合適數(shù)據(jù)結(jié)構(gòu)
  • Hash結(jié)構(gòu)的entry數(shù)量不要超過1000
  • 設(shè)置合理的超時(shí)時(shí)間

到此這篇關(guān)于Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Redis鍵值設(shè)計(jì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 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 Lua腳本實(shí)現(xiàn)分布式鎖方式

    Redis Lua腳本實(shí)現(xiàn)分布式鎖方式

    文章主要介紹了在分布式系統(tǒng)中使用Lua腳本實(shí)現(xiàn)Redis分布式鎖的方法,包括可重入鎖的實(shí)現(xiàn)和注意事項(xiàng),以及紅鎖算法在Redis集群狀態(tài)下的潛在問題
    2026-05-05
  • Redis搜索日期范圍內(nèi)的查詢示例

    Redis搜索日期范圍內(nèi)的查詢示例

    Redis作為內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),雖未專為日期范圍查詢?cè)O(shè)計(jì),但可通過存儲(chǔ)日期數(shù)據(jù)、使用KEYS命令或有序集合(SortedSet)實(shí)現(xiàn)查詢功能,下面就來(lái)介紹一下
    2024-09-09
  • 解決redis修改requirepass后不生效的問題

    解決redis修改requirepass后不生效的問題

    今天小編就為大家分享一篇解決redis修改requirepass后不生效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2018-05-05
  • Redis?List列表相關(guān)命令的用法詳解

    Redis?List列表相關(guān)命令的用法詳解

    這篇文章主要為大家詳細(xì)介紹了Redis中List列表相關(guān)命令的用法,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • 利用Redis進(jìn)行數(shù)據(jù)緩存的項(xiàng)目實(shí)踐

    利用Redis進(jìn)行數(shù)據(jù)緩存的項(xiàng)目實(shí)踐

    在實(shí)際的業(yè)務(wù)場(chǎng)景中,Redis 一般和其他數(shù)據(jù)庫(kù)搭配使用,用來(lái)減輕后端數(shù)據(jù)庫(kù)的壓力,本文就介紹了利用Redis進(jìn)行數(shù)據(jù)緩存的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-06-06
  • redis主從復(fù)制原理的深入講解

    redis主從復(fù)制原理的深入講解

    這篇文章主要給大家介紹了關(guān)于redis主從復(fù)制原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 使用Jedis線程池returnResource異常注意事項(xiàng)

    使用Jedis線程池returnResource異常注意事項(xiàng)

    這篇文章主要介紹了使用Jedis線程池returnResource異常注意事項(xiàng),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Linux服務(wù)器使用Redis作為數(shù)據(jù)緩存并用log4j2進(jìn)行日志記錄的過程分享

    Linux服務(wù)器使用Redis作為數(shù)據(jù)緩存并用log4j2進(jìn)行日志記錄的過程分享

    這篇文章主要介紹了Linux服務(wù)器使用Redis作為數(shù)據(jù)緩存并用log4j2日志記錄,關(guān)于SpringBoot項(xiàng)目配置Redis與log4j2是查詢官方文檔,本文中的Redis配置類、Redis工具類以及l(fā)og4j2.xml配置文件來(lái)自網(wǎng)絡(luò),查證源自何處比較麻煩,所以在此感謝所有人的分享
    2023-09-09
  • Redis消息隊(duì)列實(shí)現(xiàn)秒殺教程

    Redis消息隊(duì)列實(shí)現(xiàn)秒殺教程

    這篇文章主要介紹了Redis消息隊(duì)列實(shí)現(xiàn)秒殺教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04

最新評(píng)論

涪陵区| 安达市| 广饶县| 辽阳市| 石渠县| 永福县| 连城县| 武夷山市| 淅川县| 沙洋县| 徐闻县| 中牟县| 十堰市| 兴国县| 张家港市| 鱼台县| 胶南市| 将乐县| 石景山区| 剑阁县| 呼和浩特市| 景谷| 柯坪县| 北碚区| 陈巴尔虎旗| 平塘县| 安阳县| 宕昌县| 唐河县| 共和县| 胶州市| 琼结县| 赫章县| 芷江| 四会市| 琼中| 中方县| 大关县| 东港市| 钟祥市| 西峡县|