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

Redis鍵值設(shè)計的實(shí)踐

 更新時間:2023年01月30日 09:10:12   作者:左右盲  
本文主要介紹了Redis鍵值設(shè)計的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在Redis中,良好的鍵值設(shè)計可以達(dá)成事半功倍的效果,而不好的鍵值設(shè)計可能會帶來Redis服務(wù)停滯,網(wǎng)絡(luò)阻塞,CPU使用率飆升等一系列問題,今天就教大家如何設(shè)計一個良好的key-value

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

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

遵循基本格式[業(yè)務(wù)名稱]:[數(shù)據(jù)名]:[id],例如我們的登錄業(yè)務(wù),需要保存用戶信息,其key可以設(shè)計成如下格式

在這里插入圖片描述

這種設(shè)計的好處不僅在于可讀性強(qiáng),還在于可以避免key的沖突問題,而且方便管理

Key的長度不超過44字節(jié)

無論是哪種數(shù)據(jù)類型, key都是string類型,string類型的底層編碼包含int、embstr和raw三種。如果key中全是數(shù)字,那么就會直接以int類型去存儲,而int占用的空間也是最小的,當(dāng)然出于業(yè)務(wù)需求,我們不可能將key設(shè)計為一個全數(shù)字的,而如果不是純數(shù)字,底層存儲的就是SDS內(nèi)容,如果小于44字節(jié),就會使用embstr類型,embstr在內(nèi)存中是一段連續(xù)的存儲空間,內(nèi)存占用相對raw來說較小,而當(dāng)字節(jié)數(shù)大于44字節(jié)時,會轉(zhuǎn)為raw模式存儲,在raw模式下,內(nèi)存空間不是連續(xù)的,而是采用一個指針指向了另外一段內(nèi)存空間,在這段空間里存儲SDS內(nèi)容,這樣空間不連續(xù),訪問的時候性能也就會收到影響,還有可能產(chǎn)生內(nèi)存碎片

需要注意的是,如果你的redis版本低于4.0,那么界限是39字節(jié)而非44字節(jié)

Key中不包含一些特殊字符

2 拒絕BigKey

2.1 判斷BigKey

BigKey顧名思義就是一個很大的Key,這里的大并不是指Key本身很大,而是指包括這個Key的Value在內(nèi)的一整個鍵值對很大

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

  • Key的Value過大:例如一個String類型的Key,它的Value為5MB
  • Key中的成員數(shù)過多:例如一個ZSET類型的Key,它的成員數(shù)量為10000個
  • Key中成員的Value過大:例如一個Hash類型的Key,它的成員數(shù)量雖然只有1000個,但這些成員的Value總大小為100 MB

那么如何判斷元素的大小呢?redis中為我們提供了相應(yīng)的命令,語法如下:

memory usage 鍵名

這條命令會返回一條數(shù)據(jù)占用內(nèi)存的總大小,這個大小不僅包括Key和Value的大小,還包括數(shù)據(jù)存儲時的一些元信息,因此可能你的Key與Value只占用了幾十個字節(jié),但最終的返回結(jié)果是幾百個字節(jié)

但是我們一般不推薦使用memory指令,因?yàn)檫@個指令對CPU的占用率是很高的,實(shí)際開發(fā)中我們一般只需要衡量Value的大小或者Key中的成員數(shù)即可

例如如果我們使用的數(shù)據(jù)類型是String,就可以使用以下命令,返回的結(jié)果是Value的長度

strlen 鍵名

如果我們使用的數(shù)據(jù)類型是List,就可以使用以下命令,返回的結(jié)果是List中成員的個數(shù)

llen 鍵名

一般我們推薦,單個key的value小于10KB,集合類型的key元素數(shù)量小于1000

2.2 BigKey的危害

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

當(dāng)我們對一個BigKey發(fā)起讀請求時,只需少量的QPS就可能導(dǎo)致帶寬使用率被占滿,導(dǎo)致Redis實(shí)例乃至所在物理機(jī)變慢,例如一個bigkey占用5M內(nèi)存,只需要QPS達(dá)到20,那么1秒鐘就會占100M的帶寬

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

集群環(huán)境下,由于所有插槽一開始都是均衡分配的,因此BigKey所在的Redis實(shí)例內(nèi)存使用率會遠(yuǎn)超其他實(shí)例,從而無法使數(shù)據(jù)分片的內(nèi)存資源達(dá)到均衡,最后不得不手動重新分配插槽,增加運(yùn)維人員的負(fù)擔(dān)

Redis阻塞

對元素較多的hash、list、zset等做運(yùn)算會耗時較久,而且由于Redis是單線程的,在運(yùn)算過程中會導(dǎo)致服務(wù)阻塞,無法接收其他用戶請求

CPU壓力

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

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

既然我們知道了什么叫BigKey以及BigKey的危害,那么如何去快速發(fā)現(xiàn)Redis中所有的BigKey呢?這里為大家提供以下幾種方案:

1)利用Redis本身提供的命令

利用以下命令,可以遍歷分析所有key,并返回Key的整體統(tǒng)計信息與每種數(shù)據(jù)類型中Top1的BigKey

redis-cli -a 密碼 --bigkeys

演示如下(這里我的redis沒有設(shè)置密碼,如果你的redis設(shè)置了密碼,則需要使用 -a 密碼 進(jìn)行連接)

在這里插入圖片描述

2)自己手動編寫程序進(jìn)行掃描

我們可以通過自己編寫程序,將Redis中所有的數(shù)據(jù)查詢出來并一一統(tǒng)計長度來找出BigKey,這里不建議使用keys *來查詢所有數(shù)據(jù),因?yàn)?code>keys * 是一次將所有的數(shù)據(jù)全部查找出來,如果數(shù)據(jù)量很大,key *一次可能要幾十秒甚至幾分鐘,在如此長的時間內(nèi),Redis的主線程會因?yàn)閳?zhí)行該命令而被阻塞。

這里建議使用redis提供的scan命令,語法如下:

scan 起始位置 count 數(shù)量

scan掃描有點(diǎn)類似于分頁查詢,而被分頁的對象是redis中所有的數(shù)據(jù),scan命令調(diào)用一次只會從指定的起始位置開始返回指定數(shù)量的數(shù)據(jù),以及此次掃描結(jié)束時光標(biāo)所在的位置,下一次掃描時就需要從這個光標(biāo)開始繼續(xù)往下掃描

這里提供一個已經(jīng)編寫好的查找BigKey的測試類,大家可以參考一下

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);
    }

    //設(shè)置string類型的長度上限,超過這個上限就判斷為BigKey
    final static int STR_MAX_LEN = 10 * 1024;
    //設(shè)置集合類型允許的成員數(shù)量上限,超過這個上限就判斷為BigKey
    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();
        }
    }

}

3)第三方工具

利用第三方工具,這里推薦Redis-Rdb-Tools,它會針對Redis的RDB快照文件來分析內(nèi)存使用情況,由于分析的是快照文件,因此不會占用Redis服務(wù)的任何性能,但是時效性相對較差

Redis-Rdb-Tools的github網(wǎng)址:https://github.com/sripathikrishnan/redis-rdb-tools

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

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

在這里插入圖片描述

2.4 如何刪除BigKey

BigKey內(nèi)存占用較多,因此即便我們使用的是刪除操作,刪除BigKey也需要耗費(fèi)很長時間,導(dǎo)致Redis主線程阻塞,引發(fā)一系列問題。

如果redis版本在4.0之后,我們可以通過異步刪除命令unlink來刪除一個BigKey,該命令會先把數(shù)據(jù)標(biāo)記為已刪除,然后再異步執(zhí)行刪除操作。

如果redis版本在4.0之前,針對集合類型,我們可以先遍歷BigKey中所有的元素,先將子元素逐個刪除,最后再刪除BigKey。至于如何遍歷,針對不同的集合類型,可以參考以下不同的命令

在這里插入圖片描述

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

找出BigKey中,我們應(yīng)該如何對BigKey進(jìn)行優(yōu)化呢?這里我們需要選擇恰當(dāng)?shù)臄?shù)據(jù)類型

3.1 存儲對象

如果我們要存儲一個User對象,有三種存儲方式:

1)JSON字符串

將一整個對象轉(zhuǎn)成Json格式進(jìn)行存儲

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

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

缺點(diǎn):數(shù)據(jù)耦合,不夠靈活,且需要維護(hù)JSON結(jié)構(gòu),占用內(nèi)存相對較大

2)字段打散

將對象的不同屬性存儲到不同的key中

keyvalue
user:1:nameJack
user:1:age21

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

缺點(diǎn):由于每條數(shù)據(jù)都會有一些元信息需要存儲,因此將一個Key分成多個Key進(jìn)行存儲,占用的內(nèi)存會變的更大,且由于字段分散,當(dāng)我們需要做統(tǒng)一控制時會變得很困難

3)hash(推薦)

使用hash結(jié)構(gòu)來存儲對象,對象的一個屬性對應(yīng)集合中的一個成員

user:1namejack
age21

優(yōu)點(diǎn):hash結(jié)構(gòu)底層會使用ziplist壓縮列表,空間占用小,且可以靈活訪問對象的任意字段

缺點(diǎn):代碼編寫時相對復(fù)雜

3.2 Hash優(yōu)化

假如有一個hash類型的key,其中有100萬對field和value,field是自增id,這個key存在什么問題?如何優(yōu)化?

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

當(dāng)hash的entry數(shù)量超過500時,底層會使用哈希表存儲而不是ZipList,內(nèi)存占用會變得比較高,雖然這個數(shù)量限制我們是可以通過以下命令進(jìn)行修改的

config set hash-max-ziplist-entries 數(shù)量

