Redis 從入門到實(shí)戰(zhàn)

大家好光绕,這里是樂(lè)字節(jié)教育 Java后端。

這篇文章我想和你聊一聊 Redis 的最佳實(shí)踐。

你的項(xiàng)目或許已經(jīng)使用 Redis 很長(zhǎng)時(shí)間了骤宣,但在使用過(guò)程中,你可能還會(huì)或多或少地遇到以下問(wèn)題:

我的 Redis 內(nèi)存為什么增長(zhǎng)這么快序愚?

為什么我的 Redis 操作延遲變大了憔披?

如何降低 Redis 故障發(fā)生的頻率?

日常運(yùn)維 Redis 需要注意什么爸吮?

部署 Redis 時(shí)芬膝,如何做好資源規(guī)劃?

Redis 監(jiān)控重點(diǎn)要關(guān)注哪些指標(biāo)形娇?

尤其是當(dāng)你的項(xiàng)目越來(lái)越依賴 Redis 時(shí)蔗候,這些問(wèn)題就變得尤為重要。

此時(shí)埂软,你迫切需要一份「最佳實(shí)踐指南」锈遥。

這篇文章,我將從以下七個(gè)維度勘畔,帶你「全面」分析 Redis 的最佳實(shí)踐優(yōu)化:

內(nèi)存

性能

高可靠

日常運(yùn)維

資源規(guī)劃

監(jiān)控

安全

在文章的最后所灸,我還會(huì)給你一個(gè)完整的最佳實(shí)踐清單,不管你是業(yè)務(wù)開(kāi)發(fā)人員炫七,還是 DBA 運(yùn)維人員爬立,這個(gè)清單將會(huì)幫助你更加「優(yōu)雅」地用好 Redis。

這篇文章干貨很多万哪,希望你可以耐心讀完侠驯。

如何使用 Redis 更節(jié)省內(nèi)存?

首先奕巍,我們來(lái)看一下 Redis 內(nèi)存方面的優(yōu)化吟策。

眾所周知,Redis 的性能之所以如此之高的止,原因就在于它的數(shù)據(jù)都存儲(chǔ)在「內(nèi)存」中檩坚,所以訪問(wèn) Redis 中的數(shù)據(jù)速度極快。

但從資源利用率層面來(lái)說(shuō)诅福,機(jī)器的內(nèi)存資源相比于磁盤匾委,還是比較昂貴的。

當(dāng)你的業(yè)務(wù)應(yīng)用在 Redis 中存儲(chǔ)數(shù)據(jù)很少時(shí)氓润,你可能并不太關(guān)心內(nèi)存資源的使用情況赂乐。但隨著業(yè)務(wù)的發(fā)展,你的業(yè)務(wù)存儲(chǔ)在 Redis 中的數(shù)據(jù)就會(huì)越來(lái)越多咖气。

如果沒(méi)有提前制定好內(nèi)存優(yōu)化策略挨措,那么等業(yè)務(wù)開(kāi)始增長(zhǎng)時(shí)辐啄,Redis 占用的內(nèi)存也會(huì)開(kāi)始膨脹。

所以运嗜,提前制定合理的內(nèi)存優(yōu)化策略壶辜,對(duì)于資源利用率的提升是很有必要的。

那在使用 Redis 時(shí)担租,怎樣做才能更節(jié)省內(nèi)存呢砸民?這里我給你總結(jié)了 6 點(diǎn)建議,我們依次來(lái)看:

1) 控制 key 的長(zhǎng)度

最簡(jiǎn)單直接的內(nèi)存優(yōu)化奋救,就是控制 key 的長(zhǎng)度岭参。

在開(kāi)發(fā)業(yè)務(wù)時(shí),你需要提前預(yù)估整個(gè) Redis 中寫入 key 的數(shù)量尝艘,如果 key 數(shù)量達(dá)到了百萬(wàn)級(jí)別演侯,那么,過(guò)長(zhǎng)的 key 名也會(huì)占用過(guò)多的內(nèi)存空間背亥。

所以秒际,你需要保證 key 在簡(jiǎn)單、清晰的前提下狡汉,盡可能把 key 定義得短一些娄徊。

例如,原有的 key 為 user:book:123盾戴,則可以優(yōu)化為 u:bk:123寄锐。

這樣一來(lái),你的 Redis 就可以節(jié)省大量的內(nèi)存尖啡,這個(gè)方案對(duì)內(nèi)存的優(yōu)化非常直接和高效橄仆。

2) 避免存儲(chǔ) bigkey

除了控制 key 的長(zhǎng)度之外,你同樣需要關(guān)注 value 的大小衅斩,如果大量存儲(chǔ) bigkey盆顾,也會(huì)導(dǎo)致 Redis 內(nèi)存增長(zhǎng)過(guò)快。

除此之外矛渴,客戶端在讀寫 bigkey 時(shí)椎扬,還有產(chǎn)生性能問(wèn)題(下文會(huì)具體詳述)。

所以,你要避免在 Redis 中存儲(chǔ) bigkey障贸,我給你的建議是:

String:大小控制在 10KB 以下

List/Hash/Set/ZSet:元素?cái)?shù)量控制在 1 萬(wàn)以下

3) 選擇合適的數(shù)據(jù)類型

Redis 提供了豐富的數(shù)據(jù)類型戈二,這些數(shù)據(jù)類型在實(shí)現(xiàn)上,也對(duì)內(nèi)存使用做了優(yōu)化珊随。具體來(lái)說(shuō)就是,一種數(shù)據(jù)類型對(duì)應(yīng)多種數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn):

