欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis面試必備之緩存設計規(guī)范與性能優(yōu)化詳解

 更新時間:2024年03月01日 09:48:32   作者:江-小北  
你是否在使用Redis時,不清楚Redis應該遵循的設計規(guī)范而苦惱,你是否在Redis出現(xiàn)性能問題時,不知道該如何優(yōu)化而發(fā)愁,快跟隨小編一起學習起來吧

一、Redis Key-Value設計規(guī)范&性能優(yōu)化

1. key名設計規(guī)范

(1)【建議】: 可讀性和可管理性

以業(yè)務名(或數(shù)據(jù)庫名)為前綴(防止key沖突),用冒號分隔,比如業(yè)務名:表名:id

(2)【建議】:簡潔性

保證語義的前提下,控制key的長度,當key較多時,內存占用也不容忽視,例如:

(3)【強制】:不要包含特殊字符

反例:包含空格、換行、單雙引號以及其他轉義字符

2. Value設計規(guī)范

(1)【強制】:拒絕bigkey(防止網(wǎng)卡流量、慢查詢)

在Redis中,一個字符串最大512MB,一個二級數(shù)據(jù)結構(例如hash、list、set、zset)可以存儲大約40億個(2^32-1)個元素,但實際中如果下面兩種情況,我就會認為它是bigkey。

  • 字符串類型:它的big體現(xiàn)在單個value值很大,一般認為超過10KB就是bigkey。
  • 非字符串類型:哈希、列表、集合、有序集合,它們的big體現(xiàn)在元素個數(shù)太多。

一般來說,string類型控制在10KB以內;

hash、list、set、zset元素個數(shù)不要超過5000。

反例:一個包含200萬個元素的list。

3. bigkey性能優(yōu)化

bigkey的危害:

1.導致redis阻塞

2.網(wǎng)絡擁塞

bigkey也就意味著每次獲取要產(chǎn)生的網(wǎng)絡流量較大;

假設一個bigkey為1MB,客戶端每秒訪問量為1000,那么每秒產(chǎn)生1000MB的流量,對于普通的千兆網(wǎng)卡(按照字節(jié)算是128MB/s)的服務器來說簡直是滅頂之災,而且一般服務器會采用單機多實例的方式來部署,也就是說一個bigkey可能會對其他實例也造成影響,其后果不堪設想。

3.過期刪除

有個bigkey,它安分守己(只執(zhí)行簡單的命令,例如hget、lpop、zscore等),但它設置了過期時間,當它過期后,會被刪除,如果沒有使用Redis 4.0的過期異步刪除(lazyfree-lazy- expire yes),就會存在阻塞Redis的可能性。

bigkey的產(chǎn)生:

一般來說,bigkey的產(chǎn)生都是由于程序設計不當,或者對于數(shù)據(jù)規(guī)模預料不清楚造成的,來看幾個例子:

  • 社交類: 粉絲列表,如果某些明星或者大v不精心設計下,必是bigkey。
  • 統(tǒng)計類: 例如按天存儲某項功能或者網(wǎng)站的用戶集合,除非沒幾個人用,否則必是bigkey。
  • 緩存類: 將數(shù)據(jù)從數(shù)據(jù)庫load出來序列化放到Redis里,這個方式非常常用,但有兩個地方需要注意,第一,是不是有必要把所有字段都緩存;第二,有沒有相關關聯(lián)的數(shù)據(jù),有的同學為了圖方便把相關數(shù)據(jù)都存一個key下,產(chǎn)生bigkey。

如何優(yōu)化bigkey

1、拆

如果是大List(big list),那么就可以拆成多個List:

比如拆成:list1、list2、...listN

如果是一個大的哈希表(big hash),可以將數(shù)據(jù)分段存儲:

比如一個大的key,假設存了1百萬的用戶數(shù)據(jù),可以拆分成 200個key,每個key下面存放5000個用戶數(shù)據(jù)

