精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

使用Redis是你必須知道的21個(gè)注意要點(diǎn)

數(shù)據(jù)分析與開發(fā) ? 來(lái)源:掘金 ? 作者:撿田螺的小男孩 ? 2021-04-29 17:04 ? 次閱讀

前言

最近在學(xué)習(xí)Redis相關(guān)知識(shí),看了阿里的redis開發(fā)規(guī)范,以及Redis開發(fā)與運(yùn)維這本書。分使用規(guī)范、有坑的命令、項(xiàng)目實(shí)戰(zhàn)操作、運(yùn)維配置四個(gè)方向,整理了使用Redis的21個(gè)注意點(diǎn),希望對(duì)大家有幫助,一起學(xué)習(xí)哈

ade9a7da-a8c8-11eb-9728-12bb97331649.png

1、Redis的使用規(guī)范

1.1、 key的規(guī)范要點(diǎn)

我們?cè)O(shè)計(jì)Redis的key的時(shí)候,要注意以下這幾個(gè)點(diǎn):

以業(yè)務(wù)名為key前綴,用冒號(hào)隔開,以防止key沖突覆蓋。如,live1

確保key的語(yǔ)義清晰的情況下,key的長(zhǎng)度盡量小于30個(gè)字符。

key禁止包含特殊字符,如空格、換行、單雙引號(hào)以及其他轉(zhuǎn)義字符。

Redis的key盡量設(shè)置ttl,以保證不使用的Key能被及時(shí)清理或淘汰。

?

1.2、value的規(guī)范要點(diǎn)

Redis的value值不可以隨意設(shè)置的哦。

「第一點(diǎn)」,如果大量存儲(chǔ)bigKey是會(huì)有問(wèn)題的,會(huì)導(dǎo)致慢查詢,內(nèi)存增長(zhǎng)過(guò)快等等。

如果是String類型,單個(gè)value大小控制10k以內(nèi)。

如果是hash、list、set、zset類型,元素個(gè)數(shù)一般不超過(guò)5000。

「第二點(diǎn)」,要選擇適合的數(shù)據(jù)類型。不少小伙伴只用Redis的String類型,上來(lái)就是set和get。實(shí)際上,Redis 提供了「豐富的數(shù)據(jù)結(jié)構(gòu)類型」,有些業(yè)務(wù)場(chǎng)景,更適合hash、zset等其他數(shù)據(jù)結(jié)果。

ae391324-a8c8-11eb-9728-12bb97331649.png

「反例:」

setusernamejay setuserage18

「正例」

hmsetuser:666namejayage18

1.3. 給Key設(shè)置過(guò)期時(shí)間,同時(shí)注意不同業(yè)務(wù)的key,盡量過(guò)期時(shí)間分散一點(diǎn)

因?yàn)镽edis的數(shù)據(jù)是存在內(nèi)存中的,而內(nèi)存資源是很寶貴的。

我們一般是把Redis當(dāng)做緩存來(lái)用,而「不是數(shù)據(jù)庫(kù)」,所以key的生命周期就不宜太長(zhǎng)久啦。

因此,你的key,一般建議用「expire設(shè)置過(guò)期時(shí)間」。

如果大量的key在某個(gè)時(shí)間點(diǎn)集中過(guò)期,到過(guò)期的那個(gè)時(shí)間點(diǎn),Redis可能會(huì)存在卡頓,甚至出現(xiàn)「緩存雪崩」現(xiàn)象,因此一般不同業(yè)務(wù)的key,過(guò)期時(shí)間應(yīng)該分散一些。有時(shí)候,同業(yè)務(wù)的,也可以在時(shí)間上加一個(gè)隨機(jī)值,讓過(guò)期時(shí)間分散一些。

1.4.建議使用批量操作提高效率

我們?nèi)粘慡QL的時(shí)候,都知道,批量操作效率會(huì)更高,一次更新50條,比循環(huán)50次,每次更新一條效率更高。其實(shí)Redis操作命令也是這個(gè)道理。

Redis客戶端執(zhí)行一次命令可分為4個(gè)過(guò)程:1.發(fā)送命令-> 2.命令排隊(duì)-> 3.命令執(zhí)行-> 4. 返回結(jié)果。1和4 稱為RRT(命令執(zhí)行往返時(shí)間)。Redis提供了「批量操作命令,如mget、mset」等,可有效節(jié)約RRT。但是呢,大部分的命令,是不支持批量操作的,比如hgetall,并沒(méi)有mhgetall存在。「Pipeline」則可以解決這個(gè)問(wèn)題。

Pipeline是什么呢?它能將一組Redis命令進(jìn)行組裝,通過(guò)一次RTT傳輸給Redis,再將這組Redis命令的執(zhí)行結(jié)果按順序返回給客戶端.