例如,String达皿、Set 在存儲(chǔ) int 數(shù)據(jù)時(shí)天吓,會(huì)采用整數(shù)編碼存儲(chǔ)。Hash峦椰、ZSet 在元素?cái)?shù)量比較少時(shí)(可配置)龄寞,會(huì)采用壓縮列表(ziplist)存儲(chǔ),在存儲(chǔ)比較多的數(shù)據(jù)時(shí)汤功,才會(huì)轉(zhuǎn)換為哈希表和跳表物邑。

作者這么設(shè)計(jì)的原因,就是為了進(jìn)一步節(jié)約內(nèi)存資源滔金。

那么你在存儲(chǔ)數(shù)據(jù)時(shí)色解,就可以利用這些特性來(lái)優(yōu)化 Redis 的內(nèi)存。這里我給你的建議如下:

String餐茵、Set:盡可能存儲(chǔ) int 類型數(shù)據(jù)

Hash科阎、ZSet:存儲(chǔ)的元素?cái)?shù)量控制在轉(zhuǎn)換閾值之下,以壓縮列表存儲(chǔ)忿族,節(jié)約內(nèi)存

4) 把 Redis 當(dāng)作緩存使用

Redis 數(shù)據(jù)存儲(chǔ)在內(nèi)存中锣笨,這也意味著其資源是有限的。你在使用 Redis 時(shí)道批,要把它當(dāng)做緩存來(lái)使用票唆,而不是數(shù)據(jù)庫(kù)。

所以屹徘,你的應(yīng)用寫入到 ?Redis 中的數(shù)據(jù)走趋,盡可能地都設(shè)置「過(guò)期時(shí)間」。

業(yè)務(wù)應(yīng)用在 Redis 中查不到數(shù)據(jù)時(shí)噪伊,再?gòu)暮蠖藬?shù)據(jù)庫(kù)中加載到 Redis 中簿煌。

采用這種方案,可以讓 Redis 中只保留經(jīng)常訪問(wèn)的「熱數(shù)據(jù)」鉴吹,內(nèi)存利用率也會(huì)比較高姨伟。

5) 實(shí)例設(shè)置 maxmemory + 淘汰策略

雖然你的 Redis key 都設(shè)置了過(guò)期時(shí)間,但如果你的業(yè)務(wù)應(yīng)用寫入量很大豆励,并且過(guò)期時(shí)間設(shè)置得比較久夺荒,那么短期間內(nèi) Redis 的內(nèi)存依舊會(huì)快速增長(zhǎng)。

如果不控制 Redis 的內(nèi)存上限良蒸,也會(huì)導(dǎo)致使用過(guò)多的內(nèi)存資源技扼。

對(duì)于這種場(chǎng)景,你需要提前預(yù)估業(yè)務(wù)數(shù)據(jù)量嫩痰,然后給這個(gè)實(shí)例設(shè)置 maxmemory 控制實(shí)例的內(nèi)存上限剿吻,這樣可以避免 Redis 的內(nèi)存持續(xù)膨脹。

配置了 maxmemory串纺,此時(shí)你還要設(shè)置數(shù)據(jù)淘汰策略丽旅,而淘汰策略如何選擇椰棘,你需要結(jié)合你的業(yè)務(wù)特點(diǎn)來(lái)決定:

volatile-lru / allkeys-lru:優(yōu)先保留最近訪問(wèn)過(guò)的數(shù)據(jù)

volatile-lfu / allkeys-lfu:優(yōu)先保留訪問(wèn)次數(shù)最頻繁的數(shù)據(jù)(4.0+版本支持)

volatile-ttl :優(yōu)先淘汰即將過(guò)期的數(shù)據(jù)

volatile-random / allkeys-random:隨機(jī)淘汰數(shù)據(jù)

6) 數(shù)據(jù)壓縮后寫入 Redis

以上方案基本涵蓋了 Redis 內(nèi)存優(yōu)化的各個(gè)方面。

如果你還想進(jìn)一步優(yōu)化 Redis 內(nèi)存榄笙,你還可以在業(yè)務(wù)應(yīng)用中先將數(shù)據(jù)壓縮邪狞,再寫入到 Redis 中(例如采用 snappy、gzip 等壓縮算法)茅撞。

當(dāng)然帆卓,壓縮存儲(chǔ)的數(shù)據(jù),客戶端在讀取時(shí)還需要解壓縮乡翅,在這期間會(huì)消耗更多 CPU 資源鳞疲,你需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡。

以上就是「節(jié)省內(nèi)存資源」方面的實(shí)踐優(yōu)化蠕蚜,是不是都比較簡(jiǎn)單尚洽?

下面我們來(lái)看「性能」方面的優(yōu)化。

如何持續(xù)發(fā)揮 Redis 的高性能靶累?

當(dāng)你的系統(tǒng)決定引入 Redis 時(shí)腺毫,想必看中它最關(guān)鍵的一點(diǎn)就是:性能

我們知道挣柬,一個(gè)單機(jī)版 Redis 就可以達(dá)到 10W QPS潮酒,這么高的性能,也意味著如果在使用過(guò)程中發(fā)生延遲情況邪蛔,就會(huì)與我們的預(yù)期不符急黎。

所以,在使用 Redis 時(shí)侧到,如何持續(xù)發(fā)揮它的高性能勃教,避免操作延遲的情況發(fā)生,也是我們的關(guān)注焦點(diǎn)匠抗。

在這方面故源,我給你總結(jié)了 13 條建議:

1) 避免存儲(chǔ) bigkey

存儲(chǔ) bigkey 除了前面講到的使用過(guò)多內(nèi)存之外,對(duì) Redis 性能也會(huì)有很大影響汞贸。

由于 Redis 處理請(qǐng)求是單線程的绳军,當(dāng)你的應(yīng)用在寫入一個(gè) bigkey 時(shí),更多時(shí)間將消耗在「內(nèi)存分配」上矢腻,這時(shí)操作延遲就會(huì)增加门驾。同樣地,刪除一個(gè) bigkey 在「釋放內(nèi)存」時(shí)踏堡,也會(huì)發(fā)生耗時(shí)猎唁。