如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出來(例如有時候僅僅需要 hmget,而不是hgetall),刪除也是一樣,盡量使用優(yōu)雅的方式來處理。

2、選擇合適的數(shù)據(jù)類型【推薦】

最好的優(yōu)化方案其實是在設計階段,所以我們在使用Redis時,在設計階段就應該盡量避免bigkey,所以選擇合適的數(shù)據(jù)類型尤為重要。

例如:實體類型(要合理控制和使用數(shù)據(jù)結構,但也要注意節(jié)省內存和性能質檢的平衡)

錯誤的做法:

set user:1:name tom
set user:1:age 19
set user:1:favor football

正確的做法:

hmset user:1 name tom age 19 favor football

3、控制key的生命周期,redis不是垃圾桶,當不需要使用的數(shù)據(jù),及時過期清理【推薦】

建議使用Expire設置過期時間

條件允許可以打散過期時間,防止幾種過期

比如:設置key的過期時間時,采用固定過期時間+一定范圍內的隨機數(shù)

二、Redis命令的使用規(guī)范&性能優(yōu)化

1、使用O(N)類型的命令要注意關注N的數(shù)量【推薦】

比如hgetall、lrange、smembers、zrange、sinter等并非不能使用。

但是在使用的時候一定要明確N的值,不然就可能由于查詢數(shù)據(jù)太大導致redis阻塞。

建議:有遍歷的需求時可以使用hscan、sscan、zscan代替

2、生產(chǎn)環(huán)境禁用部分高危命令【推薦】

禁止線上使用keys、flushall、flushdb等,通過redis的rename機制禁掉命令。

當有需要掃描的需要時,建議使用scan方式漸進式處理

3、合理使用select【推薦】

redis的多數(shù)據(jù)庫較弱,使用數(shù)字進行區(qū)分,很多客戶端支持較差,同時多業(yè)務用多數(shù)據(jù)庫實際還是單線程處理,會有干擾

所以建議redis使用數(shù)據(jù)庫只用序號0的數(shù)據(jù)庫即可,在0數(shù)據(jù)庫里采用key前綴區(qū)分業(yè)務即可

4、使用批量操作提高效率【推薦】

當我們要插入多個key時,可以采用一些批量命令代替單個命令,提高查詢效率,例如:

  • 原生命令:例如mget、mset。
  • 非原生命令:可以使用pipeline提高效率。

但要注意控制一次批量操作的元素個數(shù)(例如500以內,實際也和元素字節(jié)數(shù)有關)。

注意兩者不同:

  • 原生命令是原子操作,pipeline是非原子操作。
  • pipeline可以打包不同的命令,原生命令做不到
  • pipeline需要客戶端和服務端同時支持。

5、redis事務功能較弱,不建議過多使用redis的事務命令

如果業(yè)務上有需要,可以使用lua替代【建議】

三、客戶端使用規(guī)范&性能優(yōu)化

1、避免多個應用使用同一個Redis實例【推薦】

錯誤的做法:

多個業(yè)務線公用同一個redis實例,比如訂單、庫存、權限都用同一個redis實例,只要有一塊業(yè)務有阻塞,所有業(yè)務都會受影響。

正確的做法:

不相干的業(yè)務拆分為獨立的redis實例,比如訂單、庫存、權限拆分為3個redis實例。

2、客戶端連接使用帶有連接池的連接,可以有效控制連接,同時提高效率:

Jedis使用連接池方式:

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(5);
jedisPoolConfig.setMaxIdle(2);
jedisPoolConfig.setTestOnBorrow(true);

JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.0.60", 6379, 3000, null);
Jedis jedis = null;

使用連接池執(zhí)行命令:

try {
    jedis = jedisPool.getResource();
    //執(zhí)行具體的命令
    jedis.executeCommand()
} catch (Exception e) {
    logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
//注意這里不是關閉連接,在JedisPool模式下,Jedis會被歸還給資源池。
if (jedis != null)
    jedis.close();
}

