国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

這篇具有很好參考價(jià)值的文章主要介紹了Redis高級(jí)——鍵值對(duì)設(shè)計(jì)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1、Redis鍵值設(shè)計(jì)

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

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

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

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

Redis高級(jí)——鍵值對(duì)設(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)存碎片

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

1.2、拒絕BigKey

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

  • 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也給我們提供了命令

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

推薦值:

  • 單個(gè)key的value小于10KB
  • 對(duì)于集合類型的key,建議元素?cái)?shù)量小于1000
1.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í)例,無法使數(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)用
1.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

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

②scan掃描

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

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

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.選擇庫
        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();
        }
    }

}
③第三方工具
  • 利用第三方工具,如 Redis-Rdb-Tools 分析RDB快照文件,全面分析內(nèi)存使用情況
  • https://github.com/sripathikrishnan/redis-rdb-tools
④網(wǎng)絡(luò)監(jiān)控
  • 自定義工具,監(jiān)控進(jìn)出Redis的網(wǎng)絡(luò)數(shù)據(jù),超出預(yù)警值時(shí)主動(dòng)告警
  • 一般阿里云搭建的云服務(wù)器就有相關(guān)監(jiān)控頁面

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

1.2.3、如何刪除BigKey

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

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

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

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

1.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)簡單粗暴

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

②方式二:字段打散
user:1:name Jack
user:1:age 21

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

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

③方式三:hash(推薦)
user:1 name jack
age 21

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

缺點(diǎn):代碼相對(duì)復(fù)雜

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

存在的問題:

  • hash的entry數(shù)量超過500時(shí),會(huì)使用哈希表而不是ZipList,內(nèi)存占用較多
    • Redis高級(jí)——鍵值對(duì)設(shè)計(jì)
  • 可以通過hash-max-ziplist-entries配置entry上限。但是如果entry過多就會(huì)導(dǎo)致BigKey問題
方案一

拆分為string類型

key value
id:0 value0
..... .....
id:999999 value999999

存在的問題:

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

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)

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

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

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

Redis高級(jí)——鍵值對(duì)設(shè)計(jì)文章來源地址http://www.zghlxwxcb.cn/news/detail-431736.html

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.選擇庫
        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();
        }
    }
}

