在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

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

Redis10大性能優(yōu)化策略

jf_ro2CN3Fa ? 來(lái)源:阿里開(kāi)發(fā)者 ? 2023-07-04 10:21 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1.Redis真的變慢了嗎?

對(duì) Redis 進(jìn)行基準(zhǔn)性能測(cè)試

例如,我的機(jī)器配置比較低,當(dāng)延遲為 2ms 時(shí),我就認(rèn)為 Redis 變慢了,但是如果你的硬件配置比較高,那么在你的運(yùn)行環(huán)境下,可能延遲是 0.5ms 時(shí)就可以認(rèn)為 Redis 變慢了。

所以,你只有了解了你的 Redis 在生產(chǎn)環(huán)境服務(wù)器上的基準(zhǔn)性能,才能進(jìn)一步評(píng)估,當(dāng)其延遲達(dá)到什么程度時(shí),才認(rèn)為 Redis 確實(shí)變慢了。

為了避免業(yè)務(wù)服務(wù)器到 Redis 服務(wù)器之間的網(wǎng)絡(luò)延遲,你需要直接在 Redis 服務(wù)器上測(cè)試實(shí)例的響應(yīng)延遲情況。執(zhí)行以下命令,就可以測(cè)試出這個(gè)實(shí)例 60 秒內(nèi)的最大響應(yīng)延遲:

./redis-cli--intrinsic-latency120
Maxlatencysofar:17microseconds.
Maxlatencysofar:44microseconds.
Maxlatencysofar:94microseconds.
Maxlatencysofar:110microseconds.
Maxlatencysofar:119microseconds.

36481658totalruns(avglatency:3.2893microseconds/3289.32nanosecondsperrun).
Worstruntook36xlongerthantheaveragelatency.

從輸出結(jié)果可以看到,這 60 秒內(nèi)的最大響應(yīng)延遲為 119 微秒(0.119毫秒)。你還可以使用以下命令,查看一段時(shí)間內(nèi) Redis 的最小、最大、平均訪(fǎng)問(wèn)延遲。

$redis-cli-h127.0.0.1-p6379--latency-history-i1
min:0,max:1,avg:0.13(100samples)--1.01secondsrange
min:0,max:1,avg:0.12(99samples)--1.01secondsrange
min:0,max:1,avg:0.13(99samples)--1.01secondsrange
min:0,max:1,avg:0.10(99samples)--1.01secondsrange
min:0,max:1,avg:0.13(98samples)--1.00secondsrange
min:0,max:1,avg:0.08(99samples)--1.01secondsrange

如果你觀(guān)察到的 Redis 運(yùn)行時(shí)延遲是其基線(xiàn)性能的 2 倍及以上,就可以認(rèn)定 Redis 變慢了。

網(wǎng)絡(luò)對(duì) Redis 性能的影響,一個(gè)簡(jiǎn)單的方法是用 iPerf 這樣的工具測(cè)試網(wǎng)絡(luò)極限帶寬。

服務(wù)器端


>基于SpringBoot+MyBatisPlus+Vue&Element實(shí)現(xiàn)的后臺(tái)管理系統(tǒng)+用戶(hù)小程序,支持RBAC動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
>
>*項(xiàng)目地址:
>*視頻教程

#iperf-s-p12345-i1-M
iperf:optionrequiresanargument--M
------------------------------------------------------------
ServerlisteningonTCPport12345
TCPwindowsize:4.00MByte(default)
------------------------------------------------------------
[4]local172.20.0.113port12345connectedwith172.20.0.114port56796
[ID]IntervalTransferBandwidth
[4]0.0-1.0sec614MBytes5.15Gbits/sec
[4]1.0-2.0sec622MBytes5.21Gbits/sec
[4]2.0-3.0sec647MBytes5.42Gbits/sec
[4]3.0-4.0sec644MBytes5.40Gbits/sec
[4]4.0-5.0sec651MBytes5.46Gbits/sec
[4]5.0-6.0sec652MBytes5.47Gbits/sec
[4]6.0-7.0sec669MBytes5.61Gbits/sec
[4]7.0-8.0sec670MBytes5.62Gbits/sec
[4]8.0-9.0sec667MBytes5.59Gbits/sec
[4]9.0-10.0sec667MBytes5.60Gbits/sec
[4]0.0-10.0sec6.35GBytes5.45Gbits/sec
客戶(hù)端


>基于SpringCloudAlibaba+Gateway+Nacos+RocketMQ+Vue&Element實(shí)現(xiàn)的后臺(tái)管理系統(tǒng)+用戶(hù)小程序,支持RBAC動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
>
>*項(xiàng)目地址:
>*視頻教程

#iperf-c服務(wù)器端IP-p12345-i1-t10-w20K
------------------------------------------------------------
Clientconnectingto172.20.0.113,TCPport12345
TCPwindowsize:40.0KByte(WARNING:requested20.0KByte)
------------------------------------------------------------
[3]local172.20.0.114port56796connectedwith172.20.0.113port12345
[ID]IntervalTransferBandwidth
[3]0.0-1.0sec614MBytes5.15Gbits/sec
[3]1.0-2.0sec622MBytes5.21Gbits/sec
[3]2.0-3.0sec646MBytes5.42Gbits/sec
[3]3.0-4.0sec644MBytes5.40Gbits/sec
[3]4.0-5.0sec651MBytes5.46Gbits/sec
[3]5.0-6.0sec652MBytes5.47Gbits/sec
[3]6.0-7.0sec669MBytes5.61Gbits/sec
[3]7.0-8.0sec670MBytes5.62Gbits/sec
[3]8.0-9.0sec667MBytes5.59Gbits/sec
[3]9.0-10.0sec668MBytes5.60Gbits/sec
[3]0.0-10.0sec6.35GBytes5.45Gbits/sec

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

首先,第一步,你需要去查看一下 Redis 的慢日志(slowlog)。

Redis 提供了慢日志命令的統(tǒng)計(jì)功能,它記錄了有哪些命令在執(zhí)行時(shí)耗時(shí)比較久。

查看 Redis 慢日志之前,你需要設(shè)置慢日志的閾值。例如,設(shè)置慢日志的閾值為 5 毫秒,并且保留最近 500 條慢日志記錄:

#命令執(zhí)行耗時(shí)超過(guò)5毫秒,記錄慢日志
CONFIGSETslowlog-log-slower-than5000
#只保留最近500條慢日志
CONFIGSETslowlog-max-len500

1)經(jīng)常使用 O(N) 以上復(fù)雜度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合類(lèi)命令。

2)使用 O(N) 復(fù)雜度的命令,但 N 的值非常大。

第一種情況導(dǎo)致變慢的原因在于,Redis 在操作內(nèi)存數(shù)據(jù)時(shí),時(shí)間復(fù)雜度過(guò)高,要花費(fèi)更多的 CPU 資源。

第二種情況導(dǎo)致變慢的原因在于,Redis 一次需要返回給客戶(hù)端的數(shù)據(jù)過(guò)多,更多時(shí)間花費(fèi)在數(shù)據(jù)協(xié)議的組裝和網(wǎng)絡(luò)傳輸過(guò)程中。

另外,我們還可以從資源使用率層面來(lái)分析,如果你的應(yīng)用程序操作 Redis 的 OPS 不是很大,但 Redis 實(shí)例的 CPU 使用率卻很高 ,那么很有可能是使用了復(fù)雜度過(guò)高的命令導(dǎo)致的。

3.操作bigkey

如果你查詢(xún)慢日志發(fā)現(xiàn),并不是復(fù)雜度過(guò)高的命令導(dǎo)致的,而都是 SET / DEL 這種簡(jiǎn)單命令出現(xiàn)在慢日志中,那么你就要懷疑你的實(shí)例否寫(xiě)入了 bigkey。

redis-cli-h127.0.0.1-p6379--bigkeys-i1
--------summary-------
Sampled829675keysinthekeyspace!
Totalkeylengthinbytesis10059825(avglen12.13)
Biggeststringfound'key:291880'has10bytes
Biggestlistfound'mylist:004'has40items
Biggestsetfound'myset:2386'has38members
Biggesthashfound'myhash:3574'has37fields
Biggestzsetfound'myzset:2704'has42members
36313stringswith363130bytes(04.38%ofkeys,avgsize10.00)
787393listswith896540items(94.90%ofkeys,avgsize1.14)
1994setswith40052members(00.24%ofkeys,avgsize20.09)
1990hashswith39632fields(00.24%ofkeys,avgsize19.92)
1985zsetswith39750members(00.24%ofkeys,avgsize20.03)