我們先來(lái)看下沒(méi)有使用Pipeline執(zhí)行了n條命令的模型:

aebbded0-a8c8-11eb-9728-12bb97331649.png

使用Pipeline執(zhí)行了n次命令,整個(gè)過(guò)程需要1次RTT,模型如下:

af0f70ea-a8c8-11eb-9728-12bb97331649.png

2、Redis 有坑的那些命令

2.1. 慎用O(n)復(fù)雜度命令,如hgetall、smember,lrange等

因?yàn)镽edis是單線程執(zhí)行命令的。hgetall、smember等命令時(shí)間復(fù)雜度為O(n),當(dāng)n持續(xù)增加時(shí),會(huì)導(dǎo)致 Redis CPU 持續(xù)飆高,阻塞其他命令的執(zhí)行。

hgetall、smember,lrange等這些命令不是一定不能使用,需要綜合評(píng)估數(shù)據(jù)量,明確n的值,再去決定。比如hgetall,如果哈希元素n比較多的話,可以優(yōu)先考慮使用「hscan」。

2.2 慎用Redis的monitor命令

Redis Monitor 命令用于實(shí)時(shí)打印出Redis服務(wù)器接收到的命令,如果我們想知道客戶端對(duì)redis服務(wù)端做了哪些命令操作,就可以用Monitor 命令查看,但是它一般「調(diào)試」用而已,盡量不要在生產(chǎn)上用!因?yàn)椤竚onitor命令可能導(dǎo)致redis的內(nèi)存持續(xù)飆升?!?/p>

monitor的模型是醬紫的,它會(huì)將所有在Redis服務(wù)器執(zhí)行的命令進(jìn)行輸出,一般來(lái)講Redis服務(wù)器的QPS是很高的,也就是如果執(zhí)行了monitor命令,Redis服務(wù)器在Monitor這個(gè)客戶端的輸出緩沖區(qū)又會(huì)有大量“存貨”,也就占用了大量Redis內(nèi)存。

af1f8976-a8c8-11eb-9728-12bb97331649.png

2.3、生產(chǎn)環(huán)境不能使用 keys指令

Redis Keys 命令用于查找所有符合給定模式pattern的key。如果想查看Redis 某類型的key有多少個(gè),不少小伙伴想到用keys命令,如下:

keyskey前綴*

但是,redis的keys是遍歷匹配的,復(fù)雜度是O(n),數(shù)據(jù)庫(kù)數(shù)據(jù)越多就越慢。我們知道,redis是單線程的,如果數(shù)據(jù)比較多的話,keys指令就會(huì)導(dǎo)致redis線程阻塞,線上服務(wù)也會(huì)停頓了,直到指令執(zhí)行完,服務(wù)才會(huì)恢復(fù)。因此,「一般在生產(chǎn)環(huán)境,不要使用keys指令」。官方文檔也有聲明:

Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using sets.

其實(shí),可以使用scan指令,它同keys命令一樣提供模式匹配功能。它的復(fù)雜度也是 O(n),但是它通過(guò)游標(biāo)分步進(jìn)行,「不會(huì)阻塞redis線程」;但是會(huì)有一定的「重復(fù)概率」,需要在「客戶端做一次去重」。

scan支持增量式迭代命令,增量式迭代命令也是有缺點(diǎn)的:舉個(gè)例子, 使用 SMEMBERS 命令可以返回集合鍵當(dāng)前包含的所有元素, 但是對(duì)于 SCAN 這類增量式迭代命令來(lái)說(shuō), 因?yàn)樵趯?duì)鍵進(jìn)行增量式迭代的過(guò)程中, 鍵可能會(huì)被修改, 所以增量式迭代命令只能對(duì)被返回的元素提供有限的保證 。

2.4 禁止使用flushall、flushdb

Flushall 命令用于清空整個(gè) Redis 服務(wù)器的數(shù)據(jù)(刪除所有數(shù)據(jù)庫(kù)的所有 key )。

Flushdb 命令用于清空當(dāng)前數(shù)據(jù)庫(kù)中的所有 key。

這兩命令是原子性的,不會(huì)終止執(zhí)行。一旦開始執(zhí)行,不會(huì)執(zhí)行失敗的。

2.5 注意使用del命令

刪除key你一般使用什么命令?是直接del?如果刪除一個(gè)key,直接使用del命令當(dāng)然沒(méi)問(wèn)題。但是,你想過(guò)del的時(shí)間復(fù)雜度是多少嘛?我們分情況探討一下:

如果刪除一個(gè)String類型的key,時(shí)間復(fù)雜度就是O(1),「可以直接del」。