3、連接池配置參數(shù)優(yōu)化建議

1、maxTotal優(yōu)化:最大連接數(shù)(早期版本叫maxActive)【建議】

實際上最大連接數(shù)該如何優(yōu)化,是一個很難回答的問題,考慮的因素有很多:

比如:

  • 業(yè)務希望的Redis并發(fā)量
  • 客戶端執(zhí)行命令時間
  • Redis資源:例如nodes(實例應用個數(shù))* maxTotal是不能超過Redis的最大連接數(shù)maxClients
  • 資源開銷:例如雖然希望控制空閑連接(連接池此刻可馬上使用的連接),但是又不希望因為連接池的頻繁釋放、創(chuàng)建連接造成不必要的開銷。

以一個例子說明,假設:

一次命令時間(borrow|return resource + Jedis執(zhí)行命令(含網(wǎng)絡) )的平均耗時約為1ms,一個連接的QPS大約是1000

業(yè)務期望的QPS是50000

那么理論上需要的資源池大小是50000 / 1000 = 50個。但事實上這是個理論值,還要考慮到要比理論值預留一些資源,通常來講maxTotal可以比理論值大一些。

但這個值不是越大越好,一方面連接太多占用客戶端和服務端資源,另一方面對于Redis這種高QPS的服務器,一個大命令的阻塞即使設置再大資源池仍然會無濟于事。

2、maxldle和minldle優(yōu)化:(資源池允許最大空閑連接數(shù)和資源池確保最少空閑連接數(shù))【建議】

maxldle(最大空閑連接數(shù)):

maxIdle實際上才是業(yè)務需要的最大連接數(shù),maxTotal是為了給出余量,所以maxIdle不要設置過小,否則會有new Jedis(新連接)開銷。

連接池的最佳性能是maxTotal = maxIdle,這樣就避免連接池伸縮帶來的性能干擾。但是如果并發(fā)量不大或者maxTotal設置過高,會導致不必要的連接資源浪費。一般推薦maxIdle可以設置為按上面的業(yè)務期望QPS計算出來的理論連接,maxTotal可以再放大一倍。

minIdle(最小空閑連接數(shù)):

minIdle與其說是最小空閑連接數(shù),不如說是"至少需要保持的空閑連接數(shù)",在使用連接的過程中,如果連接數(shù)超過了minIdle,那么繼續(xù)建立連接,如果超過了maxIdle,當超過的連接執(zhí)行完業(yè)務后會慢慢被移出連接池釋放掉

所以最小空閑連接數(shù)需要根據(jù)自己的業(yè)務規(guī)模和客戶端規(guī)模自行評估配置

【建議】:

如果你的系統(tǒng)QPS很高,系統(tǒng)啟動完馬上就會有很多的請求過來,那么可以給redis連接池做預熱,比如快速的創(chuàng)建一些redis連接,執(zhí)行簡單命令,類似ping(),快速的將連接池里的空閑連接提升到minIdle的數(shù)量。

連接池預熱示例代碼:

List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
    Jedis jedis = null;
    try {
            jedis = pool.getResource();
            minIdleJedisList.add(jedis);
            jedis.ping();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
        //注意,這里不能馬上close將連接還回連接池,否則最后連接池里只會建立1個連接。。
        //jedis.close();
        }
    }
    //統(tǒng)一將預熱的連接還回連接池
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
    Jedis jedis = null;
    try {
        jedis = minIdleJedisList.get(i);
        //將連接歸還回連接池
        jedis.close();
      } catch (Exception e) {
        logger.error(e.getMessage(), e);
      } finally {

     }
}

總之,要根據(jù)實際系統(tǒng)的QPS和調用redis客戶端的規(guī)模整體評估每個節(jié)點所使用的連接池大小

3、【建議】高并發(fā)下,建議客戶端添加熔斷功能

(例如接入sentinel、hystrix)

4、【推薦】設置合理的密碼

有必要可以使用SSL加密訪問