這里我需要提醒你的是,當(dāng)執(zhí)行這個(gè)命令時(shí),要注意 2 個(gè)問(wèn)題:

1)對(duì)線(xiàn)上實(shí)例進(jìn)行 bigkey 掃描時(shí),Redis 的 OPS 會(huì)突增,為了降低掃描過(guò)程中對(duì) Redis 的影響,最好控制一下掃描的頻率,指定 -i 參數(shù)即可,它表示掃描過(guò)程中每次掃描后休息的時(shí)間間隔,單位是秒。

2)掃描結(jié)果中,對(duì)于容器類(lèi)型(List、Hash、Set、ZSet)的 key,只能掃描出元素最多的 key。但一個(gè) key 的元素多,不一定表示占用內(nèi)存也多,你還需要根據(jù)業(yè)務(wù)情況,進(jìn)一步評(píng)估內(nèi)存占用情況。

4.集中過(guò)期

如果你發(fā)現(xiàn),平時(shí)在操作 Redis 時(shí),并沒(méi)有延遲很大的情況發(fā)生,但在某個(gè)時(shí)間點(diǎn)突然出現(xiàn)一波延時(shí),其現(xiàn)象表現(xiàn)為:變慢的時(shí)間點(diǎn)很有規(guī)律,例如某個(gè)整點(diǎn),或者每間隔多久就會(huì)發(fā)生一波延遲。

如果是出現(xiàn)這種情況,那么你需要排查一下,業(yè)務(wù)代碼中是否存在設(shè)置大量 key 集中過(guò)期的情況。

如果有大量的 key 在某個(gè)固定時(shí)間點(diǎn)集中過(guò)期,在這個(gè)時(shí)間點(diǎn)訪(fǎng)問(wèn) Redis 時(shí),就有可能導(dǎo)致延時(shí)變大。

Redis 的過(guò)期數(shù)據(jù)采用被動(dòng)過(guò)期 + 主動(dòng)過(guò)期兩種策略:

1)被動(dòng)過(guò)期:只有當(dāng)訪(fǎng)問(wèn)某個(gè) key 時(shí),才判斷這個(gè) key 是否已過(guò)期,如果已過(guò)期,則從實(shí)例中刪除。

2)主動(dòng)過(guò)期:Redis 內(nèi)部維護(hù)了一個(gè)定時(shí)任務(wù),默認(rèn)每隔 100 毫秒(1秒10次)就會(huì)從全局的過(guò)期哈希表中隨機(jī)取出 20 個(gè) key,然后刪除其中過(guò)期的 key,如果過(guò)期 key 的比例超過(guò)了 25%,則繼續(xù)重復(fù)此過(guò)程,直到過(guò)期 key 的比例下降到 25% 以下,或者這次任務(wù)的執(zhí)行耗時(shí)超過(guò)了 25 毫秒,才會(huì)退出循環(huán)。

注意,這個(gè)主動(dòng)過(guò)期 key 的定時(shí)任務(wù),是在 Redis 主線(xiàn)程中執(zhí)行的。

也就是說(shuō)如果在執(zhí)行主動(dòng)過(guò)期的過(guò)程中,出現(xiàn)了需要大量刪除過(guò)期 key 的情況,那么此時(shí)應(yīng)用程序在訪(fǎng)問(wèn) Redis 時(shí),必須要等待這個(gè)過(guò)期任務(wù)執(zhí)行結(jié)束,Redis 才可以服務(wù)這個(gè)客戶(hù)端請(qǐng)求。

如果此時(shí)需要過(guò)期刪除的是一個(gè) bigkey,那么這個(gè)耗時(shí)會(huì)更久。而且,這個(gè)操作延遲的命令并不會(huì)記錄在慢日志中。

因?yàn)槁罩局?strong>只記錄一個(gè)命令真正操作內(nèi)存數(shù)據(jù)的耗時(shí) ,而 Redis 主動(dòng)刪除過(guò)期 key 的邏輯,是在命令真正執(zhí)行之前執(zhí)行的。

5.實(shí)例內(nèi)存達(dá)到上限

當(dāng)我們把 Redis 當(dāng)做純緩存使用時(shí),通常會(huì)給這個(gè)實(shí)例設(shè)置一個(gè)內(nèi)存上限 maxmemory,然后設(shè)置一個(gè)數(shù)據(jù)淘汰策略。

當(dāng) Redis 內(nèi)存達(dá)到 maxmemory 后,每次寫(xiě)入新的數(shù)據(jù)之前,Redis 必須先從實(shí)例中踢出一部分?jǐn)?shù)據(jù),讓整個(gè)實(shí)例的內(nèi)存維持在 maxmemory 之下 ,然后才能把新數(shù)據(jù)寫(xiě)進(jìn)來(lái)。

這個(gè)踢出舊數(shù)據(jù)的邏輯也是需要消耗時(shí)間的,而具體耗時(shí)的長(zhǎng)短,要取決于你配置的淘汰策略:

allkeys-lru:不管 key 是否設(shè)置了過(guò)期,淘汰最近最少訪(fǎng)問(wèn)的 key

volatile-lru:只淘汰最近最少訪(fǎng)問(wèn)、并設(shè)置了過(guò)期時(shí)間的 key

allkeys-random:不管 key 是否設(shè)置了過(guò)期,隨機(jī)淘汰 key

volatile-random:只隨機(jī)淘汰設(shè)置了過(guò)期時(shí)間的 key

allkeys-ttl:不管 key 是否設(shè)置了過(guò)期,淘汰即將過(guò)期的 key

noeviction:不淘汰任何 key,實(shí)例內(nèi)存達(dá)到 maxmeory 后,再寫(xiě)入新數(shù)據(jù)直接返回錯(cuò)誤

allkeys-lfu:不管 key 是否設(shè)置了過(guò)期,淘汰訪(fǎng)問(wèn)頻率最低的 key(4.0+版本支持)

volatile-lfu:只淘汰訪(fǎng)問(wèn)頻率最低、并設(shè)置了過(guò)期時(shí)間 key(4.0+版本支持)

一般最常使用的是 allkeys-lru / volatile-lru 淘汰策略 ,它們的處理邏輯是,每次從實(shí)例中隨機(jī)取出一批 key(這個(gè)數(shù)量可配置),然后淘汰一個(gè)最少訪(fǎng)問(wèn)的 key,之后把剩下的 key 暫存到一個(gè)池子中,繼續(xù)隨機(jī)取一批 key,并與之前池子中的 key 比較,再淘汰一個(gè)最少訪(fǎng)問(wèn)的 key。以此往復(fù),直到實(shí)例內(nèi)存降到 maxmemory 之下。

需要注意的是,Redis 的淘汰數(shù)據(jù)的邏輯與刪除過(guò)期 key 的一樣,也是在命令真正執(zhí)行之前執(zhí)行的,也就是說(shuō)它也會(huì)增加我們操作 Redis 的延遲,而且,寫(xiě) OPS 越高,延遲也會(huì)越明顯。

02644d1e-1a0b-11ee-962d-dac502259ad0.png

如果此時(shí)你的 Redis 實(shí)例中還存儲(chǔ)了 bigkey,那么在淘汰刪除 bigkey 釋放內(nèi)存時(shí) ,也會(huì)耗時(shí)比較久。

6.fork耗時(shí)嚴(yán)重

當(dāng) Redis 開(kāi)啟了后臺(tái) RDB 和 AOF rewrite 后,在執(zhí)行時(shí),它們都需要主進(jìn)程創(chuàng)建出一個(gè)子進(jìn)程進(jìn)行數(shù)據(jù)的持久化。

主進(jìn)程創(chuàng)建子進(jìn)程,會(huì)調(diào)用操作系統(tǒng)提供的 fork 函數(shù)。

而 fork 在執(zhí)行過(guò)程中,主進(jìn)程需要拷貝自己的內(nèi)存頁(yè)表給子進(jìn)程 ,如果這個(gè)實(shí)例很大,那么這個(gè)拷貝的過(guò)程也會(huì)比較耗時(shí)。

而且這個(gè) fork 過(guò)程會(huì)消耗大量的 CPU 資源,在完成 fork 之前,整個(gè) Redis 實(shí)例會(huì)被阻塞住,無(wú)法處理任何客戶(hù)端請(qǐng)求。

如果此時(shí)你的 CPU 資源本來(lái)就很緊張,那么 fork 的耗時(shí)會(huì)更長(zhǎng),甚至達(dá)到秒級(jí),這會(huì)嚴(yán)重影響 Redis 的性能。

那如何確認(rèn)確實(shí)是因?yàn)?fork 耗時(shí)導(dǎo)致的 Redis 延遲變大呢?