而且,當(dāng)你在讀取這個(gè) bigkey 時(shí)顷蟆,也會(huì)在「網(wǎng)絡(luò)數(shù)據(jù)傳輸」上花費(fèi)更多時(shí)間诫隅,此時(shí)后面待執(zhí)行的請(qǐng)求就會(huì)發(fā)生排隊(duì),Redis 性能下降帐偎。

所以逐纬,你的業(yè)務(wù)應(yīng)用盡量不要存儲(chǔ) bigkey,避免操作延遲發(fā)生削樊。

如果你確實(shí)有存儲(chǔ) bigkey 的需求豁生,你可以把 bigkey 拆分為多個(gè)小 key 存儲(chǔ)。

2) 開(kāi)啟 lazy-free 機(jī)制

如果你無(wú)法避免存儲(chǔ) bigkey漫贞,那么我建議你開(kāi)啟 Redis 的 lazy-free 機(jī)制甸箱。(4.0+版本支持)

當(dāng)開(kāi)啟這個(gè)機(jī)制后,Redis 在刪除一個(gè) bigkey 時(shí)迅脐,釋放內(nèi)存的耗時(shí)操作芍殖,將會(huì)放到后臺(tái)線程中去執(zhí)行,這樣可以在最大程度上谴蔑,避免對(duì)主線程的影響豌骏。

3) 不使用復(fù)雜度過(guò)高的命令

Redis 是單線程模型處理請(qǐng)求,除了操作 bigkey 會(huì)導(dǎo)致后面請(qǐng)求發(fā)生排隊(duì)之外隐锭,在執(zhí)行復(fù)雜度過(guò)高的命令時(shí)窃躲,也會(huì)發(fā)生這種情況。

因?yàn)閳?zhí)行復(fù)雜度過(guò)高的命令钦睡,會(huì)消耗更多的 CPU 資源蒂窒,主線程中的其它請(qǐng)求只能等待,這時(shí)也會(huì)發(fā)生排隊(duì)延遲荞怒。

所以洒琢,你需要避免執(zhí)行例如 SORT、SINTER挣输、SINTERSTORE纬凤、ZUNIONSTORE、ZINTERSTORE 等聚合類命令撩嚼。

對(duì)于這種聚合類操作停士,我建議你把它放到客戶端來(lái)執(zhí)行,不要讓 Redis 承擔(dān)太多的計(jì)算工作完丽。

4) 執(zhí)行 O(N) 命令時(shí)恋技,關(guān)注 N 的大小

規(guī)避使用復(fù)雜度過(guò)高的命令,就可以高枕無(wú)憂了么逻族?

答案是否定的蜻底。

當(dāng)你在執(zhí)行 O(N) 命令時(shí),同樣需要注意 N 的大小聘鳞。

如果一次性查詢過(guò)多的數(shù)據(jù)薄辅,也會(huì)在網(wǎng)絡(luò)傳輸過(guò)程中耗時(shí)過(guò)長(zhǎng)要拂,操作延遲變大。

所以站楚,對(duì)于容器類型(List/Hash/Set/ZSet)脱惰,在元素?cái)?shù)量未知的情況下,一定不要無(wú)腦執(zhí)行 LRANGE key 0 -1 / HGETALL / SMEMBERS / ZRANGE key 0 -1窿春。

在查詢數(shù)據(jù)時(shí)拉一,你要遵循以下原則:

先查詢數(shù)據(jù)元素的數(shù)量(LLEN/HLEN/SCARD/ZCARD)

元素?cái)?shù)量較少,可一次性查詢?nèi)繑?shù)據(jù)

元素?cái)?shù)量非常多旧乞,分批查詢數(shù)據(jù)(LRANGE/HASCAN/SSCAN/ZSCAN)

5) 關(guān)注 DEL 時(shí)間復(fù)雜度

你沒(méi)看錯(cuò)蔚润,在刪除一個(gè) key 時(shí),如果姿勢(shì)不對(duì)尺栖,也有可能影響到 Redis 性能嫡纠。

刪除一個(gè) key,我們通常使用的是 DEL 命令决瞳,回想一下货徙,你覺(jué)得 DEL 的時(shí)間復(fù)雜度是多少?

O(1) 皮胡?其實(shí)不一定痴颊。

當(dāng)你刪除的是一個(gè) String 類型 key 時(shí),時(shí)間復(fù)雜度確實(shí)是 O(1)屡贺。

但當(dāng)你要?jiǎng)h除的 key 是 List/Hash/Set/ZSet 類型蠢棱,它的復(fù)雜度其實(shí)為 O(N),N 代表元素個(gè)數(shù)甩栈。

也就是說(shuō)泻仙,刪除一個(gè) key,其元素?cái)?shù)量越多量没,執(zhí)行 DEL 也就越慢玉转!

原因在于,刪除大量元素時(shí)殴蹄,需要依次回收每個(gè)元素的內(nèi)存究抓,元素越多,花費(fèi)的時(shí)間也就越久袭灯!

而且刺下,這個(gè)過(guò)程默認(rèn)是在主線程中執(zhí)行的,這勢(shì)必會(huì)阻塞主線程稽荧,產(chǎn)生性能問(wèn)題橘茉。

那刪除這種元素比較多的 key,如何處理呢?

我給你的建議是畅卓,分批刪除:

List類型:執(zhí)行多次 LPOP/RPOP擅腰,直到所有元素都刪除完成

Hash/Set/ZSet類型:先執(zhí)行 HSCAN/SSCAN/SCAN 查詢?cè)兀賵?zhí)行 HDEL/SREM/ZREM 依次刪除每個(gè)元素