5、【建議】設置合適的緩存淘汰策略

LRU 算法(Least Recently Used,最近最少使用)

淘汰很久沒被訪問過的數(shù)據(jù),以最近一次訪問時間作為參考。

LFU 算法(Least Frequently Used,最不經(jīng)常使用)

淘汰最近一段時間被訪問次數(shù)最少的數(shù)據(jù),以次數(shù)作為參考。

當存在熱點數(shù)據(jù)時,LRU的效率很好,但偶發(fā)性的、周期性的批量操作會導致LRU命中率急劇下降,緩存污染情況比較嚴重。這時使用LFU可能更好點。

根據(jù)自身業(yè)務類型,配置好maxmemory-policy(默認是noeviction),推薦使用volatile-lru。如果不設置最大內存,當 Redis 內存超出物理內存限制時,內存的數(shù)據(jù)會開始和磁盤產(chǎn)生頻繁的交換 (swap),會讓 Redis 的性能急劇下降。

當Redis運行在主從模式時,只有主結點才會執(zhí)行過期刪除策略,然后把刪除操作”del key”同

步到從結點刪除數(shù)據(jù)。

四、系統(tǒng)內核參數(shù)優(yōu)化

1、vm.swapiness配置,根據(jù)linux版本選擇配置(默認0)

swap對于操作系統(tǒng)來說比較重要,當物理內存不足時,可以將一部分內存頁進行swap到硬盤上,以解燃眉之急。

但世界上沒有免費午餐,swap空間由硬盤提供,對于需要高并發(fā)、高吞吐的應用來說,磁盤IO通常會成為系統(tǒng)瓶頸。

在Linux中,并不是要等到所有物理內存都使用完才會使用到swap,系統(tǒng)參數(shù)swppiness會決定操作系統(tǒng)使用swap的傾向程度。swappiness的取值范圍是0~100,swappiness的值越大,說明操作系統(tǒng)可能使用swap的概率越高,swappiness值越低,表示操作系統(tǒng)更加傾向于使用物理內存。

swappiness的取值越大,說明操作系統(tǒng)可能使用swap的概率越高,越低則越傾向于使用物理內存。

如果linux內核版本<3.5,那么swapiness設置為0,這樣系統(tǒng)寧愿swap也不會oom kille(殺掉進程)

如果linux內核版本>=3.5,那么swapiness設置為1,這樣系統(tǒng)寧愿swap也不會oom killer

一般需要保證redis不會被kill掉:

cat /proc/version #查看linux內核版本
echo 1 > /proc/sys/vm/swappiness
echo vm.swapiness=1 >> /etc/sysctl.conf

PS:OOM killer 機制是指Linux操作系統(tǒng)發(fā)現(xiàn)可用內存不足時,強制殺死一些用戶進程(非內核進程),來保證系統(tǒng)有足夠的可用內存進行分配。

2、vm.overcommit_memory配置改為1(默認0)

0:表示內核將檢查是否有足夠的可用物理內存(實際不一定用滿)供應用進程使用;

  • 如果有足夠的可用物理內存,內存申請允許;
  • 否則,內存申請失敗,并把錯誤返回給應用進程

1:表示內核允許分配所有的物理內存,而不管當前的內存狀態(tài)如何;

如果是0的話,可能導致類似fork等操作執(zhí)行失敗,申請不到足夠的內存空間

Redis建議把這個值設置為1,就是為了讓fork操作能夠在低內存下也執(zhí)行成功。

cat /proc/sys/vm/overcommit_memory
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1

3、合理設置文件句柄數(shù)

操作系統(tǒng)進程試圖打開一個文件(或者叫句柄),但是現(xiàn)在進程打開的句柄數(shù)已經(jīng)達到了上限,繼續(xù)打開會報錯:“Too many open files”

ulimit ‐a #查看系統(tǒng)文件句柄數(shù),看open files那項
ulimit ‐n 65535 #設置系統(tǒng)文件句柄數(shù)