你可以在 Redis 上執(zhí)行 INFO 命令,查看 latest_fork_usec 項(xiàng),單位微秒。

#上一次fork耗時(shí),單位微秒
latest_fork_usec:59477

這個(gè)時(shí)間就是主進(jìn)程在 fork 子進(jìn)程期間,整個(gè)實(shí)例阻塞無(wú)法處理客戶(hù)端請(qǐng)求的時(shí)間。

如果你發(fā)現(xiàn)這個(gè)耗時(shí)很久,就要警惕起來(lái)了,這意味在這期間,你的整個(gè) Redis 實(shí)例都處于不可用的狀態(tài)。

除了數(shù)據(jù)持久化會(huì)生成 RDB 之外,當(dāng)主從節(jié)點(diǎn)第一次建立數(shù)據(jù)同步時(shí),主節(jié)點(diǎn)也創(chuàng)建子進(jìn)程生成 RDB,然后發(fā)給從節(jié)點(diǎn)進(jìn)行一次全量同步,所以,這個(gè)過(guò)程也會(huì)對(duì) Redis 產(chǎn)生性能影響。

028dbdca-1a0b-11ee-962d-dac502259ad0.png

7.開(kāi)啟內(nèi)存大頁(yè)

除了上面講到的子進(jìn)程 RDB 和 AOF rewrite 期間,fork 耗時(shí)導(dǎo)致的延時(shí)變大之外,這里還有一個(gè)方面也會(huì)導(dǎo)致性能問(wèn)題,這就是操作系統(tǒng)是否開(kāi)啟了內(nèi)存大頁(yè)機(jī)制 。

什么是內(nèi)存大頁(yè)?

我們都知道,應(yīng)用程序向操作系統(tǒng)申請(qǐng)內(nèi)存時(shí),是按內(nèi)存頁(yè) 進(jìn)行申請(qǐng)的,而常規(guī)的內(nèi)存頁(yè)大小是 4KB。

Linux 內(nèi)核從 2.6.38 開(kāi)始,支持了內(nèi)存大頁(yè)機(jī)制 ,該機(jī)制允許應(yīng)用程序以 2MB 大小為單位,向操作系統(tǒng)申請(qǐng)內(nèi)存。

應(yīng)用程序每次向操作系統(tǒng)申請(qǐng)的內(nèi)存單位變大了,但這也意味著申請(qǐng)內(nèi)存的耗時(shí)變長(zhǎng)。

這對(duì) Redis 會(huì)有什么影響呢?

當(dāng) Redis 在執(zhí)行后臺(tái) RDB,采用 fork 子進(jìn)程的方式來(lái)處理。但主進(jìn)程 fork 子進(jìn)程后,此時(shí)的主進(jìn)程依舊是可以接收寫(xiě)請(qǐng)求 的,而進(jìn)來(lái)的寫(xiě)請(qǐng)求,會(huì)采用 Copy On Write(寫(xiě)時(shí)復(fù)制)的方式操作內(nèi)存數(shù)據(jù)。

也就是說(shuō),主進(jìn)程一旦有數(shù)據(jù)需要修改,Redis 并不會(huì)直接修改現(xiàn)有內(nèi)存中的數(shù)據(jù),而是先將這塊內(nèi)存數(shù)據(jù)拷貝出來(lái),再修改這塊新內(nèi)存的數(shù)據(jù) ,這就是所謂的「寫(xiě)時(shí)復(fù)制」。

寫(xiě)時(shí)復(fù)制你也可以理解成,誰(shuí)需要發(fā)生寫(xiě)操作,誰(shuí)就需要先拷貝,再修改。

這樣做的好處是,父進(jìn)程有任何寫(xiě)操作,并不會(huì)影響子進(jìn)程的數(shù)據(jù)持久化(子進(jìn)程只持久化 fork 這一瞬間整個(gè)實(shí)例中的所有數(shù)據(jù)即可,不關(guān)心新的數(shù)據(jù)變更,因?yàn)樽舆M(jìn)程只需要一份內(nèi)存快照,然后持久化到磁盤(pán)上)。

但是請(qǐng)注意,主進(jìn)程在拷貝內(nèi)存數(shù)據(jù)時(shí),這個(gè)階段就涉及到新內(nèi)存的申請(qǐng),如果此時(shí)操作系統(tǒng)開(kāi)啟了內(nèi)存大頁(yè),那么在此期間,客戶(hù)端即便只修改 10B 的數(shù)據(jù),Redis 在申請(qǐng)內(nèi)存時(shí)也會(huì)以 2MB 為單位向操作系統(tǒng)申請(qǐng),申請(qǐng)內(nèi)存的耗時(shí)變長(zhǎng),進(jìn)而導(dǎo)致每個(gè)寫(xiě)請(qǐng)求的延遲增加,影響到 Redis 性能。

同樣地,如果這個(gè)寫(xiě)請(qǐng)求操作的是一個(gè) bigkey,那主進(jìn)程在拷貝這個(gè) bigkey 內(nèi)存塊時(shí),一次申請(qǐng)的內(nèi)存會(huì)更大,時(shí)間也會(huì)更久。可見(jiàn),bigkey 在這里又一次影響到了性能。

8.開(kāi)啟AOF

前面我們分析了 RDB 和 AOF rewrite 對(duì) Redis 性能的影響,主要關(guān)注點(diǎn)在 fork 上。

其實(shí),關(guān)于數(shù)據(jù)持久化方面,還有影響 Redis 性能的因素,這次我們重點(diǎn)來(lái)看 AOF 數(shù)據(jù)持久化。

如果你的 AOF 配置不合理,還是有可能會(huì)導(dǎo)致性能問(wèn)題。

當(dāng) Redis 開(kāi)啟 AOF 后,其工作原理如下:

1)Redis 執(zhí)行寫(xiě)命令后,把這個(gè)命令寫(xiě)入到 AOF 文件內(nèi)存中(write 系統(tǒng)調(diào)用)

2)Redis 根據(jù)配置的 AOF 刷盤(pán)策略,把 AOF 內(nèi)存數(shù)據(jù)刷到磁盤(pán)上(fsync 系統(tǒng)調(diào)用)

為了保證 AOF 文件數(shù)據(jù)的安全性,Redis 提供了 3 種刷盤(pán)機(jī)制:

1)appendfsync always:主線(xiàn)程每次執(zhí)行寫(xiě)操作后立即刷盤(pán),此方案會(huì)占用比較大的磁盤(pán) IO 資源,但數(shù)據(jù)安全性最高。

2)appendfsync no:主線(xiàn)程每次寫(xiě)操作只寫(xiě)內(nèi)存就返回,內(nèi)存數(shù)據(jù)什么時(shí)候刷到磁盤(pán),交由操作系統(tǒng)決定,此方案對(duì)性能影響最小,但數(shù)據(jù)安全性也最低,Redis 宕機(jī)時(shí)丟失的數(shù)據(jù)取決于操作系統(tǒng)刷盤(pán)時(shí)機(jī)。

3)appendfsync everysec:主線(xiàn)程每次寫(xiě)操作只寫(xiě)內(nèi)存就返回,然后由后臺(tái)線(xiàn)程每隔 1 秒執(zhí)行一次刷盤(pán)操作(觸發(fā)fsync系統(tǒng)調(diào)用),此方案對(duì)性能影響相對(duì)較小,但當(dāng) Redis 宕機(jī)時(shí)會(huì)丟失 1 秒的數(shù)據(jù)。

看到這里,我猜你肯定和大多數(shù)人的想法一樣,選比較折中的方案 appendfsync everysec 就沒(méi)問(wèn)題了吧?

這個(gè)方案優(yōu)勢(shì)在于,Redis 主線(xiàn)程寫(xiě)完內(nèi)存后就返回,具體的刷盤(pán)操作是放到后臺(tái)線(xiàn)程中執(zhí)行的,后臺(tái)線(xiàn)程每隔 1 秒把內(nèi)存中的數(shù)據(jù)刷到磁盤(pán)中。

這種方案既兼顧了性能,又盡可能地保證了數(shù)據(jù)安全,是不是覺(jué)得很完美?

但是,這里我要給你潑一盆冷水了,采用這種方案你也要警惕一下,因?yàn)檫@種方案還是存在導(dǎo)致 Redis 延遲變大的情況發(fā)生,甚至?xí)枞麄€(gè) Redis。

你試想這樣一種情況:當(dāng) Redis 后臺(tái)線(xiàn)程在執(zhí)行 AOF 文件刷盤(pán)時(shí),如果此時(shí)磁盤(pán)的 IO 負(fù)載很高,那這個(gè)后臺(tái)線(xiàn)程在執(zhí)行刷盤(pán)操作(fsync系統(tǒng)調(diào)用)時(shí)就會(huì)被阻塞住。