如果刪除一個(gè)List/Hash/Set/ZSet類型時(shí),它的復(fù)雜度是O(n), n表示元素個(gè)數(shù)。

因此,如果你刪除一個(gè)List/Hash/Set/ZSet類型的key時(shí),元素越多,就越慢。「當(dāng)n很大時(shí),要尤其注意」,會(huì)阻塞主線程的。那么,如果不用del,我們應(yīng)該怎么刪除呢?

如果是List類型,你可以執(zhí)行l(wèi)pop或者rpop,直到所有元素刪除完成。

如果是Hash/Set/ZSet類型,你可以先執(zhí)行hscan/sscan/scan查詢,再執(zhí)行hdel/srem/zrem依次刪除每個(gè)元素。

2.6 避免使用SORT、SINTER等復(fù)雜度過(guò)高的命令。

執(zhí)行復(fù)雜度較高的命令,會(huì)消耗更多的 CPU 資源,會(huì)阻塞主線程。所以你要避免執(zhí)行如SORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE等聚合命令,一般建議把它放到客戶端來(lái)執(zhí)行。

3、項(xiàng)目實(shí)戰(zhàn)避坑操作

3.1 分布式鎖使用的注意點(diǎn)

分布式鎖其實(shí)就是,控制分布式系統(tǒng)不同進(jìn)程共同訪問(wèn)共享資源的一種鎖的實(shí)現(xiàn)。秒殺下單、搶紅包等等業(yè)務(wù)場(chǎng)景,都需要用到分布式鎖。我們經(jīng)常使用Redis作為分布式鎖,主要有這些注意點(diǎn):

3.1.1 兩個(gè)命令SETNX + EXPIRE分開寫(典型錯(cuò)誤實(shí)現(xiàn)范例)