沒(méi)想到吧髓介?一個(gè)小小的刪除操作惕鼓,稍微不小心筋现,也有可能引發(fā)性能問(wèn)題唐础,你在操作時(shí)需要格外注意。

6) 批量命令代替單個(gè)命令

當(dāng)你需要一次性操作多個(gè) key 時(shí)矾飞,你應(yīng)該使用批量命令來(lái)處理一膨。

批量操作相比于多次單個(gè)操作的優(yōu)勢(shì)在于,可以顯著減少客戶端洒沦、服務(wù)端的來(lái)回網(wǎng)絡(luò) IO 次數(shù)豹绪。

所以我給你的建議是:

String / Hash 使用 MGET/MSET 替代 GET/SET,HMGET/HMSET 替代 HGET/HSET

其它數(shù)據(jù)類型使用 Pipeline申眼,打包一次性發(fā)送多個(gè)命令到服務(wù)端執(zhí)行

7) 避免集中過(guò)期 key

Redis 清理過(guò)期 key 是采用定時(shí) + 懶惰的方式來(lái)做的瞒津,而且這個(gè)過(guò)程都是在主線程中執(zhí)行。

如果你的業(yè)務(wù)存在大量 key 集中過(guò)期的情況括尸,那么 Redis 在清理過(guò)期 key 時(shí)巷蚪,也會(huì)有阻塞主線程的風(fēng)險(xiǎn)。

想要避免這種情況發(fā)生濒翻,你可以在設(shè)置過(guò)期時(shí)間時(shí)屁柏,增加一個(gè)隨機(jī)時(shí)間,把這些 key 的過(guò)期時(shí)間打散有送,從而降低集中過(guò)期對(duì)主線程的影響淌喻。

8) 使用長(zhǎng)連接操作 Redis,合理配置連接池

你的業(yè)務(wù)應(yīng)該使用長(zhǎng)連接操作 Redis雀摘,避免短連接裸删。

當(dāng)使用短連接操作 Redis 時(shí),每次都需要經(jīng)過(guò) TCP 三次握手阵赠、四次揮手涯塔,這個(gè)過(guò)程也會(huì)增加操作耗時(shí)。

同時(shí)豌注,你的客戶端應(yīng)該使用連接池的方式訪問(wèn) Redis伤塌,并設(shè)置合理的參數(shù),長(zhǎng)時(shí)間不操作 Redis 時(shí)轧铁,需及時(shí)釋放連接資源每聪。

9) 只使用 db0

盡管 Redis 提供了 16 個(gè) db,但我只建議你使用 db0。

為什么呢药薯?我總結(jié)了以下 3 點(diǎn)原因:

在一個(gè)連接上操作多個(gè) db 數(shù)據(jù)時(shí)绑洛,每次都需要先執(zhí)行 SELECT,這會(huì)給 Redis 帶來(lái)額外的壓力

使用多個(gè) db 的目的是童本,按不同業(yè)務(wù)線存儲(chǔ)數(shù)據(jù)真屯,那為何不拆分多個(gè)實(shí)例存儲(chǔ)呢?拆分多個(gè)實(shí)例部署穷娱,多個(gè)業(yè)務(wù)線不會(huì)互相影響绑蔫,還能提高 Redis 的訪問(wèn)性能

Redis Cluster 只支持 db0,如果后期你想要遷移到 Redis Cluster泵额,遷移成本高

10) 使用讀寫分離 + 分片集群

如果你的業(yè)務(wù)讀請(qǐng)求量很大配深,那么可以采用部署多個(gè)從庫(kù)的方式,實(shí)現(xiàn)讀寫分離嫁盲,讓 Redis 的從庫(kù)分擔(dān)讀壓力篓叶,進(jìn)而提升性能。

如果你的業(yè)務(wù)寫請(qǐng)求量很大羞秤,單個(gè) Redis 實(shí)例已無(wú)法支撐這么大的寫流量缸托,那么此時(shí)你需要使用分片集群,分擔(dān)寫壓力瘾蛋。

11) 不開(kāi)啟 AOF 或 AOF 配置為每秒刷盤

如果對(duì)于丟失數(shù)據(jù)不敏感的業(yè)務(wù)俐镐,我建議你不開(kāi)啟 AOF,避免 AOF 寫磁盤拖慢 Redis 的性能瘦黑。

如果確實(shí)需要開(kāi)啟 AOF京革,那么我建議你配置為 appendfsync everysec,把數(shù)據(jù)持久化的刷盤操作幸斥,放到后臺(tái)線程中去執(zhí)行匹摇,盡量降低 Redis 寫磁盤對(duì)性能的影響。

12) 使用物理機(jī)部署 Redis

Redis 在做數(shù)據(jù)持久化時(shí)甲葬,采用創(chuàng)建子進(jìn)程的方式進(jìn)行廊勃。

而創(chuàng)建子進(jìn)程會(huì)調(diào)用操作系統(tǒng)的 fork 系統(tǒng)調(diào)用,這個(gè)系統(tǒng)調(diào)用的執(zhí)行耗時(shí)经窖,與系統(tǒng)環(huán)境有關(guān)坡垫。

虛擬機(jī)環(huán)境執(zhí)行 fork 的耗時(shí),要比物理機(jī)慢得多画侣,所以你的 Redis 應(yīng)該盡可能部署在物理機(jī)上冰悠。

13) 關(guān)閉操作系統(tǒng)內(nèi)存大頁(yè)機(jī)制

Linux 操作系統(tǒng)提供了內(nèi)存大頁(yè)機(jī)制,其特點(diǎn)在于配乱,每次應(yīng)用程序向操作系統(tǒng)申請(qǐng)內(nèi)存時(shí)溉卓,申請(qǐng)單位由之前的 4KB 變?yōu)榱?2MB皮迟。

這會(huì)導(dǎo)致什么問(wèn)題呢?