此時(shí)的主線(xiàn)程依舊會(huì)接收寫(xiě)請(qǐng)求,緊接著,主線(xiàn)程又需要把數(shù)據(jù)寫(xiě)到文件內(nèi)存中(write 系統(tǒng)調(diào)用),當(dāng)主線(xiàn)程使用后臺(tái)子線(xiàn)程執(zhí)行了一次 fsync,需要再次把新接收的操作記錄寫(xiě)回磁盤(pán)時(shí),如果主線(xiàn)程發(fā)現(xiàn)上一次的 fsync 還沒(méi)有執(zhí)行完,那么它就會(huì)阻塞。

所以,如果后臺(tái)子線(xiàn)程執(zhí)行的 fsync 頻繁阻塞的話(huà)(比如 AOF 重寫(xiě)占用了大量的磁盤(pán) IO 帶寬),主線(xiàn)程也會(huì)阻塞,導(dǎo)致 Redis 性能變慢。

02ad0284-1a0b-11ee-962d-dac502259ad0.png

看到了么?在這個(gè)過(guò)程中,主線(xiàn)程依舊有阻塞的風(fēng)險(xiǎn)。

所以,盡管你的 AOF 配置為 appendfsync everysec,也不能掉以輕心,要警惕磁盤(pán)壓力過(guò)大導(dǎo)致的 Redis 有性能問(wèn)題。

那什么情況下會(huì)導(dǎo)致磁盤(pán) IO 負(fù)載過(guò)大?以及如何解決這個(gè)問(wèn)題呢?

我總結(jié)了以下幾種情況,你可以參考進(jìn)行問(wèn)題排查:

1)進(jìn)程正在執(zhí)行 AOF rewrite,這個(gè)過(guò)程會(huì)占用大量的磁盤(pán) IO 資源

2)有其他應(yīng)用程序在執(zhí)行大量的寫(xiě)文件操作,也會(huì)占用磁盤(pán) IO 資源

對(duì)于情況1,說(shuō)白了就是,Redis 的 AOF 后臺(tái)子線(xiàn)程刷盤(pán)操作,撞上了子進(jìn)程 AOF rewrite!

9.綁定CPU

很多時(shí)候,我們?cè)诓渴鸱?wù)時(shí),為了提高服務(wù)性能,降低應(yīng)用程序在多個(gè) CPU 核心之間的上下文切換帶來(lái)的性能損耗,通常采用的方案是進(jìn)程綁定 CPU 的方式提高性能。

我們都知道,一般現(xiàn)代的服務(wù)器會(huì)有多個(gè) CPU,而每個(gè) CPU 又包含多個(gè)物理核心,每個(gè)物理核心又分為多個(gè)邏輯核心,每個(gè)物理核下的邏輯核共用 L1/L2 Cache。

而 Redis Server 除了主線(xiàn)程服務(wù)客戶(hù)端請(qǐng)求之外,還會(huì)創(chuàng)建子進(jìn)程、子線(xiàn)程。

其中子進(jìn)程用于數(shù)據(jù)持久化,而子線(xiàn)程用于執(zhí)行一些比較耗時(shí)操作,例如異步釋放 fd、異步 AOF 刷盤(pán)、異步 lazy-free 等等。

如果你把 Redis 進(jìn)程只綁定了一個(gè) CPU 邏輯核心上,那么當(dāng) Redis 在進(jìn)行數(shù)據(jù)持久化時(shí),fork 出的子進(jìn)程會(huì)繼承父進(jìn)程的 CPU 使用偏好。

而此時(shí)的子進(jìn)程會(huì)消耗大量的 CPU 資源進(jìn)行數(shù)據(jù)持久化(把實(shí)例數(shù)據(jù)全部掃描出來(lái)需要耗費(fèi)CPU),這就會(huì)導(dǎo)致子進(jìn)程會(huì)與主進(jìn)程發(fā)生 CPU 爭(zhēng)搶?zhuān)M(jìn)而影響到主進(jìn)程服務(wù)客戶(hù)端請(qǐng)求,訪(fǎng)問(wèn)延遲變大。

這就是 Redis 綁定 CPU 帶來(lái)的性能問(wèn)題。

10.使用Swap

如果你發(fā)現(xiàn) Redis 突然變得非常慢,每次的操作耗時(shí)都達(dá)到了幾百毫秒甚至秒級(jí),那此時(shí)你就需要檢查 Redis 是否使用到了 Swap,在這種情況下 Redis 基本上已經(jīng)無(wú)法提供高性能的服務(wù)了。

什么是 Swap?為什么使用 Swap 會(huì)導(dǎo)致 Redis 的性能下降?

如果你對(duì)操作系統(tǒng)有些了解,就會(huì)知道操作系統(tǒng)為了緩解內(nèi)存不足對(duì)應(yīng)用程序的影響,允許把一部分內(nèi)存中的數(shù)據(jù)換到磁盤(pán)上,以達(dá)到應(yīng)用程序?qū)?nèi)存使用的緩沖,這些內(nèi)存數(shù)據(jù)被換到磁盤(pán)上的區(qū)域,就是 Swap。

問(wèn)題就在于,當(dāng)內(nèi)存中的數(shù)據(jù)被換到磁盤(pán)上后,Redis 再訪(fǎng)問(wèn)這些數(shù)據(jù)時(shí),就需要從磁盤(pán)上讀取,訪(fǎng)問(wèn)磁盤(pán)的速度要比訪(fǎng)問(wèn)內(nèi)存慢幾百倍!

尤其是針對(duì) Redis 這種對(duì)性能要求極高、性能極其敏感的數(shù)據(jù)庫(kù)來(lái)說(shuō),這個(gè)操作延時(shí)是無(wú)法接受的。

此時(shí),你需要檢查 Redis 機(jī)器的內(nèi)存使用情況,確認(rèn)是否存在使用了 Swap。

你可以通過(guò)以下方式來(lái)查看 Redis 進(jìn)程是否使用到了 Swap:

#先找到Redis的進(jìn)程ID
$ps-aux|grepredis-server
#查看RedisSwap使用情況
$cat/proc/$pid/smaps|egrep'^(Swap|Size)'

輸出結(jié)果如下:

Size:1256kB
Swap:0kB
Size:4kB
Swap:0kB
Size:132kB
Swap:0kB
Size:63488kB
Swap:0kB
Size:132kB
Swap:0kB
Size:65404kB
Swap:0kB
Size:1921024kB
Swap:0kB

每一行 Size 表示 Redis 所用的一塊內(nèi)存大小,Size 下面的 Swap 就表示這塊 Size 大小的內(nèi)存,有多少數(shù)據(jù)已經(jīng)被換到磁盤(pán)上了,如果這兩個(gè)值相等,說(shuō)明這塊內(nèi)存的數(shù)據(jù)都已經(jīng)完全被換到磁盤(pán)上了。

如果只是少量數(shù)據(jù)被換到磁盤(pán)上,例如每一塊 Swap 占對(duì)應(yīng) Size 的比例很小,那影響并不是很大。如果是幾百兆甚至上 GB 的內(nèi)存 被換到了磁盤(pán)上,那么你就需要警惕了,這種情況 Redis 的性能肯定會(huì)急劇下降。

11.碎片整理

Redis 的數(shù)據(jù)都存儲(chǔ)在內(nèi)存中,當(dāng)我們的應(yīng)用程序頻繁修改 Redis 中的數(shù)據(jù)時(shí),就有可能會(huì)導(dǎo)致 Redis 產(chǎn)生內(nèi)存碎片。

內(nèi)存碎片會(huì)降低 Redis 的內(nèi)存使用率,我們可以通過(guò)執(zhí)行 INFO 命令,得到這個(gè)實(shí)例的內(nèi)存碎片率:

#Memory
used_memory:5709194824
used_memory_human:5.32G
used_memory_rss:8264855552
used_memory_rss_human:7.70G
...
mem_fragmentation_ratio:1.45

這個(gè)內(nèi)存碎片率是怎么計(jì)算的?

很簡(jiǎn)單,mem_fragmentation_ratio = used_memory_rss / used_memory。

其中 used_memory 表示 Redis 存儲(chǔ)數(shù)據(jù)的內(nèi)存大小,而 used_memory_rss 表示操作系統(tǒng)實(shí)際分配給 Redis 進(jìn)程的大小。