但是entry數(shù)量如果實(shí)在太大了還是會導(dǎo)致BigKey問題,這是需要優(yōu)化的,這里提供以下兩種解決思路:

1)拆分為String類型(不推薦)

將Hash中的每個成員單獨(dú)使用一個String類型的key進(jìn)行存儲

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

這種方案是不推薦的,存在的問題如下

  • string結(jié)構(gòu)底層沒有太多內(nèi)存優(yōu)化的,且存儲這些key的同時也會存儲大量的元信息,雖然數(shù)據(jù)打散了,但是整體內(nèi)存占用更多了
  • 如果我們想要批量獲取這些數(shù)據(jù),會變得格外麻煩

2)拆分成多個Hash類型

拆分為小的hash,將 id / 100 作為key, 將id % 100 作為field,這樣每100個元素為一個Hash,這種方式相對上面兩種來說內(nèi)存占用會少很多,而且解決了Bigkey的問題,當(dāng)然多少個元素作為一個Hash是自己定義的,這里建議數(shù)量不要超過500

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

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

相關(guān)文章

  • 一文詳解Redis中的持久化

    一文詳解Redis中的持久化

    這篇文章主要介紹了一文詳解Redis中的持久化,持久化功能有效地避免因進(jìn)程退出造成的數(shù)據(jù)丟失問題,當(dāng)下次重啟時利用之前持久化的文件即可實(shí)現(xiàn)數(shù)據(jù)恢復(fù)
    2022-09-09
  • 全網(wǎng)最完整的Redis新手入門指導(dǎo)教程

    全網(wǎng)最完整的Redis新手入門指導(dǎo)教程

    這篇文章主要給大家介紹了Redis新手入門的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Redis集群詳解

    Redis集群詳解

    這篇文章主要介紹了Redis集群詳解,需要的朋友可以參考下
    2020-07-07
  • Redis教程之代理ip池設(shè)計方法詳解

    Redis教程之代理ip池設(shè)計方法詳解

    這篇文章主要介紹了Redis實(shí)現(xiàn)代理ip池的設(shè)計方法,文中給出了詳細(xì)的介紹與示例代碼,相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。
    2017-01-01
  • redis中5種數(shù)據(jù)基礎(chǔ)查詢命令

    redis中5種數(shù)據(jù)基礎(chǔ)查詢命令

    本文主要介紹了redis中5種數(shù)據(jù)基礎(chǔ)查詢命令,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • redis中bind配置的詳細(xì)步驟

    redis中bind配置的詳細(xì)步驟

    本文主要介紹了redis中bind配置的詳細(xì)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Redis數(shù)據(jù)類型string和Hash詳解

    Redis數(shù)據(jù)類型string和Hash詳解

    大家都知道Redis中有五大數(shù)據(jù)類型分別是String、List、Set、Hash和Zset,本文給大家分享Redis數(shù)據(jù)類型string和Hash的相關(guān)操作,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • 詳解Redis瘦身指南

    詳解Redis瘦身指南

    Redis應(yīng)該是開發(fā)者最常用的緩存服務(wù)器了,它豐富的數(shù)據(jù)結(jié)構(gòu),快速高效的內(nèi)存操作能幫助開發(fā)者迅速完成復(fù)雜功能的設(shè)計,作為一個內(nèi)存型數(shù)據(jù)庫,Redis經(jīng)常會遇到內(nèi)存問題,今天我們來談一下Redis常見的內(nèi)存滿的問題,介紹一下給 Redis “瘦身”的通用方式。
    2021-05-05
  • RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析

    RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析

    訂單服務(wù)涉及許多方面,分布式事務(wù),分布式鎖,例如訂單超時未支付要取消訂單,訂單如何防止重復(fù)提交,如何防止超賣、這里都會使用到,這篇文章主要介紹了RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析,需要的朋友可以參考下
    2024-07-07
  • Windows下安裝Redis服務(wù)的圖文教程

    Windows下安裝Redis服務(wù)的圖文教程

    Redis是有名的NoSql數(shù)據(jù)庫,一般Linux都會默認(rèn)支持。但在Windows環(huán)境中,可能需要手動安裝設(shè)置才能有效使用。下面通過本文給大家介紹Windows下安裝Redis服務(wù)的圖文教程,感興趣的朋友一起看看吧
    2018-08-08

最新評論

黎平县| 滦平县| 玉山县| 岳普湖县| 汾西县| 门源| 松潘县| 宣武区| 开鲁县| 乳山市| 新绛县| 遂宁市| 家居| 曲水县| 八宿县| 蛟河市| 镇远县| 波密县| 光泽县| 红原县| 铁岭市| 普安县| 红桥区| 繁峙县| 墨玉县| 兴仁县| 商河县| 青岛市| 黄大仙区| 潍坊市| 沧州市| 穆棱市| 巴里| 资阳市| 公主岭市| 石家庄市| 龙山县| 溧阳市| 兴仁县| 苏尼特右旗| 沁水县|