if(jedis.setnx(key_resource_id,lock_value)==1){//加鎖 expire(key_resource_id,100);//設(shè)置過(guò)期時(shí)間 try{ dosomething//業(yè)務(wù)請(qǐng)求 }catch(){ } finally{ jedis.del(key_resource_id);//釋放鎖 } }

如果執(zhí)行完setnx加鎖,正要執(zhí)行expire設(shè)置過(guò)期時(shí)間時(shí),進(jìn)程crash或者要重啟維護(hù)了,那么這個(gè)鎖就“長(zhǎng)生不老”了,「別的線程永遠(yuǎn)獲取不到鎖」啦,所以一般分布式鎖不能這么實(shí)現(xiàn)。

3.1.2 SETNX + value值是過(guò)期時(shí)間 (有些小伙伴是這么實(shí)現(xiàn),有坑)

longexpires=System.currentTimeMillis()+expireTime;//系統(tǒng)時(shí)間+設(shè)置的過(guò)期時(shí)間 StringexpiresStr=String.valueOf(expires); //如果當(dāng)前鎖不存在,返回加鎖成功 if(jedis.setnx(key_resource_id,expiresStr)==1){ returntrue; } //如果鎖已經(jīng)存在,獲取鎖的過(guò)期時(shí)間 StringcurrentValueStr=jedis.get(key_resource_id); //如果獲取到的過(guò)期時(shí)間,小于系統(tǒng)當(dāng)前時(shí)間,表示已經(jīng)過(guò)期 if(currentValueStr!=null&&Long.parseLong(currentValueStr)

//鎖已過(guò)期,獲取上一個(gè)鎖的過(guò)期時(shí)間,并設(shè)置現(xiàn)在鎖的過(guò)期時(shí)間(不了解redis的getSet命令的小伙伴,可以去官網(wǎng)看下哈) StringoldValueStr=jedis.getSet(key_resource_id,expiresStr); if(oldValueStr!=null&&oldValueStr.equals(currentValueStr)){ //考慮多線程并發(fā)的情況,只有一個(gè)線程的設(shè)置值和當(dāng)前值相同,它才可以加鎖 returntrue; } } //其他情況,均返回加鎖失敗 returnfalse; }

這種方案的「缺點(diǎn)」:

過(guò)期時(shí)間是客戶端自己生成的,分布式環(huán)境下,每個(gè)客戶端的時(shí)間必須同步

沒(méi)有保存持有者的唯一標(biāo)識(shí),可能被別的客戶端釋放/解鎖。

鎖過(guò)期的時(shí)候,并發(fā)多個(gè)客戶端同時(shí)請(qǐng)求過(guò)來(lái),都執(zhí)行了jedis.getSet(),最終只能有一個(gè)客戶端加鎖成功,但是該客戶端鎖的過(guò)期時(shí)間,可能被別的客戶端覆蓋。

3.1.3:SET的擴(kuò)展命令(SET EX PX NX)(注意可能存在的問(wèn)題)

if(jedis.set(key_resource_id,lock_value,"NX","EX",100s)==1){//加鎖 try{ dosomething//業(yè)務(wù)處理 }catch(){ } finally{ jedis.del(key_resource_id);//釋放鎖 } }

這個(gè)方案還是可能存在問(wèn)題:

鎖過(guò)期釋放了,業(yè)務(wù)還沒(méi)執(zhí)行完。

鎖被別的線程誤刪。

3.1.4 SET EX PX NX + 校驗(yàn)唯一隨機(jī)值,再刪除(解決了誤刪問(wèn)題,還是存在鎖過(guò)期,業(yè)務(wù)沒(méi)執(zhí)行完的問(wèn)題)

if(jedis.set(key_resource_id,uni_request_id,"NX","EX",100s)==1){//加鎖 try{ dosomething//業(yè)務(wù)處理 }catch(){ } finally{ //判斷是不是當(dāng)前線程加的鎖,是才釋放 if(uni_request_id.equals(jedis.get(key_resource_id))){ jedis.del(lockKey);//釋放鎖 } } }

在這里,判斷是不是當(dāng)前線程加的鎖和釋放鎖不是一個(gè)原子操作。如果調(diào)用jedis.del()釋放鎖的時(shí)候,可能這把鎖已經(jīng)不屬于當(dāng)前客戶端,會(huì)解除他人加的鎖。

af3f388e-a8c8-11eb-9728-12bb97331649.png

一般也是用lua腳本代替。lua腳本如下:

ifredis.call('get',KEYS[1])==ARGV[1]then returnredis.call('del',KEYS[1]) else return0 end;

3.1.5 Redisson框架 + Redlock算法 解決鎖過(guò)期釋放,業(yè)務(wù)沒(méi)執(zhí)行完問(wèn)題+單機(jī)問(wèn)題

Redisson 使用了一個(gè)Watch dog解決了鎖過(guò)期釋放,業(yè)務(wù)沒(méi)執(zhí)行完問(wèn)題,Redisson原理圖如下:

af5508bc-a8c8-11eb-9728-12bb97331649.png

以上的分布式鎖,還存在單機(jī)問(wèn)題:

afc860d2-a8c8-11eb-9728-12bb97331649.png

如果線程一在Redis的master節(jié)點(diǎn)上拿到了鎖,但是加鎖的key還沒(méi)同步到slave節(jié)點(diǎn)。恰好這時(shí),master節(jié)點(diǎn)發(fā)生故障,一個(gè)slave節(jié)點(diǎn)就會(huì)升級(jí)為master節(jié)點(diǎn)。線程二就可以獲取同個(gè)key的鎖啦,但線程一也已經(jīng)拿到鎖了,鎖的安全性就沒(méi)了。

針對(duì)單機(jī)問(wèn)題,可以使用Redlock算法。有興趣的朋友可以看下我這篇文章哈,七種方案!探討Redis分布式鎖的正確使用姿勢(shì)

3.2 緩存一致性注意點(diǎn)

如果是讀請(qǐng)求,先讀緩存,后讀數(shù)據(jù)庫(kù)

如果寫請(qǐng)求,先更新數(shù)據(jù)庫(kù),再寫緩存

每次更新數(shù)據(jù)后,需要清除緩存

緩存一般都需要設(shè)置一定的過(guò)期失效

一致性要求高的話,可以使用biglog+MQ保證。

有興趣的朋友,可以看下我這篇文章哈:并發(fā)環(huán)境下,先操作數(shù)據(jù)庫(kù)還是先操作緩存?

3.3 合理評(píng)估Redis容量,避免由于頻繁set覆蓋,導(dǎo)致之前設(shè)置的過(guò)期時(shí)間無(wú)效。

我們知道,Redis的所有數(shù)據(jù)結(jié)構(gòu)類型,都是可以設(shè)置過(guò)期時(shí)間的。假設(shè)一個(gè)字符串,已經(jīng)設(shè)置了過(guò)期時(shí)間,你再去重新設(shè)置它,就會(huì)導(dǎo)致之前的過(guò)期時(shí)間無(wú)效。

affad094-a8c8-11eb-9728-12bb97331649.png

Redis setKey源碼如下:

voidsetKey(redisDb*db,robj*key,robj*val){ if(lookupKeyWrite(db,key)==NULL){ dbAdd(db,key,val); }else{ dbOverwrite(db,key,val); } incrRefCount(val); removeExpire(db,key);//去掉過(guò)期時(shí)間 signalModifiedKey(db,key); }

實(shí)際業(yè)務(wù)開發(fā)中,同時(shí)我們要合理評(píng)估Redis的容量,避免頻繁set覆蓋,導(dǎo)致設(shè)置了過(guò)期時(shí)間的key失效。新手小白容易犯這個(gè)錯(cuò)誤。

3.4 緩存穿透問(wèn)題

先來(lái)看一個(gè)常見的緩存使用方式:讀請(qǐng)求來(lái)了,先查下緩存,緩存有值命中,就直接返回;緩存沒(méi)命中,就去查數(shù)據(jù)庫(kù),然后把數(shù)據(jù)庫(kù)的值更新到緩存,再返回。

b0267334-a8c8-11eb-9728-12bb97331649.png

「緩存穿透」:指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)需要從數(shù)據(jù)庫(kù)查詢,查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到數(shù)據(jù)庫(kù)去查詢,進(jìn)而給數(shù)據(jù)庫(kù)帶來(lái)壓力。

通俗點(diǎn)說(shuō),讀請(qǐng)求訪問(wèn)時(shí),緩存和數(shù)據(jù)庫(kù)都沒(méi)有某個(gè)值,這樣就會(huì)導(dǎo)致每次對(duì)這個(gè)值的查詢請(qǐng)求都會(huì)穿透到數(shù)據(jù)庫(kù),這就是緩存穿透。

緩存穿透一般都是這幾種情況產(chǎn)生的:

「業(yè)務(wù)不合理的設(shè)計(jì)」,比如大多數(shù)用戶都沒(méi)開守護(hù),但是你的每個(gè)請(qǐng)求都去緩存,查詢某個(gè)userid查詢有沒(méi)有守護(hù)。

「業(yè)務(wù)/運(yùn)維/開發(fā)失誤的操作」,比如緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)都被誤刪除了。

黑客非法請(qǐng)求攻擊」,比如黑客故意捏造大量非法請(qǐng)求,以讀取不存在的業(yè)務(wù)數(shù)據(jù)。

「如何避免緩存穿透呢?」一般有三種方法。

如果是非法請(qǐng)求,我們?cè)贏PI入口,對(duì)參數(shù)進(jìn)行校驗(yàn),過(guò)濾非法值。

如果查詢數(shù)據(jù)庫(kù)為空,我們可以給緩存設(shè)置個(gè)空值,或者默認(rèn)值。但是如有有寫請(qǐng)求進(jìn)來(lái)的話,需要更新緩存哈,以保證緩存一致性,同時(shí),最后給緩存設(shè)置適當(dāng)?shù)倪^(guò)期時(shí)間。(業(yè)務(wù)上比較常用,簡(jiǎn)單有效)