如果 mem_fragmentation_ratio > 1.5,說(shuō)明內(nèi)存碎片率已經(jīng)超過(guò)了 50%,這時(shí)我們就需要采取一些措施來(lái)降低內(nèi)存碎片了。

解決的方案一般如下:

1)如果你使用的是 Redis 4.0 以下版本,只能通過(guò)重啟實(shí)例來(lái)解決

2)如果你使用的是 Redis 4.0 版本,它正好提供了自動(dòng)碎片整理的功能,可以通過(guò)配置開(kāi)啟碎片自動(dòng)整理。

但是,開(kāi)啟內(nèi)存碎片整理,它也有可能會(huì)導(dǎo)致 Redis 性能下降。

原因在于,Redis 的碎片整理工作是也在主線(xiàn)程 中執(zhí)行的,當(dāng)其進(jìn)行碎片整理時(shí),必然會(huì)消耗 CPU 資源,產(chǎn)生更多的耗時(shí),從而影響到客戶(hù)端的請(qǐng)求。

所以,當(dāng)你需要開(kāi)啟這個(gè)功能時(shí),最好提前測(cè)試評(píng)估它對(duì) Redis 的影響。

Redis 碎片整理的參數(shù)配置如下:

#開(kāi)啟自動(dòng)內(nèi)存碎片整理(總開(kāi)關(guān))
activedefragyes

#內(nèi)存使用100MB以下,不進(jìn)行碎片整理
active-defrag-ignore-bytes100mb

#內(nèi)存碎片率超過(guò)10%,開(kāi)始碎片整理
active-defrag-threshold-lower10
#內(nèi)存碎片率超過(guò)100%,盡最大努力碎片整理
active-defrag-threshold-upper100

#內(nèi)存碎片整理占用CPU資源最小百分比
active-defrag-cycle-min1
#內(nèi)存碎片整理占用CPU資源最大百分比
active-defrag-cycle-max25

#碎片整理期間,對(duì)于List/Set/Hash/ZSet類(lèi)型元素一次Scan的數(shù)量
active-defrag-max-scan-fields1000

二、Redis如何優(yōu)化

1.慢查詢(xún)優(yōu)化

1)盡量不使用 O(N) 以上復(fù)雜度過(guò)高的命令,對(duì)于數(shù)據(jù)的聚合操作,放在客戶(hù)端做。

2)執(zhí)行 O(N) 命令,保證 N 盡量的?。ㄍ扑] N <= 300),每次獲取盡量少的數(shù)據(jù),讓 Redis 可以及時(shí)處理返回。

2.集中過(guò)期優(yōu)化

一般有兩種方案來(lái)規(guī)避這個(gè)問(wèn)題:

1.集中過(guò)期 key 增加一個(gè)隨機(jī)過(guò)期時(shí)間,把集中過(guò)期的時(shí)間打散,降低 Redis 清理過(guò)期 key 的壓力

2.如果你使用的 Redis 是 4.0 以上版本,可以開(kāi)啟 lazy-free 機(jī)制,當(dāng)刪除過(guò)期 key 時(shí),把釋放內(nèi)存的操作放到后臺(tái)線(xiàn)程中執(zhí)行,避免阻塞主線(xiàn)程。

第一種方案,在設(shè)置 key 的過(guò)期時(shí)間時(shí),增加一個(gè)隨機(jī)時(shí)間,偽代碼可以這么寫(xiě):

#在過(guò)期時(shí)間點(diǎn)之后的5分鐘內(nèi)隨機(jī)過(guò)期掉
redis.expireat(key,expire_time+random(300))

第二種方案,Redis 4.0 以上版本,開(kāi)啟 lazy-free 機(jī)制:

#釋放過(guò)期key的內(nèi)存,放到后臺(tái)線(xiàn)程執(zhí)行
lazyfree-lazy-expireyes

運(yùn)維層面,你需要把 Redis 的各項(xiàng)運(yùn)行狀態(tài)數(shù)據(jù)監(jiān)控起來(lái),在 Redis 上執(zhí)行 INFO 命令就可以拿到這個(gè)實(shí)例所有的運(yùn)行狀態(tài)數(shù)據(jù)。

在這里我們需要重點(diǎn)關(guān)注 expired_keys 這一項(xiàng) ,它代表整個(gè)實(shí)例到目前為止,累計(jì)刪除過(guò)期 key 的數(shù)量。

你需要把這個(gè)指標(biāo)監(jiān)控起來(lái),當(dāng)這個(gè)指標(biāo)在很短時(shí)間內(nèi)出現(xiàn)了突增,需要及時(shí)報(bào)警出來(lái),然后與業(yè)務(wù)應(yīng)用報(bào)慢的時(shí)間點(diǎn)進(jìn)行對(duì)比分析,確認(rèn)時(shí)間是否一致,如果一致,則可以確認(rèn)確實(shí)是因?yàn)榧羞^(guò)期 key 導(dǎo)致的延遲變大。

3.實(shí)例內(nèi)存達(dá)到上限優(yōu)化

1)避免存儲(chǔ) bigkey,降低釋放內(nèi)存的耗時(shí)

2)淘汰策略改為隨機(jī)淘汰,隨機(jī)淘汰比 LRU 要快很多(視業(yè)務(wù)情況調(diào)整)

3)拆分實(shí)例,把淘汰 key 的壓力分?jǐn)偟蕉鄠€(gè)實(shí)例上

4)如果使用的是 Redis 4.0 以上版本,開(kāi)啟 layz-free 機(jī)制,把淘汰 key 釋放內(nèi)存的操作放到后臺(tái)線(xiàn)程中執(zhí)行(配置 lazyfree-lazy-eviction = yes)

4.fork耗時(shí)嚴(yán)重優(yōu)化

1)控制 Redis 實(shí)例的內(nèi)存:盡量在 10G 以下,執(zhí)行 fork 的耗時(shí)與實(shí)例大小有關(guān),實(shí)例越大,耗時(shí)越久。

2)合理配置數(shù)據(jù)持久化策略:在 slave 節(jié)點(diǎn)執(zhí)行 RDB 備份,推薦在低峰期執(zhí)行,而對(duì)于丟失數(shù)據(jù)不敏感的業(yè)務(wù)(例如把 Redis 當(dāng)做純緩存使用),可以關(guān)閉 AOF 和 AOF rewrite。

3)Redis 實(shí)例不要部署在虛擬機(jī)上:fork 的耗時(shí)也與系統(tǒng)也有關(guān),虛擬機(jī)比物理機(jī)耗時(shí)更久。

4)降低主從庫(kù)全量同步的概率:適當(dāng)調(diào)大 repl-backlog-size 參數(shù),避免主從全量同步。

從建立同步時(shí),優(yōu)先檢測(cè)是否可以嘗試只同步部分?jǐn)?shù)據(jù),這種情況就是針對(duì)于之前已經(jīng)建立好了復(fù)制鏈路,只是因?yàn)楣收蠈?dǎo)致臨時(shí)斷開(kāi),故障恢復(fù)后重新建立同步時(shí),為了避免全量同步的資源消耗,Redis會(huì)優(yōu)先嘗試部分?jǐn)?shù)據(jù)同步,如果條件不符合,才會(huì)觸發(fā)全量同步。

這個(gè)判斷依據(jù)就是在master上維護(hù)的復(fù)制緩沖區(qū)大小,如果這個(gè)緩沖區(qū)配置的過(guò)小,很有可能在主從斷開(kāi)復(fù)制的這段時(shí)間內(nèi),master產(chǎn)生的寫(xiě)入導(dǎo)致復(fù)制緩沖區(qū)的數(shù)據(jù)被覆蓋,重新建立同步時(shí)的slave需要同步的offset位置在master的緩沖區(qū)中找不到,那么此時(shí)就會(huì)觸發(fā)全量同步。

如何避免這種情況?解決方案就是適當(dāng)調(diào)大復(fù)制緩沖區(qū)repl-backlog-size的大小,這個(gè)緩沖區(qū)的大小默認(rèn)為1MB,如果實(shí)例寫(xiě)入量比較大,可以針對(duì)性調(diào)大此配置。

5.多核CPU優(yōu)化

那如何解決這個(gè)問(wèn)題呢?

如果你確實(shí)想要綁定 CPU,可以?xún)?yōu)化的方案是,不要讓 Redis 進(jìn)程只綁定在一個(gè) CPU 邏輯核上,而是綁定在多個(gè)邏輯核心上,而且,綁定的多個(gè)邏輯核心最好是同一個(gè)物理核心,這樣它們還可以共用 L1/L2 Cache。

當(dāng)然,即便我們把 Redis 綁定在多個(gè)邏輯核心上,也只能在一定程度上緩解主線(xiàn)程、子進(jìn)程、后臺(tái)線(xiàn)程在 CPU 資源上的競(jìng)爭(zhēng)。