當(dāng) Redis 在做數(shù)據(jù)持久化時(shí)桑寨,會(huì)先 fork 一個(gè)子進(jìn)程伏尼,此時(shí)主進(jìn)程和子進(jìn)程共享相同的內(nèi)存地址空間。

當(dāng)主進(jìn)程需要修改現(xiàn)有數(shù)據(jù)時(shí)尉尾,會(huì)采用寫時(shí)復(fù)制(Copy On Write)的方式進(jìn)行操作爆阶,在這個(gè)過(guò)程中,需要重新申請(qǐng)內(nèi)存沙咏。

如果申請(qǐng)內(nèi)存單位變?yōu)榱?2MB辨图,那么勢(shì)必會(huì)增加內(nèi)存申請(qǐng)的耗時(shí),如果此時(shí)主進(jìn)程有大量寫操作芭碍,需要修改原有的數(shù)據(jù)徒役,那么在此期間,操作延遲就會(huì)變大窖壕。

所以,為了避免出現(xiàn)這種問(wèn)題杉女,你需要在操作系統(tǒng)上關(guān)閉內(nèi)存大頁(yè)機(jī)制瞻讽。

好了,以上這些就是 Redis 「高性能」方面的實(shí)踐優(yōu)化熏挎。如果你非常關(guān)心 Redis 的性能問(wèn)題速勇,可以結(jié)合這些方面針對(duì)性優(yōu)化。

我們?cè)賮?lái)看 Redis 「可靠性」如何保證坎拐。

如何保證 Redis 的可靠性烦磁?

這里我想提醒你的是,保證 Redis 可靠性其實(shí)并不難哼勇,但難的是如何做到「持續(xù)穩(wěn)定」都伪。

下面我會(huì)從「資源隔離」、「多副本」积担、「故障恢復(fù)」這三大維度陨晶,帶你分析保障 Redis 可靠性的最佳實(shí)踐瘟芝。

1) 按業(yè)務(wù)線部署實(shí)例

提升可靠性的第一步栅哀,就是「資源隔離」。

你最好按不同的業(yè)務(wù)線來(lái)部署 Redis 實(shí)例绍绘,這樣當(dāng)其中一個(gè)實(shí)例發(fā)生故障時(shí)的烁,不會(huì)影響到其它業(yè)務(wù)褐耳。

這種資源隔離的方案,實(shí)施成本是最低的渴庆,但成效卻是非常大的铃芦。

2) 部署主從集群

如果你只使用單機(jī)版 Redis买雾,那么就會(huì)存在機(jī)器宕機(jī)服務(wù)不可用的風(fēng)險(xiǎn)。

所以杨帽,你需要部署「多副本」實(shí)例漓穿,即主從集群,這樣當(dāng)主庫(kù)宕機(jī)后注盈,依舊有從庫(kù)可以使用晃危,避免了數(shù)據(jù)丟失的風(fēng)險(xiǎn),也降低了服務(wù)不可用的時(shí)間老客。

在部署主從集群時(shí)僚饭,你還需要注意,主從庫(kù)需要分布在不同機(jī)器上胧砰,避免交叉部署鳍鸵。

這么做的原因在于,通常情況下尉间,Redis 的主庫(kù)會(huì)承擔(dān)所有的讀寫流量偿乖,所以我們一定要優(yōu)先保證主庫(kù)的穩(wěn)定性,即使從庫(kù)機(jī)器異常哲嘲,也不要對(duì)主庫(kù)造成影響贪薪。

而且,有時(shí)我們需要對(duì) Redis 做日常維護(hù)眠副,例如數(shù)據(jù)定時(shí)備份等操作画切,這時(shí)你就可以只在從庫(kù)上進(jìn)行,這只會(huì)消耗從庫(kù)機(jī)器的資源囱怕,也避免了對(duì)主庫(kù)的影響霍弹。

3) 合理配置主從復(fù)制參數(shù)

在部署主從集群時(shí),如果參數(shù)配置不合理娃弓,也有可能導(dǎo)致主從復(fù)制發(fā)生問(wèn)題:

主從復(fù)制中斷

從庫(kù)發(fā)起全量復(fù)制典格,主庫(kù)性能受到影響

在這方面我給你的建議有以下 2 點(diǎn):

設(shè)置合理的 repl-backlog 參數(shù):過(guò)小的 repl-backlog 在寫流量比較大的場(chǎng)景下,主從復(fù)制中斷會(huì)引發(fā)全量復(fù)制數(shù)據(jù)的風(fēng)險(xiǎn)

設(shè)置合理的 slave client-output-buffer-limit:當(dāng)從庫(kù)復(fù)制發(fā)生問(wèn)題時(shí)忘闻,過(guò)小的 buffer 會(huì)導(dǎo)致從庫(kù)緩沖區(qū)溢出钝计,從而導(dǎo)致復(fù)制中斷

4) 部署哨兵集群,實(shí)現(xiàn)故障自動(dòng)切換

只部署了主從節(jié)點(diǎn)齐佳,但故障發(fā)生時(shí)是無(wú)法自動(dòng)切換的私恬,所以,你還需要部署哨兵集群炼吴,實(shí)現(xiàn)故障的「自動(dòng)切換」本鸣。

而且,多個(gè)哨兵節(jié)點(diǎn)需要分布在不同機(jī)器上硅蹦,實(shí)例為奇數(shù)個(gè)荣德,防止哨兵選舉失敗闷煤,影響切換時(shí)間。

以上這些就是保障 Redis「高可靠」實(shí)踐優(yōu)化涮瞻,你應(yīng)該也發(fā)現(xiàn)了鲤拿,這些都是部署和運(yùn)維層的優(yōu)化。

除此之外署咽,你可能還會(huì)對(duì) Redis 做一些「日常運(yùn)維」工作近顷,這時(shí)你要注意哪些問(wèn)題呢?