使用布隆過(guò)濾器快速判斷數(shù)據(jù)是否存在。即一個(gè)查詢請(qǐng)求過(guò)來(lái)時(shí),先通過(guò)布隆過(guò)濾器判斷值是否存在,存在才繼續(xù)往下查。

布隆過(guò)濾器原理:它由初始值為0的位圖數(shù)組和N個(gè)哈希函數(shù)組成。一個(gè)對(duì)一個(gè)key進(jìn)行N個(gè)hash算法獲取N個(gè)值,在比特?cái)?shù)組中將這N個(gè)值散列后設(shè)定為1,然后查的時(shí)候如果特定的這幾個(gè)位置都為1,那么布隆過(guò)濾器判斷該key存在。

3.5 緩存雪奔問(wèn)題

「緩存雪奔:」指緩存中數(shù)據(jù)大批量到過(guò)期時(shí)間,而查詢數(shù)據(jù)量巨大,請(qǐng)求都直接訪問(wèn)數(shù)據(jù)庫(kù),引起數(shù)據(jù)庫(kù)壓力過(guò)大甚至down機(jī)。

緩存雪奔一般是由于大量數(shù)據(jù)同時(shí)過(guò)期造成的,對(duì)于這個(gè)原因,可通過(guò)均勻設(shè)置過(guò)期時(shí)間解決,即讓過(guò)期時(shí)間相對(duì)離散一點(diǎn)。如采用一個(gè)較大固定值+一個(gè)較小的隨機(jī)值,5小時(shí)+0到1800秒醬紫。

Redis 故障宕機(jī)也可能引起緩存雪奔。這就需要構(gòu)造Redis高可用集群啦。

3.6 緩存擊穿問(wèn)題

「緩存擊穿:」指熱點(diǎn)key在某個(gè)時(shí)間點(diǎn)過(guò)期的時(shí)候,而恰好在這個(gè)時(shí)間點(diǎn)對(duì)這個(gè)Key有大量的并發(fā)請(qǐng)求過(guò)來(lái),從而大量的請(qǐng)求打到db。