因?yàn)檫@些子進(jìn)程、子線(xiàn)程還是會(huì)在這多個(gè)邏輯核心上進(jìn)行切換,存在性能損耗。

如何再進(jìn)一步優(yōu)化?

可能你已經(jīng)想到了,我們是否可以讓主線(xiàn)程、子進(jìn)程、后臺(tái)線(xiàn)程,分別綁定在固定的 CPU 核心上,不讓它們來(lái)回切換,這樣一來(lái),他們各自使用的 CPU 資源互不影響。

其實(shí),這個(gè)方案 Redis 官方已經(jīng)想到了。

Redis 在 6.0 版本已經(jīng)推出了這個(gè)功能,我們可以通過(guò)以下配置,對(duì)主線(xiàn)程、后臺(tái)線(xiàn)程、后臺(tái) RDB 進(jìn)程、AOF rewrite 進(jìn)程,綁定固定的 CPU 邏輯核心:

Redis6.0 前綁定CPU核

taskset-c0./redis-server

Redis6.0 后綁定CPU核

#RedisServer和IO線(xiàn)程綁定到CPU核心0,2,4,6
server_cpulist0-7:2
#后臺(tái)子線(xiàn)程綁定到CPU核心1,3
bio_cpulist1,3
#后臺(tái)AOFrewrite進(jìn)程綁定到CPU核心8,9,10,11
aof_rewrite_cpulist8-11
#后臺(tái)RDB進(jìn)程綁定到CPU核心1,10,11
#bgsave_cpulist1,10-1

如果你使用的正好是 Redis 6.0 版本,就可以通過(guò)以上配置,來(lái)進(jìn)一步提高 Redis 性能。

這里我需要提醒你的是,一般來(lái)說(shuō),Redis 的性能已經(jīng)足夠優(yōu)秀,除非你對(duì) Redis 的性能有更加嚴(yán)苛的要求,否則不建議你綁定 CPU。

6.查看Redis內(nèi)存是否發(fā)生Swap

$redis-cliinfo|grepprocess_id
process_id:5332

然后,進(jìn)入 Redis 所在機(jī)器的 /proc 目錄下的該進(jìn)程目錄中:

$cd/proc/5332

最后,運(yùn)行下面的命令,查看該 Redis 進(jìn)程的使用情況。在這兒,我只截取了部分結(jié)果:

$catsmaps|egrep'^(Swap|Size)'
Size:584kB
Swap:0kB
Size:4kB
Swap:4kB
Size:4kB
Swap:0kB
Size:462044kB
Swap:462008kB
Size:21392kB
Swap:0kB

一旦發(fā)生內(nèi)存 swap,最直接的解決方法就是增加機(jī)器內(nèi)存。如果該實(shí)例在一個(gè) Redis 切片集群中,可以增加 Redis 集群的實(shí)例個(gè)數(shù),來(lái)分?jǐn)偯總€(gè)實(shí)例服務(wù)的數(shù)據(jù)量,進(jìn)而減少每個(gè)實(shí)例所需的內(nèi)存量。

7.內(nèi)存大頁(yè)

如果采用了內(nèi)存大頁(yè),那么,即使客戶(hù)端請(qǐng)求只修改 100B 的數(shù)據(jù),Redis 也需要拷貝 2MB 的大頁(yè)。相反,如果是常規(guī)內(nèi)存頁(yè)機(jī)制,只用拷貝 4KB。兩者相比,你可以看到,當(dāng)客戶(hù)端請(qǐng)求修改或新寫(xiě)入數(shù)據(jù)較多時(shí),內(nèi)存大頁(yè)機(jī)制將導(dǎo)致大量的拷貝,這就會(huì)影響 Redis 正常的訪(fǎng)存操作,最終導(dǎo)致性能變慢。

首先,我們要先排查下內(nèi)存大頁(yè)。方法是:在 Redis 實(shí)例運(yùn)行的機(jī)器上執(zhí)行如下命令:

$cat/sys/kernel/mm/transparent_hugepage/enabled
[always]madvisenever

如果執(zhí)行結(jié)果是 always,就表明內(nèi)存大頁(yè)機(jī)制被啟動(dòng)了;如果是 never,就表示,內(nèi)存大頁(yè)機(jī)制被禁止。

在實(shí)際生產(chǎn)環(huán)境中部署時(shí),我建議你不要使用內(nèi)存大頁(yè)機(jī)制 ,操作也很簡(jiǎn)單,只需要執(zhí)行下面的命令就可以了:

echonever/sys/kernel/mm/transparent_hugepage/enabled

其實(shí),操作系統(tǒng)提供的內(nèi)存大頁(yè)機(jī)制,其優(yōu)勢(shì)是,可以在一定程序上降低應(yīng)用程序申請(qǐng)內(nèi)存的次數(shù)。

但是對(duì)于 Redis 這種對(duì)性能和延遲極其敏感的數(shù)據(jù)庫(kù)來(lái)說(shuō),我們希望 Redis 在每次申請(qǐng)內(nèi)存時(shí),耗時(shí)盡量短,所以我不建議你在 Redis 機(jī)器上開(kāi)啟這個(gè)機(jī)制。

***8.刪除使用Lazy Free* **

支持版本:Redis 4.0+

1)主動(dòng)刪除鍵使用lazy free

UNLINK命令

127.0.0.1:7000>LLENmylist
(integer)2000000
127.0.0.1:7000>UNLINKmylist
(integer)1
127.0.0.1:7000>SLOWLOGget
1)1)(integer)1
2)(integer)1505465188
3)(integer)30
4)1)"UNLINK"
2)"mylist"
5)"127.0.0.1:17015"
6)""

注意:DEL命令,還是并發(fā)阻塞的刪除操作

FLUSHALL/FLUSHDB ASYNC

127.0.0.1:7000>DBSIZE
(integer)1812295
127.0.0.1:7000>flushall//同步清理實(shí)例數(shù)據(jù),180萬(wàn)個(gè)key耗時(shí)1020毫秒
OK
(1.02s)
127.0.0.1:7000>DBSIZE
(integer)1812637
127.0.0.1:7000>flushallasync//異步清理實(shí)例數(shù)據(jù),180萬(wàn)個(gè)key耗時(shí)約9毫秒
OK
127.0.0.1:7000>SLOWLOGget
1)1)(integer)2996109
2)(integer)1505465989
3)(integer)9274//指令運(yùn)行耗時(shí)9.2毫秒
4)1)"flushall"
2)"async"
5)"127.0.0.1:20110"
6)""

2)被動(dòng)刪除鍵使用lazy free

lazy free應(yīng)用于被動(dòng)刪除中,目前有4種場(chǎng)景,每種場(chǎng)景對(duì)應(yīng)一個(gè)配置參數(shù);默認(rèn)都是關(guān)閉。

lazyfree-lazy-evictionno
lazyfree-lazy-expireno
lazyfree-lazy-server-delno
slave-lazy-flushno

lazyfree-lazy-eviction

針對(duì)redis內(nèi)存使用達(dá)到maxmeory,并設(shè)置有淘汰策略時(shí);在被動(dòng)淘汰鍵時(shí),是否采用lazy free機(jī)制;因?yàn)榇藞?chǎng)景開(kāi)啟lazy free, 可能使用淘汰鍵的內(nèi)存釋放不及時(shí),導(dǎo)致redis內(nèi)存超用,超過(guò)maxmemory的限制。此場(chǎng)景使用時(shí),請(qǐng)結(jié)合業(yè)務(wù)測(cè)試。(生產(chǎn)環(huán)境不建議設(shè)置yes)

lazyfree-lazy-expire

針對(duì)設(shè)置有TTL的鍵,達(dá)到過(guò)期后,被redis清理刪除時(shí)是否采用lazy free機(jī)制;此場(chǎng)景建議開(kāi)啟,因TTL本身是自適應(yīng)調(diào)整的速度。

lazyfree-lazy-server-del

針對(duì)有些指令在處理已存在的鍵時(shí),會(huì)帶有一個(gè)隱式的DEL鍵的操作。如rename命令,當(dāng)目標(biāo)鍵已存在,redis會(huì)先刪除目標(biāo)鍵,如果這些目標(biāo)鍵是一個(gè)big key,那就會(huì)引入阻塞刪除的性能問(wèn)題。此參數(shù)設(shè)置就是解決這類(lèi)問(wèn)題,建議可開(kāi)啟。

slave-lazy-flush