總結

本文梳理了在使用Redis過程需要遵循的一些最佳實踐,包括針對架構維度的一些深入性能優(yōu)化的知識,如果面試官問你:"說下在使用Redis的過程中,需要注意哪些規(guī)范?",如果你按照本文的思路回答,肯定能讓面試官眼前一亮,offer自然就到手了。

以上就是Redis面試必備之緩存設計規(guī)范與性能優(yōu)化詳解的詳細內容,更多關于Redis緩存設計規(guī)范與性能優(yōu)化的資料請關注腳本之家其它相關文章!

相關文章

  • Redis在項目中常見的12種使用場景示例和說明

    Redis在項目中常見的12種使用場景示例和說明

    Redis是一個開源的高性能鍵值對數(shù)據(jù)庫,它以其內存中數(shù)據(jù)存儲、鍵過期策略、持久化、事務、豐富的數(shù)據(jù)類型支持以及原子操作等特性,在許多項目中扮演著關鍵角色,以下是整理的12個Redis在項目中常見的使用場景舉例說明和解釋
    2024-06-06
  • nestjs使用redis實現(xiàn)ip限流的步驟詳解

    nestjs使用redis實現(xiàn)ip限流的步驟詳解

    如果使用nestjs開發(fā)接口并部署之后,我們通常需要考慮到接口是否會被惡意盜刷消耗過多的資源,一個簡單的方式就是限制在單位時間內的訪問次數(shù),所以本文給大家介紹了nestjs使用redis實現(xiàn)ip限流的步驟,需要的朋友可以參考下
    2025-01-01
  • springboot使用Redis作緩存使用入門教程

    springboot使用Redis作緩存使用入門教程

    這篇文章主要介紹了springboot使用Redis作緩存使用入門教程,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • Redis 實現(xiàn)好友關注和關注推送的示例代碼

    Redis 實現(xiàn)好友關注和關注推送的示例代碼

    本文介紹了使用Redis實現(xiàn)好友關注和關注推送功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-03-03
  • Redis搶單預熱的實現(xiàn)示例

    Redis搶單預熱的實現(xiàn)示例

    本文主要介紹了Redis搶單預熱的實現(xiàn)示例,以應對搶單活動帶來的高并發(fā)訪問壓力,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • 如何自定義redis工具jar包供其他SpringBoot項目直接使用

    如何自定義redis工具jar包供其他SpringBoot項目直接使用

    這篇文章主要介紹了如何自定義redis工具jar包供其他SpringBoot項目直接使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Redis遠程連接Redis客戶端的實現(xiàn)步驟

    Redis遠程連接Redis客戶端的實現(xiàn)步驟

    本文主要介紹了Redis遠程連接Redis客戶端的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 關于Redis單線程的正確理解

    關于Redis單線程的正確理解

    很多同學對Redis的單線程和I/O多路復用技術并不是很了解,所以我用簡單易懂的語言讓大家了解下Redis單線程和I/O多路復用技術的原理,對學好和運用好Redis打下基礎,感興趣的朋友跟隨小編一起看看吧
    2021-11-11
  • 淺談Redis中的緩存更新策略

    淺談Redis中的緩存更新策略

    這篇文章主要介紹了淺談Redis中的緩存更新策略,CacheAsidePatter是我們比較常用的緩存更新策略,其由緩存調用者在更新數(shù)據(jù)庫時,在業(yè)務邏輯中設置緩存更新,需要的朋友可以參考下
    2023-08-08
  • 分布式使用Redis實現(xiàn)數(shù)據(jù)庫對象自增主鍵ID

    分布式使用Redis實現(xiàn)數(shù)據(jù)庫對象自增主鍵ID

    本文介紹在分布式項目中使用Redis生成對象的自增主鍵ID,通過Redis的INCR等命令實現(xiàn)計數(shù)器功能,具有一定的參考價值,感興趣的可以了解一下
    2024-12-12

最新評論