1.4、總結(jié)

  • Key的最佳實(shí)踐
    • 固定格式:[業(yè)務(wù)名]:[數(shù)據(jù)名]:[id]
    • 足夠簡短:不超過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高級(jí)——鍵值對(duì)設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spark【RDD編程(三)鍵值對(duì)RDD】

    ????????鍵值對(duì) RDD 就是每個(gè)RDD的元素都是 (key,value)類型的鍵值對(duì),是一種常見的 RDD,可以應(yīng)用于很多場景。???????? ????????因?yàn)楫吘雇ㄟ^我們之前Hadoop的學(xué)習(xí)中,我們就可以看到對(duì)數(shù)據(jù)的處理,基本都是以鍵值對(duì)的形式進(jìn)行統(tǒng)一批處理的,因?yàn)镸apReduce模型中

    2024年02月09日
    瀏覽(19)
  • Java鍵值對(duì)Pair的使用方式和操作流程

    Java鍵值對(duì)Pair的使用方式和操作流程

    目錄 一、什么是鍵值對(duì) 二、Java的Pair 三、Pair 的使用場景 ? 鍵值對(duì)是一種常見的數(shù)據(jù)結(jié)構(gòu),它由一個(gè)唯一的鍵(key)和與之關(guān)聯(lián)的值(value)組成 。鍵和值之間存在一種映射關(guān)系,通過鍵可以查找或訪問對(duì)應(yīng)的值。 在鍵值對(duì)中,鍵通常用于唯一標(biāo)識(shí)和區(qū)分不同的數(shù)據(jù)項(xiàng),而

    2024年02月07日
    瀏覽(22)
  • Python中刪除字典中鍵值對(duì)的方法

    方法一:dic.pop(\\\'key\\\', 默認(rèn)值) 1、字典的pop方法可以將字典鍵所對(duì)應(yīng)的值給刪除掉,但因?yàn)樽值渲墟I和值是映射關(guān)系,該鍵所對(duì)應(yīng)的值被刪除了,則該鍵也會(huì)從字典中移除。 2、pop方法會(huì)返回被移除鍵對(duì)應(yīng)的值。 3、若pop方法想移除的鍵不存在,則返回默認(rèn)值。 方法二:使用P

    2023年04月09日
    瀏覽(20)
  • Python 遍歷結(jié)構(gòu)復(fù)雜的多層嵌套字典,收集特定鍵值對(duì)

    可以使用遞歸函數(shù)來遍歷整個(gè)嵌套層次不同的字典,收集所有感興趣的鍵值對(duì),最終得到一個(gè)非嵌套結(jié)構(gòu)的字典: (一般用于處理爬取的json數(shù)據(jù),因?yàn)橛行┙Y(jié)構(gòu)真的蠻怪的(?3[____]

    2024年02月19日
    瀏覽(21)
  • Python dict字典基本操作(包括添加、修改、刪除鍵值對(duì))

    由于字典屬于可變序列,所以我們可以任意操作字典中的鍵值對(duì)(key-value)。Python 中,常見的字典操作有以下幾種: 向現(xiàn)有字典中添加新的鍵值對(duì)。 修改現(xiàn)有字典中的鍵值對(duì)。 從現(xiàn)有字典中刪除指定的鍵值對(duì)。 判斷現(xiàn)有字典中是否存在指定的鍵值對(duì)。 初學(xué)者要牢記,字典

    2024年02月08日
    瀏覽(29)
  • python中修改和新增字典中鍵值對(duì)的兩種方法

    方法一:方括號(hào)[]法 dic1[\\\'key\\\'] = 值,即可用于修改字典中的鍵值對(duì),又可用于新增字典中的鍵值對(duì)。 當(dāng)鍵存在時(shí),為修改。 當(dāng)鍵不存在時(shí),為新增。 方法二:dic1.update(dic2) dic1.update(dic2)既可用于修改字典中的鍵值對(duì),又可用于新增字典中的鍵值對(duì)。 當(dāng)dic2中有鍵與dic1中鍵沖突

    2024年02月11日
    瀏覽(29)
  • js在數(shù)組對(duì)象中添加和刪除鍵值對(duì)(對(duì)象屬性)的方法

    添加 1.Object.assign():用法-Object.assign(源對(duì)象, {要添加的鍵值對(duì)}) 2.拓展運(yùn)算符(...):用于取出參數(shù)對(duì)象所有可遍歷屬性然后拷貝到當(dāng)前對(duì)象 3.object[key] = value:直接給新的key賦值 刪除 1.將屬性設(shè)置為 undefined:屬性本身仍將存在于對(duì)象中,它還會(huì)改變?cè)紝?duì)象。 2.使用 delete 操

    2024年02月14日
    瀏覽(30)
  • C++-map:獲取map中value最大值、最小值對(duì)應(yīng)的鍵值對(duì)

    簡述:通過調(diào)用 max_element 函數(shù),給定其特定的比較方式,將會(huì)獲得在給定比較方式下得結(jié)果.上述代碼中,給定的比較方式是根據(jù) value 值進(jìn)行比較, 相當(dāng)于重構(gòu)了 號(hào).將返回最大值 . 使用匿名函數(shù)重構(gòu): 打印結(jié)果: C++獲取map中value最大最小值對(duì)應(yīng)的鍵值對(duì)_普通網(wǎng)友的博客-CSDN博客

    2024年02月16日
    瀏覽(23)
  • javaScript中對(duì)象使用遍歷渲染鍵值對(duì)取值,Vue的{{}}中寫方法獲取值。

    ?類似于這樣的數(shù)據(jù)有若干條,我們希望展示的方式為 我的朋友: ? ? ? ? 陪我同眠的床伴【熊貓:花花,狗熊:阿壯】 此時(shí)在代碼中的應(yīng)該如果來寫? {{?item[Object.keys(item)[0]]?}}?會(huì)顯示數(shù)組元素的值,而?(Object.keys(item)[0])?會(huì)顯示數(shù)組元素的鍵。 i tem[Object.keys(item)[0]]會(huì)根

    2024年01月17日
    瀏覽(20)
  • 【JavaSE專欄53】Java集合類HashMap解析,基于哈希表的鍵值對(duì)存儲(chǔ)結(jié)構(gòu)

    【JavaSE專欄53】Java集合類HashMap解析,基于哈希表的鍵值對(duì)存儲(chǔ)結(jié)構(gòu)

    作者主頁 :Designer 小鄭 作者簡介 :3年JAVA全棧開發(fā)經(jīng)驗(yàn),專注JAVA技術(shù)、系統(tǒng)定制、遠(yuǎn)程指導(dǎo),致力于企業(yè)數(shù)字化轉(zhuǎn)型,CSDN學(xué)院、藍(lán)橋云課認(rèn)證講師。 主打方向 :Vue、SpringBoot、微信小程序 本文講解了 Java 中集合類 HashMap 的語法、使用說明和應(yīng)用場景,并給出了樣例代碼。

    2024年02月15日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包