針對(duì)slave進(jìn)行全量數(shù)據(jù)同步,slave在加載master的RDB文件前,會(huì)運(yùn)行flushall來(lái)清理自己的數(shù)據(jù)場(chǎng)景, 參數(shù)設(shè)置決定是否采用異常flush機(jī)制。如果內(nèi)存變動(dòng)不大,建議可開(kāi)啟??蓽p少全量同步耗時(shí),從而減少主庫(kù)因輸出緩沖區(qū)爆漲引起的內(nèi)存使用增長(zhǎng)。

3)lazy free的監(jiān)控

lazy free能監(jiān)控的數(shù)據(jù)指標(biāo),只有一個(gè)值:lazyfree_pending_objects,表示redis執(zhí)行l(wèi)azy free操作,在等待被實(shí)際回收內(nèi)容的鍵個(gè)數(shù)。并不能體現(xiàn)單個(gè)大鍵的元素個(gè)數(shù)或等待lazy free回收的內(nèi)存大小。所以此值有一定參考值,可監(jiān)測(cè)redis lazy free的效率或堆積鍵數(shù)量;比如在flushall async場(chǎng)景下會(huì)有少量的堆積。

#infomemory

#Memory
lazyfree_pending_objects:0

注意事項(xiàng) :unlink命令入口函數(shù)unlinkCommand()和del調(diào)用相同函數(shù)delGenericCommand()進(jìn)行刪除KEY操作,使用lazy標(biāo)識(shí)是否為lazyfree調(diào)用。如果是lazyfree,則調(diào)用dbAsyncDelete()函數(shù)。

但并非每次unlink命令就一定啟用lazy free,redis會(huì)先判斷釋放KEY的代價(jià)(cost),當(dāng)cost大于LAZYFREE_THRESHOLD(64)才進(jìn)行l(wèi)azy free.

釋放key代價(jià)計(jì)算函數(shù)lazyfreeGetFreeEffort(),集合類(lèi)型鍵,且滿(mǎn)足對(duì)應(yīng)編碼,cost就是集合鍵的元數(shù)個(gè)數(shù),否則cost就是1。

舉例:

一個(gè)包含100元素的list key, 它的free cost就是100

一個(gè)512MB的string key, 它的free cost是1 所以可以看出,redis的lazy free的cost計(jì)算主要時(shí)間復(fù)雜度相關(guān)。

9.AOF優(yōu)化

Redis 提供了一個(gè)配置項(xiàng),當(dāng)子進(jìn)程在 AOF rewrite 期間,可以讓后臺(tái)子線(xiàn)程不執(zhí)行刷盤(pán)(不觸發(fā) fsync 系統(tǒng)調(diào)用)操作。

這相當(dāng)于在 AOF rewrite 期間,臨時(shí)把 appendfsync 設(shè)置為了 none,配置如下:

#AOFrewrite期間,AOF后臺(tái)子線(xiàn)程不進(jìn)行刷盤(pán)操作
#相當(dāng)于在這期間,臨時(shí)把a(bǔ)ppendfsync設(shè)置為了none
no-appendfsync-on-rewriteyes

當(dāng)然,開(kāi)啟這個(gè)配置項(xiàng),在 AOF rewrite 期間,如果實(shí)例發(fā)生宕機(jī),那么此時(shí)會(huì)丟失更多的數(shù)據(jù),性能和數(shù)據(jù)安全性,你需要權(quán)衡后進(jìn)行選擇。

如果占用磁盤(pán)資源的是其他應(yīng)用程序,那就比較簡(jiǎn)單了,你需要定位到是哪個(gè)應(yīng)用程序在大量寫(xiě)磁盤(pán),然后把這個(gè)應(yīng)用程序遷移到其他機(jī)器上執(zhí)行就好了,避免對(duì) Redis 產(chǎn)生影響。

當(dāng)然,如果你對(duì) Redis 的性能和數(shù)據(jù)安全都有很高的要求,那么建議從硬件層面來(lái)優(yōu)化 ,更換為 SSD 磁盤(pán),提高磁盤(pán)的 IO 能力,保證 AOF 期間有充足的磁盤(pán)資源可以使用。同時(shí)盡可能讓Redis運(yùn)行在獨(dú)立的機(jī)器上。

10.Swap優(yōu)化

1)增加機(jī)器的內(nèi)存,讓 Redis 有足夠的內(nèi)存可以使用

2)整理內(nèi)存空間,釋放出足夠的內(nèi)存供 Redis 使用,然后釋放 Redis 的 Swap,讓 Redis 重新使用內(nèi)存

釋放 Redis 的 Swap 過(guò)程通常要重啟實(shí)例,為了避免重啟實(shí)例對(duì)業(yè)務(wù)的影響,一般會(huì)先進(jìn)行主從切換,然后釋放舊主節(jié)點(diǎn)的 Swap,重啟舊主節(jié)點(diǎn)實(shí)例,待從庫(kù)數(shù)據(jù)同步完成后,再進(jìn)行主從切換即可。

預(yù)防的辦法就是,你需要對(duì) Redis 機(jī)器的內(nèi)存和 Swap 使用情況進(jìn)行監(jiān)控,在內(nèi)存不足或使用到 Swap 時(shí)報(bào)警出來(lái),及時(shí)處理。

三、Redis變慢了排查步驟

1.獲取 Redis 實(shí)例在當(dāng)前環(huán)境下的基線(xiàn)性能。

2.是否用了慢查詢(xún)命令?如果是的話(huà),就使用其他命令替代慢查詢(xún)命令,或者把聚合計(jì)算命令放在客戶(hù)端做。

3.是否對(duì)過(guò)期 key 設(shè)置了相同的過(guò)期時(shí)間?對(duì)于批量刪除的 key,可以在每個(gè) key 的過(guò)期時(shí)間上加一個(gè)隨機(jī)數(shù),避免同時(shí)刪除。

4.是否存在 bigkey?對(duì)于 bigkey 的刪除操作,如果你的 Redis 是 4.0 及以上的版本,可以直接利用異步線(xiàn)程機(jī)制減少主線(xiàn)程阻塞;如果是 Redis 4.0 以前的版本,可以使用 SCAN 命令迭代刪除;對(duì)于 bigkey 的集合查詢(xún)和聚合操作,可以使用 SCAN 命令在客戶(hù)端完成。

5.Redis AOF 配置級(jí)別是什么?業(yè)務(wù)層面是否的確需要這一可靠性級(jí)別?如果我們需要高性能,同時(shí)也允許數(shù)據(jù)丟失,可以將配置項(xiàng) no-appendfsync-on-rewrite 設(shè)置為 yes,避免 AOF 重寫(xiě)和 fsync 競(jìng)爭(zhēng)磁盤(pán) IO 資源,導(dǎo)致 Redis 延遲增加。當(dāng)然, 如果既需要高性能又需要高可靠性,最好使用高速固態(tài)盤(pán)作為 AOF 日志的寫(xiě)入盤(pán)。

6.Redis 實(shí)例的內(nèi)存使用是否過(guò)大?發(fā)生 swap 了嗎?如果是的話(huà),就增加機(jī)器內(nèi)存,或者是使用 Redis 集群,分?jǐn)倖螜C(jī) Redis 的鍵值對(duì)數(shù)量和內(nèi)存壓力。同時(shí),要避免出現(xiàn) Redis 和其他內(nèi)存需求大的應(yīng)用共享機(jī)器的情況。

7.在 Redis 實(shí)例的運(yùn)行環(huán)境中,是否啟用了透明大頁(yè)機(jī)制?如果是的話(huà),直接關(guān)閉內(nèi)存大頁(yè)機(jī)制就行了。

8.是否運(yùn)行了 Redis 主從集群?如果是的話(huà),把主庫(kù)實(shí)例的數(shù)據(jù)量大小控制在 2~4GB,以免主從復(fù)制時(shí),從庫(kù)因加載大的 RDB 文件而阻塞。

9.是否使用了多核 CPU 或 NUMA 架構(gòu)的機(jī)器運(yùn)行 Redis 實(shí)例?使用多核 CPU 時(shí),可以給 Redis 實(shí)例綁定物理核;使用 NUMA 架構(gòu)時(shí),注意把 Redis 實(shí)例和網(wǎng)絡(luò)中斷處理程序運(yùn)行在同一個(gè) CPU Socket 上。

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

    關(guān)注

    68

    文章

    11070

    瀏覽量

    216792
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    13

    文章

    9772

    瀏覽量

    87785
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3118

    瀏覽量

    75195
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    386

    瀏覽量

    11416