緩存擊穿看著有點(diǎn)像,其實(shí)它兩區(qū)別是,緩存雪奔是指數(shù)據(jù)庫(kù)壓力過(guò)大甚至down機(jī),緩存擊穿只是大量并發(fā)請(qǐng)求到了DB數(shù)據(jù)庫(kù)層面??梢哉J(rèn)為擊穿是緩存雪奔的一個(gè)子集吧。有些文章認(rèn)為它倆區(qū)別,是區(qū)別在于擊穿針對(duì)某一熱點(diǎn)key緩存,雪奔則是很多key。

解決方案就有兩種:

「1.使用互斥鎖方案」。緩存失效時(shí),不是立即去加載db數(shù)據(jù),而是先使用某些帶成功返回的原子操作命令,如(Redis的setnx)去操作,成功的時(shí)候,再去加載db數(shù)據(jù)庫(kù)數(shù)據(jù)和設(shè)置緩存。否則就去重試獲取緩存。

「2. “永不過(guò)期”」,是指沒(méi)有設(shè)置過(guò)期時(shí)間,但是熱點(diǎn)數(shù)據(jù)快要過(guò)期時(shí),異步線程去更新和設(shè)置過(guò)期時(shí)間。

3.7、緩存熱key問(wèn)題

在Redis中,我們把訪問(wèn)頻率高的key,稱為熱點(diǎn)key。如果某一熱點(diǎn)key的請(qǐng)求到服務(wù)器主機(jī)時(shí),由于請(qǐng)求量特別大,可能會(huì)導(dǎo)致主機(jī)資源不足,甚至宕機(jī),從而影響正常的服務(wù)。

而熱點(diǎn)Key是怎么產(chǎn)生的呢?主要原因有兩個(gè):

用戶消費(fèi)的數(shù)據(jù)遠(yuǎn)大于生產(chǎn)的數(shù)據(jù),如秒殺、熱點(diǎn)新聞等讀多寫少的場(chǎng)景。

請(qǐng)求分片集中,超過(guò)單Redi服務(wù)器的性能,比如固定名稱key,Hash落入同一臺(tái)服務(wù)器,瞬間訪問(wèn)量極大,超過(guò)機(jī)器瓶頸,產(chǎn)生熱點(diǎn)Key問(wèn)題。

那么在日常開發(fā)中,如何識(shí)別到熱點(diǎn)key呢?

憑經(jīng)驗(yàn)判斷哪些是熱Key;

客戶端統(tǒng)計(jì)上報(bào);

服務(wù)代理層上報(bào)

如何解決熱key問(wèn)題?

Redis集群擴(kuò)容:增加分片副本,均衡讀流量;

對(duì)熱key進(jìn)行hash散列,比如將一個(gè)key備份為key1,key2……keyN,同樣的數(shù)據(jù)N個(gè)備份,N個(gè)備份分布到不同分片,訪問(wèn)時(shí)可隨機(jī)訪問(wèn)N個(gè)備份中的一個(gè),進(jìn)一步分擔(dān)讀流量;

使用二級(jí)緩存,即JVM本地緩存,減少Redis的讀請(qǐng)求。

4. Redis配置運(yùn)維

4.1 使用長(zhǎng)連接而不是短連接,并且合理配置客戶端的連接池

如果使用短連接,每次都需要過(guò) TCP 三次握手、四次揮手,會(huì)增加耗時(shí)。然而長(zhǎng)連接的話,它建立一次連接,redis的命令就能一直使用,醬紫可以減少建立redis連接時(shí)間。

連接池可以實(shí)現(xiàn)在客戶端建立多個(gè)連接并且不釋放,需要使用連接的時(shí)候,不用每次都創(chuàng)建連接,節(jié)省了耗時(shí)。但是需要合理設(shè)置參數(shù),長(zhǎng)時(shí)間不操作 Redis時(shí),也需及時(shí)釋放連接資源。

4.2 只使用 db0

Redis-standalone架構(gòu)禁止使用非db0.原因有兩個(gè)

一個(gè)連接,Redis執(zhí)行命令select 0和select 1切換,會(huì)損耗新能。

Redis Cluster 只支持 db0,要遷移的話,成本高

4.3 設(shè)置maxmemory + 恰當(dāng)?shù)奶蕴呗浴?/p>

為了防止內(nèi)存積壓膨脹。比如有些時(shí)候,業(yè)務(wù)量大起來(lái)了,redis的key被大量使用,內(nèi)存直接不夠了,運(yùn)維小哥哥也忘記加大內(nèi)存了。難道redis直接這樣掛掉?所以需要根據(jù)實(shí)際業(yè)務(wù),選好maxmemory-policy(最大內(nèi)存淘汰策略),設(shè)置好過(guò)期時(shí)間。一共有8種內(nèi)存淘汰策略:

volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),從設(shè)置了過(guò)期時(shí)間的key中使用LRU(最近最少使用)算法進(jìn)行淘汰;

allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),從所有key中使用LRU(最近最少使用)算法進(jìn)行淘汰。

volatile-lfu:4.0版本新增,當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在過(guò)期的key中,使用LFU算法進(jìn)行刪除key。

allkeys-lfu:4.0版本新增,當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),從所有key中使用LFU算法進(jìn)行淘汰;

volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),從設(shè)置了過(guò)期時(shí)間的key中,隨機(jī)淘汰數(shù)據(jù);。

allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),從所有key中隨機(jī)淘汰數(shù)據(jù)。

volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的key中,根據(jù)過(guò)期時(shí)間進(jìn)行淘汰,越早過(guò)期的優(yōu)先被淘汰;

noeviction:默認(rèn)策略,當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),新寫入操作會(huì)報(bào)錯(cuò)。

4.4 開啟 lazy-free 機(jī)制

Redis4.0+版本支持lazy-free機(jī)制,如果你的Redis還是有bigKey這種玩意存在,建議把lazy-free開啟。當(dāng)開啟它后,Redis 如果刪除一個(gè) bigkey 時(shí),釋放內(nèi)存的耗時(shí)操作,會(huì)放到后臺(tái)線程去執(zhí)行,減少對(duì)主線程的阻塞影響。

pIYBAGCKd4-AW9MUAAB8XL2qvAE577.png

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    371

    瀏覽量

    10846