日常運(yùn)維 Redis 需要注意什么宁否?

如果你是 DBA 運(yùn)維人員窒升,在平時(shí)運(yùn)維 Redis 時(shí),也需要注意以下 6 個(gè)方面慕匠。

1) 禁止使用 KEYS/FLUSHALL/FLUSHDB 命令

執(zhí)行這些命令饱须,會(huì)長(zhǎng)時(shí)間阻塞 Redis 主線程,危害極大台谊,所以你必須禁止使用它蓉媳。

如果確實(shí)想使用這些命令,我給你的建議是:

SCAN 替換 KEYS

4.0+版本可使用 FLUSHALL/FLUSHDB ASYNC青伤,清空數(shù)據(jù)的操作放在后臺(tái)線程執(zhí)行

2) 掃描線上實(shí)例時(shí)督怜,設(shè)置休眠時(shí)間

不管你是使用 SCAN 掃描線上實(shí)例,還是對(duì)實(shí)例做 bigkey 統(tǒng)計(jì)分析狠角,我建議你在掃描時(shí)一定記得設(shè)置休眠時(shí)間。

防止在掃描過(guò)程中蚪腋,實(shí)例 OPS 過(guò)高對(duì) Redis 產(chǎn)生性能抖動(dòng)丰歌。

3) 慎用 MONITOR 命令

有時(shí)在排查 Redis 問(wèn)題時(shí),你會(huì)使用 MONITOR 查看 Redis 正在執(zhí)行的命令屉凯。

但如果你的 Redis OPS 比較高立帖,那么在執(zhí)行 MONITOR 會(huì)導(dǎo)致 Redis 輸出緩沖區(qū)的內(nèi)存持續(xù)增長(zhǎng),這會(huì)嚴(yán)重消耗 Redis 的內(nèi)存資源悠砚,甚至?xí)?dǎo)致實(shí)例內(nèi)存超過(guò) maxmemory晓勇,引發(fā)數(shù)據(jù)淘汰,這種情況你需要格外注意灌旧。

所以你在執(zhí)行 MONITOR 命令時(shí)绑咱,一定要謹(jǐn)慎,盡量少用枢泰。

4) 從庫(kù)必須設(shè)置為 slave-read-only

你的從庫(kù)必須設(shè)置為 slave-read-only 狀態(tài)描融,避免從庫(kù)寫入數(shù)據(jù),導(dǎo)致主從數(shù)據(jù)不一致衡蚂。

除此之外窿克,從庫(kù)如果是非 read-only 狀態(tài)骏庸,如果你使用的是 4.0 以下的 Redis,它存在這樣的 Bug:

從庫(kù)寫入了有過(guò)期時(shí)間的數(shù)據(jù)年叮,不會(huì)做定時(shí)清理和釋放內(nèi)存具被。

這會(huì)造成從庫(kù)的內(nèi)存泄露!這個(gè)問(wèn)題直到 4.0 版本才修復(fù)只损,你在配置從庫(kù)時(shí)需要格外注意一姿。

5) 合理配置 timeout 和 tcp-keepalive 參數(shù)

如果因?yàn)榫W(wǎng)絡(luò)原因,導(dǎo)致你的大量客戶端連接與 Redis 意外中斷改执,恰好你的 Redis 配置的 maxclients 參數(shù)比較小啸蜜,此時(shí)有可能導(dǎo)致客戶端無(wú)法與服務(wù)端建立新的連接(服務(wù)端認(rèn)為超過(guò)了 maxclients)。

造成這個(gè)問(wèn)題原因在于辈挂,客戶端與服務(wù)端每建立一個(gè)連接衬横,Redis 都會(huì)給這個(gè)客戶端分配了一個(gè) client fd。

當(dāng)客戶端與服務(wù)端網(wǎng)絡(luò)發(fā)生問(wèn)題時(shí)终蒂,服務(wù)端并不會(huì)立即釋放這個(gè) client fd蜂林。

什么時(shí)候釋放呢?

Redis 內(nèi)部有一個(gè)定時(shí)任務(wù)拇泣,會(huì)定時(shí)檢測(cè)所有 client 的空閑時(shí)間是否超過(guò)配置的 timeout 值噪叙。

如果 Redis 沒(méi)有開(kāi)啟 tcp-keepalive 的話,服務(wù)端直到配置的 timeout 時(shí)間后霉翔,才會(huì)清理釋放這個(gè) client fd睁蕾。

在沒(méi)有清理之前,如果還有大量新連接進(jìn)來(lái)债朵,就有可能導(dǎo)致 Redis 服務(wù)端內(nèi)部持有的 client fd 超過(guò)了 maxclients子眶,這時(shí)新連接就會(huì)被拒絕。

針對(duì)這種情況序芦,我給你的優(yōu)化建議是:

不要配置過(guò)高的 timeout:讓服務(wù)端盡快把無(wú)效的 client fd 清理掉

Redis 開(kāi)啟 tcp-keepalive:這樣服務(wù)端會(huì)定時(shí)給客戶端發(fā)送 TCP 心跳包臭杰,檢測(cè)連接連通性,當(dāng)網(wǎng)絡(luò)異常時(shí)谚中,可以盡快清理僵尸 client fd

6) 調(diào)整 maxmemory 時(shí)渴杆,注意主從庫(kù)的調(diào)整順序

Redis 5.0 以下版本存在這樣一個(gè)問(wèn)題:從庫(kù)內(nèi)存如果超過(guò)了 maxmemory,也會(huì)觸發(fā)數(shù)據(jù)淘汰宪塔。