原文標(biāo)題:Redis10大性能優(yōu)化策略

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何排查Redis性能問(wèn)題 Redis內(nèi)部實(shí)現(xiàn)原理解析

    作為業(yè)務(wù)開(kāi)發(fā)人員,我們需要了解 Redis 的基本原理,例如各個(gè)命令執(zhí)行的時(shí)間復(fù)雜度、數(shù)據(jù)過(guò)期策略、數(shù)據(jù)淘汰策略等,從而更合理地使用 Redis 命令,并且結(jié)合業(yè)務(wù)場(chǎng)景進(jìn)行
    發(fā)表于 07-05 12:33 ?448次閱讀
    如何排查<b class='flag-5'>Redis</b><b class='flag-5'>性能</b>問(wèn)題 <b class='flag-5'>Redis</b>內(nèi)部實(shí)現(xiàn)原理解析

    Linux系統(tǒng)的性能優(yōu)化策略

    近年來(lái),世界上許多大軟件公司紛紛推出各種Linux服務(wù)器系統(tǒng)及Linux下的應(yīng)用軟件。目前,Linux 已可以與各種傳統(tǒng)的商業(yè)操作系統(tǒng)分庭抗禮,在服務(wù)器市場(chǎng),占據(jù)了相當(dāng)大的份額。本文分別從磁盤(pán)調(diào)優(yōu),文件系統(tǒng),內(nèi)存管理以及編譯優(yōu)化等方面來(lái)論述 Linux系統(tǒng)的優(yōu)化調(diào)優(yōu)
    發(fā)表于 07-16 06:23

    Redis的內(nèi)存淘汰機(jī)制

    redis淘汰策略
    發(fā)表于 09-27 07:55

    淺析Redis的過(guò)期機(jī)制

    Redis數(shù)據(jù)過(guò)期策略詳解
    發(fā)表于 10-12 15:12

    FPGA設(shè)計(jì)應(yīng)用及優(yōu)化策略有哪些?

    EDA技術(shù)具有什么特征?FPGA是什么原理?FPGA設(shè)計(jì)應(yīng)用及優(yōu)化策略基于VHDL的FPGA系統(tǒng)行為級(jí)設(shè)計(jì)
    發(fā)表于 04-15 06:33

    全面分析Redis的最佳實(shí)踐優(yōu)化

    這篇文章我想和你聊一聊 Redis 的最佳實(shí)踐。 你的項(xiàng)目或許已經(jīng)使用 Redis 很長(zhǎng)時(shí)間了,但在使用過(guò)程中,你可能還會(huì)或多或少地遇到以下問(wèn)題: 我的 Redis 內(nèi)存為什么增長(zhǎng)這么快? 為什么我
    的頭像 發(fā)表于 04-26 10:51 ?2047次閱讀

    探究Redis 性能測(cè)試與監(jiān)控

    很多人在安裝部署好Redis后,就沒(méi)有對(duì)Rredis的配置和部署等有效性和高可用性進(jìn)行性能測(cè)試,最終導(dǎo)致上線(xiàn)出現(xiàn)緩存穿透、雪崩等現(xiàn)象,導(dǎo)致性能還是有問(wèn)題,其實(shí)做為技術(shù)運(yùn)維人員在部署好Redis
    的頭像 發(fā)表于 10-12 09:19 ?1676次閱讀
    探究<b class='flag-5'>Redis</b> <b class='flag-5'>性能</b>測(cè)試與監(jiān)控

    針對(duì)Redis服務(wù)我們應(yīng)該避免哪些性能浪費(fèi)

    ],最新的用戶(hù)關(guān)系[2],都存儲(chǔ)在 Redis 中,大量的查詢(xún)擊中 Redis,而不走 MySQL。 那么,針對(duì) Redis 服務(wù),我們能做哪些性能
    的頭像 發(fā)表于 10-28 14:07 ?1519次閱讀

    數(shù)據(jù)庫(kù)索引使用策略優(yōu)化

    索引使用策略優(yōu)化 MySQL的優(yōu)化主要分為結(jié)構(gòu)優(yōu)化(Scheme optimization)和查詢(xún)優(yōu)化(Query optimizatio
    的頭像 發(fā)表于 11-02 15:13 ?1961次閱讀
    數(shù)據(jù)庫(kù)索引使用<b class='flag-5'>策略</b>及<b class='flag-5'>優(yōu)化</b>

    Redis 的數(shù)據(jù)清理策略

    本文整理 Redis 的數(shù)據(jù)清理策略所有代碼來(lái)自 Redis version :5.0, 不同版本的 Redis 策略可能有調(diào)整
    發(fā)表于 09-19 14:24 ?595次閱讀
    <b class='flag-5'>Redis</b> 的數(shù)據(jù)清理<b class='flag-5'>策略</b>

    Redis的刪除策略和內(nèi)存淘汰機(jī)制介紹

    Redis過(guò)期鍵的刪除策略? Redis的過(guò)期刪除策略就是:惰性刪除和定期刪除兩種策略配合使用。 惰性刪除:
    的頭像 發(fā)表于 10-09 11:06 ?696次閱讀

    redis集群性能測(cè)試工具有哪些

    Redis是一種高性能的內(nèi)存鍵值存儲(chǔ)系統(tǒng),它被廣泛應(yīng)用于各種互聯(lián)網(wǎng)應(yīng)用和大規(guī)模的數(shù)據(jù)存儲(chǔ)中。為了評(píng)估Redis在不同場(chǎng)景下的性能,我們需要使用一些
    的頭像 發(fā)表于 12-04 11:36 ?1124次閱讀

    redis的淘汰策略

    Redis是一種基于內(nèi)存的鍵值存儲(chǔ)系統(tǒng),為了充分利用內(nèi)存,Redis采用了一些淘汰策略來(lái)管理內(nèi)存空間。淘汰策略的作用是當(dāng)內(nèi)存空間不足時(shí),選擇合適的數(shù)據(jù)對(duì)象進(jìn)行淘汰,釋放出更多的內(nèi)存空間
    的頭像 發(fā)表于 12-04 16:23 ?822次閱讀

    前端性能優(yōu)化:提升用戶(hù)體驗(yàn)的關(guān)鍵策略

    在互聯(lián)網(wǎng)飛速發(fā)展的今天,用戶(hù)對(duì)于網(wǎng)頁(yè)的加載速度和響應(yīng)性能要求越來(lái)越高。前端性能優(yōu)化成為了提升用戶(hù)體驗(yàn)、增強(qiáng)網(wǎng)站競(jìng)爭(zhēng)力的關(guān)鍵策略。一個(gè)性能良好
    的頭像 發(fā)表于 01-22 10:08 ?475次閱讀

    Redis集群部署與性能優(yōu)化實(shí)戰(zhàn)

    Redis作為高性能的內(nèi)存數(shù)據(jù)庫(kù),在現(xiàn)代互聯(lián)網(wǎng)架構(gòu)中扮演著關(guān)鍵角色。作為運(yùn)維工程師,掌握Redis的部署、配置和優(yōu)化技能至關(guān)重要。本文將從實(shí)戰(zhàn)角度出發(fā),詳細(xì)介紹
    的頭像 發(fā)表于 07-08 17:56 ?29次閱讀
    主站蜘蛛池模板: 成人免费无毒在线观看网站 | 免费国产h视频在线观看 | 34pao强力打造免费永久视频 | 男女全黄做爰视频 | 国产精品久久福利网站 | 欧美综合一区二区三区 | 国产免费爽爽视频免费可以看 | 欧美tube6最新69 | 五月激激 | 日本卡一卡2卡3卡4精品卡无人区 | 夜夜爱视频| 欧美一卡二卡3卡4卡无卡六卡七卡科普 | 卡1卡2卡3精品推荐老狼 | 国产伦精品一区二区三区免 | 亚洲人色大成年网站在线观看 | 国产伦精品一区二区三区网站 | 激情网五月 | 91三级在线 | 色综合久久久久久久久久久 | 婷婷色香五月激情综合2020 | 天天色官网| 中文天堂最新版www 中文天堂最新版在线精品 中文天堂最新版在线中文 中文天堂最新版资源新版天堂资源 | 天天天干干干 | 色综合久久综合 | 国产一区二区三区在线影院 | 丁香八月婷婷 | 午夜免费啪在线观看视频网站 | 三级网站在线 | 亚洲激情视频 | 草草影院www色极品欧美 | 天天天操 | 免费黄色福利 | 国产精品免费拍拍拍 | 免费视频一级片 | 在线视频一区二区三区 | 久久精品久久久久 | 亚洲人成电影在线播放 | 免费看黄色一级毛片 | 动漫精品成人免费网站 | 五月天丁香婷婷综合 | 中国一级特黄aa毛片大片 |