原文標(biāo)題:使用 Redis,你必須知道的 21 個(gè)注意要點(diǎn)

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    使用工業(yè)級(jí)路由器前,必須知道的這些事

    工業(yè)級(jí)路由器專為惡劣環(huán)境設(shè)計(jì),具有高穩(wěn)定性、可靠性、傳輸速率和覆蓋范圍。使用前需了解網(wǎng)絡(luò)架構(gòu),注意電源散熱和安全問(wèn)題。選擇型號(hào)需考慮需求,實(shí)施和維護(hù)也關(guān)鍵。建議咨詢專業(yè)人士以確保網(wǎng)絡(luò)安全穩(wěn)定。
    的頭像 發(fā)表于 05-22 11:41 ?380次閱讀

    強(qiáng)調(diào):關(guān)于變頻器,必須知道的哪些事情?

    分類選型 1) 采用變頻的目的:恒壓控制或恒流控制等。 2) 變頻器的負(fù)載類型:如葉片泵或容積泵等,特別注意負(fù)載的性能曲線,性能曲線決定了應(yīng)用時(shí)的方式方法。 3) 變頻器與負(fù)載的匹配問(wèn)題: I.電壓
    的頭像 發(fā)表于 03-11 08:39 ?503次閱讀
    強(qiáng)調(diào):關(guān)于變頻器,<b class='flag-5'>你</b><b class='flag-5'>必須知道</b>的哪些事情?

    什么是HMI:必須知道的定義、趨勢(shì)與關(guān)鍵特性

    所謂的HMI(Human-Machine Interface)就是人機(jī)界面,是操作者與機(jī)器/系統(tǒng)間資訊傳遞和交換的主要橋梁,也是實(shí)現(xiàn)工業(yè)自動(dòng)化的關(guān)鍵要素。HMI大多為帶有觸控功能的顯示屏或平板電腦,讓操作人員或維護(hù)人員能夠直接操作設(shè)備并進(jìn)行監(jiān)控。HMI系統(tǒng)通常能提供豐富的資訊,例如溫度、壓力、制造流程步驟以及材料的計(jì)量數(shù)據(jù)。還能顯示設(shè)備中物料的確切位置或儲(chǔ)存槽內(nèi)的液位數(shù)據(jù)等訊息。無(wú)論是在制造業(yè)、能源管理還是其他自動(dòng)化的重要行業(yè)領(lǐng)域,HMI都扮演著
    的頭像 發(fā)表于 01-16 11:11 ?4824次閱讀
    什么是HMI:<b class='flag-5'>你</b><b class='flag-5'>必須知道</b>的定義、趨勢(shì)與關(guān)鍵特性

    學(xué)習(xí)FPGA必須知道的社區(qū)

    學(xué)習(xí)FPGA必須知道的社區(qū)
    的頭像 發(fā)表于 01-03 17:51 ?359次閱讀
    學(xué)習(xí)FPGA<b class='flag-5'>必須知道</b>的社區(qū)

    POL負(fù)載點(diǎn)電源設(shè)計(jì)中有何訣竅?有兩點(diǎn)很關(guān)鍵,必須知道

    POL負(fù)載點(diǎn)電源設(shè)計(jì)中有何訣竅?有兩點(diǎn)很關(guān)鍵,必須知道
    的頭像 發(fā)表于 12-06 16:06 ?1911次閱讀
    POL負(fù)載點(diǎn)電源設(shè)計(jì)中有何訣竅?有兩點(diǎn)很關(guān)鍵,<b class='flag-5'>你</b><b class='flag-5'>必須知道</b>

    電阻的秘密——必須知道的電阻參數(shù)

    電阻的秘密——必須知道的電阻參數(shù)
    的頭像 發(fā)表于 12-06 14:31 ?823次閱讀
    電阻的秘密——<b class='flag-5'>你</b><b class='flag-5'>必須知道</b>的電阻參數(shù)

    redis容器內(nèi)怎么查看redis日志

    可以查看指定redis容器的日志: docker logs 請(qǐng)將``替換為redis容器的ID或名稱。該命令將
    的頭像 發(fā)表于 12-05 10:10 ?3502次閱讀

    redis的lru原理

    從緩存中進(jìn)行淘汰。下面將詳細(xì)介紹Redis的LRU原理。 概述 Redis使用一個(gè)雙向鏈表來(lái)維護(hù)緩存中的數(shù)據(jù),鏈表的頭部表示最近使用的數(shù)據(jù),而鏈表的尾部表示最久未使用的數(shù)據(jù)。每當(dāng)有新的數(shù)據(jù)被訪問(wèn)時(shí),
    的頭像 發(fā)表于 12-05 09:56 ?606次閱讀

    redis hash底層實(shí)現(xiàn)原理

    Redis是一個(gè)開源的內(nèi)存數(shù)據(jù)庫(kù),使用鍵值對(duì)存儲(chǔ)數(shù)據(jù)。其中,Redis中的數(shù)據(jù)結(jié)構(gòu)之一就是哈希(Hash),它提供了一種將多個(gè)字段(Field)存儲(chǔ)在一個(gè)鍵(Key)中的方法。那么
    的頭像 發(fā)表于 12-04 16:27 ?561次閱讀

    redis的持久化方式RDB和AOF的區(qū)別

    Redis 是一個(gè)高性能的鍵值對(duì)數(shù)據(jù)庫(kù),提供了兩種持久化方式:RDB 和 AOF。RDB 是將 Redis 的數(shù)據(jù)快照保存到磁盤上,而 AOF 則是將 Redis 的操作命令追加到文件
    的頭像 發(fā)表于 12-04 16:25 ?745次閱讀

    redis的哨兵和集群有什么區(qū)別

    重要的區(qū)別。 哨兵模式: 哨兵模式是一種用于實(shí)現(xiàn)Redis高可用性的方案。在哨兵模式下,有一個(gè)或多個(gè)哨兵進(jìn)程負(fù)責(zé)監(jiān)控Redis主節(jié)點(diǎn)和從節(jié)點(diǎn)的狀態(tài),并在主節(jié)點(diǎn)故障時(shí)自動(dòng)將一個(gè)從節(jié)點(diǎn)升級(jí)
    的頭像 發(fā)表于 12-04 14:53 ?2809次閱讀

    redis查看集群狀態(tài)命令

    Redis 是一個(gè)開源的、內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),提供了一系列命令來(lái)管理和操作數(shù)據(jù)。在 Redis 中,集群是一個(gè)由多個(gè) Redis 實(shí)例
    的頭像 發(fā)表于 12-04 11:39 ?1023次閱讀

    java redis鎖處理并發(fā)代碼

    在并發(fā)編程中,一個(gè)常見的問(wèn)題是如何確保多個(gè)線程安全地訪問(wèn)共享資源,避免產(chǎn)生競(jìng)態(tài)條件和數(shù)據(jù)異常。而Redis作為一種高性能的內(nèi)存數(shù)據(jù)庫(kù),可以提供分布式鎖的功能,通過(guò)Redis鎖,我們可以有效地解決并發(fā)
    的頭像 發(fā)表于 12-04 11:04 ?924次閱讀

    Java redis鎖怎么實(shí)現(xiàn)

    在Java中實(shí)現(xiàn)Redis鎖涉及到以下幾個(gè)方面:Redis的安裝配置、Redis連接池的使用、Redis數(shù)據(jù)結(jié)構(gòu)的選擇、實(shí)現(xiàn)分布式鎖的幾種方式等。 一、
    的頭像 發(fā)表于 12-04 10:47 ?1124次閱讀

    個(gè)注解搞定SpringBoot接口防刷

    技術(shù)要點(diǎn):springboot的基本知識(shí),redis基本操作,
    的頭像 發(fā)表于 11-28 10:46 ?386次閱讀