在某些場(chǎng)景下磁奖,從庫(kù)是可能優(yōu)先主庫(kù)達(dá)到 maxmemory 的(例如在從庫(kù)執(zhí)行 MONITOR 命令,輸出緩沖區(qū)占用大量?jī)?nèi)存)蝌麸,那么此時(shí)從庫(kù)開(kāi)始淘汰數(shù)據(jù)点寥,主從庫(kù)就會(huì)產(chǎn)生不一致。

要想避免此問(wèn)題来吩,在調(diào)整 maxmemory 時(shí)敢辩,一定要注意主從庫(kù)的修改順序:

調(diào)大 maxmemory:先修改從庫(kù)蔽莱,再修改主庫(kù)

調(diào)小 maxmemory:先修改主庫(kù),再修改從庫(kù)

直到 Redis 5.0戚长,Redis 才增加了一個(gè)配置 replica-ignore-maxmemory盗冷,默認(rèn)從庫(kù)超過(guò) maxmemory 不會(huì)淘汰數(shù)據(jù),才解決了此問(wèn)題同廉。

好了仪糖,以上這些就是「日常運(yùn)維」Redis 需要注意的,你可以對(duì)各個(gè)配置項(xiàng)查漏補(bǔ)缺迫肖,看有哪些是需要優(yōu)化的锅劝。

接下來(lái),我們來(lái)看一下蟆湖,保障 Redis「安全」都需要注意哪些問(wèn)題故爵。

Redis 安全如何保證?

無(wú)論如何隅津,在互聯(lián)網(wǎng)時(shí)代诬垂,安全問(wèn)題一定是我們需要隨時(shí)警戒的。

你可能聽(tīng)說(shuō)過(guò) Redis 被注入可執(zhí)行腳本伦仍,然后拿到機(jī)器 root 權(quán)限的安全問(wèn)題结窘,都是因?yàn)樵诓渴?Redis 時(shí),沒(méi)有把安全風(fēng)險(xiǎn)注意起來(lái)充蓝。

針對(duì)這方面隧枫,我給你的建議是:

不要把 Redis 部署在公網(wǎng)可訪問(wèn)的服務(wù)器上

部署時(shí)不使用默認(rèn)端口 6379

以普通用戶啟動(dòng) Redis 進(jìn)程,禁止 root 用戶啟動(dòng)

限制 Redis 配置文件的目錄訪問(wèn)權(quán)限

推薦開(kāi)啟密碼認(rèn)證

禁用/重命名危險(xiǎn)命令(KEYS/FLUSHALL/FLUSHDB/CONFIG/EVAL)

只要你把這些做到位谓苟,基本上就可以保證 Redis 的安全風(fēng)險(xiǎn)在可控范圍內(nèi)悠垛。

至此,我們分析了 Redis 在內(nèi)存娜谊、性能、可靠性斤讥、日常運(yùn)維方面的最佳實(shí)踐優(yōu)化纱皆。

除了以上這些,你還需要做到提前「預(yù)防」芭商。

如何預(yù)防 Redis 問(wèn)題派草?

要想提前預(yù)防 Redis 問(wèn)題,你需要做好以下兩個(gè)方面:

合理的資源規(guī)劃

完善的監(jiān)控預(yù)警

先來(lái)說(shuō)資源規(guī)劃铛楣。

在部署 Redis 時(shí)近迁,如果你可以提前做好資源規(guī)劃,可以避免很多因?yàn)橘Y源不足產(chǎn)生的問(wèn)題簸州。這方面我給你的建議有以下 3 點(diǎn):

保證機(jī)器有足夠的 CPU鉴竭、內(nèi)存歧譬、帶寬、磁盤資源

提前做好容量規(guī)劃搏存,主庫(kù)機(jī)器預(yù)留一半內(nèi)存資源瑰步,防止主從機(jī)器網(wǎng)絡(luò)故障,引發(fā)大面積全量同步璧眠,導(dǎo)致主庫(kù)機(jī)器內(nèi)存不足的問(wèn)題

單個(gè)實(shí)例內(nèi)存建議控制在 10G 以下缩焦,大實(shí)例在主從全量同步、RDB 備份時(shí)有阻塞風(fēng)險(xiǎn)

再來(lái)看監(jiān)控如何做责静。

監(jiān)控預(yù)警是提高穩(wěn)定性的重要環(huán)節(jié)袁滥,完善的監(jiān)控預(yù)警,可以把問(wèn)題提前暴露出來(lái)灾螃,這樣我們才可以快速反應(yīng)题翻,把問(wèn)題最小化。

這方面我給你的建議是:

做好機(jī)器 CPU睦焕、內(nèi)存藐握、帶寬、磁盤監(jiān)控垃喊,資源不足時(shí)及時(shí)報(bào)警猾普,任意資源不足都會(huì)影響 Redis 性能

設(shè)置合理的 slowlog 閾值,并對(duì)其進(jìn)行監(jiān)控本谜,slowlog 過(guò)多及時(shí)報(bào)警

監(jiān)控組件采集 Redis INFO 信息時(shí)初家,采用長(zhǎng)連接,避免頻繁的短連接

做好實(shí)例運(yùn)行時(shí)監(jiān)控乌助,重點(diǎn)關(guān)注 expired_keys溜在、evicted_keys、latest_fork_usec 指標(biāo)他托,這些指標(biāo)短時(shí)突增可能會(huì)有阻塞風(fēng)險(xiǎn)

總結(jié)

好了掖肋,總結(jié)一下,這篇文章我?guī)闳娣治隽?Redis 最佳實(shí)踐的優(yōu)化路徑赏参,其中包括內(nèi)存資源志笼、高性能、高可靠把篓、日常運(yùn)維纫溃、資源規(guī)劃、監(jiān)控韧掩、安全 7 個(gè)維度紊浩。

這里我畫成了思維導(dǎo)圖,方便你在實(shí)踐時(shí)做參考。

我還把這些實(shí)踐優(yōu)化坊谁,按照「業(yè)務(wù)開(kāi)發(fā)」和「運(yùn)維」兩個(gè)維度费彼,進(jìn)一步做了劃分。

并且以「強(qiáng)制」呜袁、「推薦」敌买、「參考」3 個(gè)級(jí)別做了標(biāo)注,這樣你在實(shí)踐優(yōu)化時(shí)阶界,就會(huì)更明確哪些該做虹钮,哪些需要結(jié)合實(shí)際的業(yè)務(wù)場(chǎng)景進(jìn)一步分析。

這些級(jí)別的實(shí)施規(guī)則如下:

強(qiáng)制:需嚴(yán)格遵守膘融,否則危害極大

推薦:推薦遵守芙粱,可提升性能、降低內(nèi)存氧映、便于運(yùn)維

參考:根據(jù)業(yè)務(wù)特點(diǎn)參考實(shí)施

如果你是業(yè)務(wù)開(kāi)發(fā)人員春畔,你需要了解 Redis 的運(yùn)行機(jī)制,例如各個(gè)命令的執(zhí)行時(shí)間復(fù)雜度岛都、數(shù)據(jù)過(guò)期策略律姨、數(shù)據(jù)淘汰策略等,使用合理的命令臼疫,并結(jié)合業(yè)務(wù)場(chǎng)景進(jìn)行優(yōu)化择份。

如果你是 DBA 運(yùn)維人員,你需要在資源規(guī)劃烫堤、運(yùn)維荣赶、監(jiān)控、安全層面做到位鸽斟,做到未雨綢繆拔创。

后記

如果你能耐心地讀到這里,應(yīng)該對(duì)如何「用好」Redis 有了新的認(rèn)識(shí)富蓄。

這篇文章我們主要講的是 Redis 最佳實(shí)踐剩燥,對(duì)于「最佳實(shí)踐」這個(gè)話題,我想再和你多聊幾句立倍。

如果你面對(duì)的不是 Redis躏吊,而是其它中間件,例如 MySQL帐萎、Kafka,你在使用這些組件時(shí)胜卤,會(huì)有什么優(yōu)化思路嗎疆导?

你也可以沿用這篇文章的這幾個(gè)維度來(lái)分析:

性能

可靠性

資源

運(yùn)維

監(jiān)控

安全

你可以思考一下,MySQL 和 Kafka 在這幾個(gè)維度葛躏,需要注意哪些問(wèn)題澈段。

另外悠菜,從學(xué)習(xí)技能的角度來(lái)講,我們?cè)谲浖_(kāi)發(fā)過(guò)程中败富,要盡可能地去思考和探索「最佳實(shí)踐」的方式悔醋。

因?yàn)橹挥羞@樣,我們才會(huì)不斷督促自己去思考兽叮,對(duì)自己提出更高的要求芬骄,做到持續(xù)進(jìn)步。

文章轉(zhuǎn)載至樂(lè)字節(jié)

最后給大家推薦幾個(gè)b站超詳細(xì)的Java自學(xué)課:

Servlet入門教程BV1D5411373E

Vue鹦聪、Vuejs教程账阻,BV19V41177od

SpringBoot+Vue項(xiàng)目實(shí)戰(zhàn)BV1o64y117qQ

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泽本,隨后出現(xiàn)的幾起案子淘太,更是在濱河造成了極大的恐慌,老刑警劉巖规丽,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒲牧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赌莺,警方通過(guò)查閱死者的電腦和手機(jī)冰抢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)雄嚣,“玉大人晒屎,你說(shuō)我怎么就攤上這事』荷” “怎么了鼓鲁?”我有些...
    開(kāi)封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)港谊。 經(jīng)常有香客問(wèn)我骇吭,道長(zhǎng),這世上最難降的妖魔是什么歧寺? 我笑而不...
    開(kāi)封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任燥狰,我火速辦了婚禮,結(jié)果婚禮上斜筐,老公的妹妹穿的比我還像新娘龙致。我一直安慰自己,他們只是感情好顷链,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布目代。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪榛了。 梳的紋絲不亂的頭發(fā)上在讶,一...
    開(kāi)封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音霜大,去河邊找鬼构哺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛战坤,可吹牛的內(nèi)容都是我干的曙强。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼湖笨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼旗扑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慈省,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤臀防,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后边败,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袱衷,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年笑窜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了致燥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡排截,死狀恐怖嫌蚤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情断傲,我是刑警寧澤脱吱,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站认罩,受9級(jí)特大地震影響箱蝠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垦垂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一宦搬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劫拗,春花似錦间校、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狰右。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逼友,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工灰瞻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猿诸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓稳析,卻偏偏與公主長(zhǎng)得像洗做,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子彰居,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 以下文章來(lái)源于水滴與銀彈 诚纸,作者M(jìn)agic Kaito Redis 作為優(yōu)秀的內(nèi)存數(shù)據(jù)庫(kù),其擁有非常高的性能陈惰,單個(gè)...
    立0911閱讀 930評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月畦徘,有人笑有人哭,有人歡樂(lè)有人憂愁抬闯,有人驚喜有人失落井辆,有的覺(jué)得收獲滿滿有...
    陌忘宇閱讀 8,536評(píng)論 28 53
  • 信任包括信任自己和信任他人 很多時(shí)候,很多事情溶握,失敗杯缺、遺憾、錯(cuò)過(guò)睡榆,源于不自信萍肆,不信任他人 覺(jué)得自己做不成,別人做不...
    吳氵晃閱讀 6,190評(píng)論 4 8
  • 怎么對(duì)待生活,它也會(huì)怎么對(duì)你 人都是哭著來(lái)到這個(gè)美麗的人間碉纳。每個(gè)人從來(lái)到塵寰到升入天堂勿负,整個(gè)生命的歷程都是一本書,...
    靜靜在等你閱讀 4,976評(píng)論 1 6