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

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Redis10大性能優化策略

jf_ro2CN3Fa ? 來源:阿里開發者 ? 2023-07-04 10:21 ? 次閱讀

1.Redis真的變慢了嗎?

對 Redis 進行基準性能測試

例如,我的機器配置比較低,當延遲為 2ms 時,我就認為 Redis 變慢了,但是如果你的硬件配置比較高,那么在你的運行環境下,可能延遲是 0.5ms 時就可以認為 Redis 變慢了。

所以,你只有了解了你的 Redis 在生產環境服務器上的基準性能,才能進一步評估,當其延遲達到什么程度時,才認為 Redis 確實變慢了。

為了避免業務服務器到 Redis 服務器之間的網絡延遲,你需要直接在 Redis 服務器上測試實例的響應延遲情況。執行以下命令,就可以測試出這個實例 60 秒內的最大響應延遲:

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

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

從輸出結果可以看到,這 60 秒內的最大響應延遲為 119 微秒(0.119毫秒)。你還可以使用以下命令,查看一段時間內 Redis 的最小、最大、平均訪問延遲。

$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

如果你觀察到的 Redis 運行時延遲是其基線性能的 2 倍及以上,就可以認定 Redis 變慢了。

網絡對 Redis 性能的影響,一個簡單的方法是用 iPerf 這樣的工具測試網絡極限帶寬。

服務器端


>基于SpringBoot+MyBatisPlus+Vue&Element實現的后臺管理系統+用戶小程序,支持RBAC動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
>
>*項目地址:
>*視頻教程

#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
客戶端


>基于SpringCloudAlibaba+Gateway+Nacos+RocketMQ+Vue&Element實現的后臺管理系統+用戶小程序,支持RBAC動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
>
>*項目地址:
>*視頻教程

#iperf-c服務器端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.使用復雜度過高的命令

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

Redis 提供了慢日志命令的統計功能,它記錄了有哪些命令在執行時耗時比較久。

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

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

1)經常使用 O(N) 以上復雜度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合類命令。

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

第一種情況導致變慢的原因在于,Redis 在操作內存數據時,時間復雜度過高,要花費更多的 CPU 資源。

第二種情況導致變慢的原因在于,Redis 一次需要返回給客戶端的數據過多,更多時間花費在數據協議的組裝和網絡傳輸過程中。

另外,我們還可以從資源使用率層面來分析,如果你的應用程序操作 Redis 的 OPS 不是很大,但 Redis 實例的 CPU 使用率卻很高 ,那么很有可能是使用了復雜度過高的命令導致的。

3.操作bigkey

如果你查詢慢日志發現,并不是復雜度過高的命令導致的,而都是 SET / DEL 這種簡單命令出現在慢日志中,那么你就要懷疑你的實例否寫入了 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)

這里我需要提醒你的是,當執行這個命令時,要注意 2 個問題:

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

2)掃描結果中,對于容器類型(List、Hash、Set、ZSet)的 key,只能掃描出元素最多的 key。但一個 key 的元素多,不一定表示占用內存也多,你還需要根據業務情況,進一步評估內存占用情況。

4.集中過期

如果你發現,平時在操作 Redis 時,并沒有延遲很大的情況發生,但在某個時間點突然出現一波延時,其現象表現為:變慢的時間點很有規律,例如某個整點,或者每間隔多久就會發生一波延遲。

如果是出現這種情況,那么你需要排查一下,業務代碼中是否存在設置大量 key 集中過期的情況。

如果有大量的 key 在某個固定時間點集中過期,在這個時間點訪問 Redis 時,就有可能導致延時變大。

Redis 的過期數據采用被動過期 + 主動過期兩種策略:

1)被動過期:只有當訪問某個 key 時,才判斷這個 key 是否已過期,如果已過期,則從實例中刪除。

2)主動過期:Redis 內部維護了一個定時任務,默認每隔 100 毫秒(1秒10次)就會從全局的過期哈希表中隨機取出 20 個 key,然后刪除其中過期的 key,如果過期 key 的比例超過了 25%,則繼續重復此過程,直到過期 key 的比例下降到 25% 以下,或者這次任務的執行耗時超過了 25 毫秒,才會退出循環。

注意,這個主動過期 key 的定時任務,是在 Redis 主線程中執行的。

也就是說如果在執行主動過期的過程中,出現了需要大量刪除過期 key 的情況,那么此時應用程序在訪問 Redis 時,必須要等待這個過期任務執行結束,Redis 才可以服務這個客戶端請求。

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

因為慢日志中只記錄一個命令真正操作內存數據的耗時 ,而 Redis 主動刪除過期 key 的邏輯,是在命令真正執行之前執行的。

5.實例內存達到上限

當我們把 Redis 當做純緩存使用時,通常會給這個實例設置一個內存上限 maxmemory,然后設置一個數據淘汰策略。

當 Redis 內存達到 maxmemory 后,每次寫入新的數據之前,Redis 必須先從實例中踢出一部分數據,讓整個實例的內存維持在 maxmemory 之下 ,然后才能把新數據寫進來。

這個踢出舊數據的邏輯也是需要消耗時間的,而具體耗時的長短,要取決于你配置的淘汰策略:

allkeys-lru:不管 key 是否設置了過期,淘汰最近最少訪問的 key

volatile-lru:只淘汰最近最少訪問、并設置了過期時間的 key

allkeys-random:不管 key 是否設置了過期,隨機淘汰 key

volatile-random:只隨機淘汰設置了過期時間的 key

allkeys-ttl:不管 key 是否設置了過期,淘汰即將過期的 key

noeviction:不淘汰任何 key,實例內存達到 maxmeory 后,再寫入新數據直接返回錯誤

allkeys-lfu:不管 key 是否設置了過期,淘汰訪問頻率最低的 key(4.0+版本支持)

volatile-lfu:只淘汰訪問頻率最低、并設置了過期時間 key(4.0+版本支持)

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

需要注意的是,Redis 的淘汰數據的邏輯與刪除過期 key 的一樣,也是在命令真正執行之前執行的,也就是說它也會增加我們操作 Redis 的延遲,而且,寫 OPS 越高,延遲也會越明顯。

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

如果此時你的 Redis 實例中還存儲了 bigkey,那么在淘汰刪除 bigkey 釋放內存時 ,也會耗時比較久。

6.fork耗時嚴重

當 Redis 開啟了后臺 RDB 和 AOF rewrite 后,在執行時,它們都需要主進程創建出一個子進程進行數據的持久化。

主進程創建子進程,會調用操作系統提供的 fork 函數。

而 fork 在執行過程中,主進程需要拷貝自己的內存頁表給子進程 ,如果這個實例很大,那么這個拷貝的過程也會比較耗時。

而且這個 fork 過程會消耗大量的 CPU 資源,在完成 fork 之前,整個 Redis 實例會被阻塞住,無法處理任何客戶端請求。

如果此時你的 CPU 資源本來就很緊張,那么 fork 的耗時會更長,甚至達到秒級,這會嚴重影響 Redis 的性能。

那如何確認確實是因為 fork 耗時導致的 Redis 延遲變大呢?

你可以在 Redis 上執行 INFO 命令,查看 latest_fork_usec 項,單位微秒。

#上一次fork耗時,單位微秒
latest_fork_usec:59477

這個時間就是主進程在 fork 子進程期間,整個實例阻塞無法處理客戶端請求的時間。

如果你發現這個耗時很久,就要警惕起來了,這意味在這期間,你的整個 Redis 實例都處于不可用的狀態。

除了數據持久化會生成 RDB 之外,當主從節點第一次建立數據同步時,主節點也創建子進程生成 RDB,然后發給從節點進行一次全量同步,所以,這個過程也會對 Redis 產生性能影響。

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

7.開啟內存大頁

除了上面講到的子進程 RDB 和 AOF rewrite 期間,fork 耗時導致的延時變大之外,這里還有一個方面也會導致性能問題,這就是操作系統是否開啟了內存大頁機制 。

什么是內存大頁?

我們都知道,應用程序向操作系統申請內存時,是按內存頁 進行申請的,而常規的內存頁大小是 4KB。

Linux 內核從 2.6.38 開始,支持了內存大頁機制 ,該機制允許應用程序以 2MB 大小為單位,向操作系統申請內存。

應用程序每次向操作系統申請的內存單位變大了,但這也意味著申請內存的耗時變長。

這對 Redis 會有什么影響呢?

當 Redis 在執行后臺 RDB,采用 fork 子進程的方式來處理。但主進程 fork 子進程后,此時的主進程依舊是可以接收寫請求 的,而進來的寫請求,會采用 Copy On Write(寫時復制)的方式操作內存數據。

也就是說,主進程一旦有數據需要修改,Redis 并不會直接修改現有內存中的數據,而是先將這塊內存數據拷貝出來,再修改這塊新內存的數據 ,這就是所謂的「寫時復制」。

寫時復制你也可以理解成,誰需要發生寫操作,誰就需要先拷貝,再修改。

這樣做的好處是,父進程有任何寫操作,并不會影響子進程的數據持久化(子進程只持久化 fork 這一瞬間整個實例中的所有數據即可,不關心新的數據變更,因為子進程只需要一份內存快照,然后持久化到磁盤上)。

但是請注意,主進程在拷貝內存數據時,這個階段就涉及到新內存的申請,如果此時操作系統開啟了內存大頁,那么在此期間,客戶端即便只修改 10B 的數據,Redis 在申請內存時也會以 2MB 為單位向操作系統申請,申請內存的耗時變長,進而導致每個寫請求的延遲增加,影響到 Redis 性能。

同樣地,如果這個寫請求操作的是一個 bigkey,那主進程在拷貝這個 bigkey 內存塊時,一次申請的內存會更大,時間也會更久??梢?,bigkey 在這里又一次影響到了性能。

8.開啟AOF

前面我們分析了 RDB 和 AOF rewrite 對 Redis 性能的影響,主要關注點在 fork 上。

其實,關于數據持久化方面,還有影響 Redis 性能的因素,這次我們重點來看 AOF 數據持久化。

如果你的 AOF 配置不合理,還是有可能會導致性能問題。

當 Redis 開啟 AOF 后,其工作原理如下:

1)Redis 執行寫命令后,把這個命令寫入到 AOF 文件內存中(write 系統調用)

2)Redis 根據配置的 AOF 刷盤策略,把 AOF 內存數據刷到磁盤上(fsync 系統調用)

為了保證 AOF 文件數據的安全性,Redis 提供了 3 種刷盤機制:

1)appendfsync always:主線程每次執行寫操作后立即刷盤,此方案會占用比較大的磁盤 IO 資源,但數據安全性最高。

2)appendfsync no:主線程每次寫操作只寫內存就返回,內存數據什么時候刷到磁盤,交由操作系統決定,此方案對性能影響最小,但數據安全性也最低,Redis 宕機時丟失的數據取決于操作系統刷盤時機。

3)appendfsync everysec:主線程每次寫操作只寫內存就返回,然后由后臺線程每隔 1 秒執行一次刷盤操作(觸發fsync系統調用),此方案對性能影響相對較小,但當 Redis 宕機時會丟失 1 秒的數據。

看到這里,我猜你肯定和大多數人的想法一樣,選比較折中的方案 appendfsync everysec 就沒問題了吧?

這個方案優勢在于,Redis 主線程寫完內存后就返回,具體的刷盤操作是放到后臺線程中執行的,后臺線程每隔 1 秒把內存中的數據刷到磁盤中。

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

但是,這里我要給你潑一盆冷水了,采用這種方案你也要警惕一下,因為這種方案還是存在導致 Redis 延遲變大的情況發生,甚至會阻塞整個 Redis。

你試想這樣一種情況:當 Redis 后臺線程在執行 AOF 文件刷盤時,如果此時磁盤的 IO 負載很高,那這個后臺線程在執行刷盤操作(fsync系統調用)時就會被阻塞住。

此時的主線程依舊會接收寫請求,緊接著,主線程又需要把數據寫到文件內存中(write 系統調用),當主線程使用后臺子線程執行了一次 fsync,需要再次把新接收的操作記錄寫回磁盤時,如果主線程發現上一次的 fsync 還沒有執行完,那么它就會阻塞。

所以,如果后臺子線程執行的 fsync 頻繁阻塞的話(比如 AOF 重寫占用了大量的磁盤 IO 帶寬),主線程也會阻塞,導致 Redis 性能變慢。

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

看到了么?在這個過程中,主線程依舊有阻塞的風險。

所以,盡管你的 AOF 配置為 appendfsync everysec,也不能掉以輕心,要警惕磁盤壓力過大導致的 Redis 有性能問題。

那什么情況下會導致磁盤 IO 負載過大?以及如何解決這個問題呢?

我總結了以下幾種情況,你可以參考進行問題排查:

1)進程正在執行 AOF rewrite,這個過程會占用大量的磁盤 IO 資源

2)有其他應用程序在執行大量的寫文件操作,也會占用磁盤 IO 資源

對于情況1,說白了就是,Redis 的 AOF 后臺子線程刷盤操作,撞上了子進程 AOF rewrite!

9.綁定CPU

很多時候,我們在部署服務時,為了提高服務性能,降低應用程序在多個 CPU 核心之間的上下文切換帶來的性能損耗,通常采用的方案是進程綁定 CPU 的方式提高性能。

我們都知道,一般現代的服務器會有多個 CPU,而每個 CPU 又包含多個物理核心,每個物理核心又分為多個邏輯核心,每個物理核下的邏輯核共用 L1/L2 Cache。

而 Redis Server 除了主線程服務客戶端請求之外,還會創建子進程、子線程。

其中子進程用于數據持久化,而子線程用于執行一些比較耗時操作,例如異步釋放 fd、異步 AOF 刷盤、異步 lazy-free 等等。

如果你把 Redis 進程只綁定了一個 CPU 邏輯核心上,那么當 Redis 在進行數據持久化時,fork 出的子進程會繼承父進程的 CPU 使用偏好。

而此時的子進程會消耗大量的 CPU 資源進行數據持久化(把實例數據全部掃描出來需要耗費CPU),這就會導致子進程會與主進程發生 CPU 爭搶,進而影響到主進程服務客戶端請求,訪問延遲變大。

這就是 Redis 綁定 CPU 帶來的性能問題。

10.使用Swap

如果你發現 Redis 突然變得非常慢,每次的操作耗時都達到了幾百毫秒甚至秒級,那此時你就需要檢查 Redis 是否使用到了 Swap,在這種情況下 Redis 基本上已經無法提供高性能的服務了。

什么是 Swap?為什么使用 Swap 會導致 Redis 的性能下降?

如果你對操作系統有些了解,就會知道操作系統為了緩解內存不足對應用程序的影響,允許把一部分內存中的數據換到磁盤上,以達到應用程序對內存使用的緩沖,這些內存數據被換到磁盤上的區域,就是 Swap。

問題就在于,當內存中的數據被換到磁盤上后,Redis 再訪問這些數據時,就需要從磁盤上讀取,訪問磁盤的速度要比訪問內存慢幾百倍!

尤其是針對 Redis 這種對性能要求極高、性能極其敏感的數據庫來說,這個操作延時是無法接受的。

此時,你需要檢查 Redis 機器的內存使用情況,確認是否存在使用了 Swap。

你可以通過以下方式來查看 Redis 進程是否使用到了 Swap:

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

輸出結果如下:

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 所用的一塊內存大小,Size 下面的 Swap 就表示這塊 Size 大小的內存,有多少數據已經被換到磁盤上了,如果這兩個值相等,說明這塊內存的數據都已經完全被換到磁盤上了。

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

11.碎片整理

Redis 的數據都存儲在內存中,當我們的應用程序頻繁修改 Redis 中的數據時,就有可能會導致 Redis 產生內存碎片。

內存碎片會降低 Redis 的內存使用率,我們可以通過執行 INFO 命令,得到這個實例的內存碎片率:

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

這個內存碎片率是怎么計算的?

很簡單,mem_fragmentation_ratio = used_memory_rss / used_memory。

其中 used_memory 表示 Redis 存儲數據的內存大小,而 used_memory_rss 表示操作系統實際分配給 Redis 進程的大小。

如果 mem_fragmentation_ratio > 1.5,說明內存碎片率已經超過了 50%,這時我們就需要采取一些措施來降低內存碎片了。

解決的方案一般如下:

1)如果你使用的是 Redis 4.0 以下版本,只能通過重啟實例來解決

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

但是,開啟內存碎片整理,它也有可能會導致 Redis 性能下降。

原因在于,Redis 的碎片整理工作是也在主線程 中執行的,當其進行碎片整理時,必然會消耗 CPU 資源,產生更多的耗時,從而影響到客戶端的請求。

所以,當你需要開啟這個功能時,最好提前測試評估它對 Redis 的影響。

Redis 碎片整理的參數配置如下:

#開啟自動內存碎片整理(總開關)
activedefragyes

#內存使用100MB以下,不進行碎片整理
active-defrag-ignore-bytes100mb

#內存碎片率超過10%,開始碎片整理
active-defrag-threshold-lower10
#內存碎片率超過100%,盡最大努力碎片整理
active-defrag-threshold-upper100

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

#碎片整理期間,對于List/Set/Hash/ZSet類型元素一次Scan的數量
active-defrag-max-scan-fields1000

二、Redis如何優化

1.慢查詢優化

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

2)執行 O(N) 命令,保證 N 盡量的小(推薦 N <= 300),每次獲取盡量少的數據,讓 Redis 可以及時處理返回。

2.集中過期優化

一般有兩種方案來規避這個問題:

1.集中過期 key 增加一個隨機過期時間,把集中過期的時間打散,降低 Redis 清理過期 key 的壓力

2.如果你使用的 Redis 是 4.0 以上版本,可以開啟 lazy-free 機制,當刪除過期 key 時,把釋放內存的操作放到后臺線程中執行,避免阻塞主線程。

第一種方案,在設置 key 的過期時間時,增加一個隨機時間,偽代碼可以這么寫:

#在過期時間點之后的5分鐘內隨機過期掉
redis.expireat(key,expire_time+random(300))

第二種方案,Redis 4.0 以上版本,開啟 lazy-free 機制:

#釋放過期key的內存,放到后臺線程執行
lazyfree-lazy-expireyes

運維層面,你需要把 Redis 的各項運行狀態數據監控起來,在 Redis 上執行 INFO 命令就可以拿到這個實例所有的運行狀態數據。

在這里我們需要重點關注 expired_keys 這一項 ,它代表整個實例到目前為止,累計刪除過期 key 的數量。

你需要把這個指標監控起來,當這個指標在很短時間內出現了突增,需要及時報警出來,然后與業務應用報慢的時間點進行對比分析,確認時間是否一致,如果一致,則可以確認確實是因為集中過期 key 導致的延遲變大。

3.實例內存達到上限優化

1)避免存儲 bigkey,降低釋放內存的耗時

2)淘汰策略改為隨機淘汰,隨機淘汰比 LRU 要快很多(視業務情況調整)

3)拆分實例,把淘汰 key 的壓力分攤到多個實例上

4)如果使用的是 Redis 4.0 以上版本,開啟 layz-free 機制,把淘汰 key 釋放內存的操作放到后臺線程中執行(配置 lazyfree-lazy-eviction = yes)

4.fork耗時嚴重優化

1)控制 Redis 實例的內存:盡量在 10G 以下,執行 fork 的耗時與實例大小有關,實例越大,耗時越久。

2)合理配置數據持久化策略:在 slave 節點執行 RDB 備份,推薦在低峰期執行,而對于丟失數據不敏感的業務(例如把 Redis 當做純緩存使用),可以關閉 AOF 和 AOF rewrite。

3)Redis 實例不要部署在虛擬機上:fork 的耗時也與系統也有關,虛擬機比物理機耗時更久。

4)降低主從庫全量同步的概率:適當調大 repl-backlog-size 參數,避免主從全量同步。

從建立同步時,優先檢測是否可以嘗試只同步部分數據,這種情況就是針對于之前已經建立好了復制鏈路,只是因為故障導致臨時斷開,故障恢復后重新建立同步時,為了避免全量同步的資源消耗,Redis會優先嘗試部分數據同步,如果條件不符合,才會觸發全量同步。

這個判斷依據就是在master上維護的復制緩沖區大小,如果這個緩沖區配置的過小,很有可能在主從斷開復制的這段時間內,master產生的寫入導致復制緩沖區的數據被覆蓋,重新建立同步時的slave需要同步的offset位置在master的緩沖區中找不到,那么此時就會觸發全量同步。

如何避免這種情況?解決方案就是適當調大復制緩沖區repl-backlog-size的大小,這個緩沖區的大小默認為1MB,如果實例寫入量比較大,可以針對性調大此配置。

5.多核CPU優化

那如何解決這個問題呢?

如果你確實想要綁定 CPU,可以優化的方案是,不要讓 Redis 進程只綁定在一個 CPU 邏輯核上,而是綁定在多個邏輯核心上,而且,綁定的多個邏輯核心最好是同一個物理核心,這樣它們還可以共用 L1/L2 Cache。

當然,即便我們把 Redis 綁定在多個邏輯核心上,也只能在一定程度上緩解主線程、子進程、后臺線程在 CPU 資源上的競爭。

因為這些子進程、子線程還是會在這多個邏輯核心上進行切換,存在性能損耗。

如何再進一步優化?

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

其實,這個方案 Redis 官方已經想到了。

Redis 在 6.0 版本已經推出了這個功能,我們可以通過以下配置,對主線程、后臺線程、后臺 RDB 進程、AOF rewrite 進程,綁定固定的 CPU 邏輯核心:

Redis6.0 前綁定CPU核

taskset-c0./redis-server

Redis6.0 后綁定CPU核

#RedisServer和IO線程綁定到CPU核心0,2,4,6
server_cpulist0-7:2
#后臺子線程綁定到CPU核心1,3
bio_cpulist1,3
#后臺AOFrewrite進程綁定到CPU核心8,9,10,11
aof_rewrite_cpulist8-11
#后臺RDB進程綁定到CPU核心1,10,11
#bgsave_cpulist1,10-1

如果你使用的正好是 Redis 6.0 版本,就可以通過以上配置,來進一步提高 Redis 性能。

這里我需要提醒你的是,一般來說,Redis 的性能已經足夠優秀,除非你對 Redis 的性能有更加嚴苛的要求,否則不建議你綁定 CPU。

6.查看Redis內存是否發生Swap

$redis-cliinfo|grepprocess_id
process_id:5332

然后,進入 Redis 所在機器的 /proc 目錄下的該進程目錄中:

$cd/proc/5332

最后,運行下面的命令,查看該 Redis 進程的使用情況。在這兒,我只截取了部分結果:

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

一旦發生內存 swap,最直接的解決方法就是增加機器內存。如果該實例在一個 Redis 切片集群中,可以增加 Redis 集群的實例個數,來分攤每個實例服務的數據量,進而減少每個實例所需的內存量。

7.內存大頁

如果采用了內存大頁,那么,即使客戶端請求只修改 100B 的數據,Redis 也需要拷貝 2MB 的大頁。相反,如果是常規內存頁機制,只用拷貝 4KB。兩者相比,你可以看到,當客戶端請求修改或新寫入數據較多時,內存大頁機制將導致大量的拷貝,這就會影響 Redis 正常的訪存操作,最終導致性能變慢。

首先,我們要先排查下內存大頁。方法是:在 Redis 實例運行的機器上執行如下命令:

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

如果執行結果是 always,就表明內存大頁機制被啟動了;如果是 never,就表示,內存大頁機制被禁止。

在實際生產環境中部署時,我建議你不要使用內存大頁機制 ,操作也很簡單,只需要執行下面的命令就可以了:

echonever/sys/kernel/mm/transparent_hugepage/enabled

其實,操作系統提供的內存大頁機制,其優勢是,可以在一定程序上降低應用程序申請內存的次數。

但是對于 Redis 這種對性能和延遲極其敏感的數據庫來說,我們希望 Redis 在每次申請內存時,耗時盡量短,所以我不建議你在 Redis 機器上開啟這個機制。

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

支持版本:Redis 4.0+

1)主動刪除鍵使用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命令,還是并發阻塞的刪除操作

FLUSHALL/FLUSHDB ASYNC

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

2)被動刪除鍵使用lazy free

lazy free應用于被動刪除中,目前有4種場景,每種場景對應一個配置參數;默認都是關閉。

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

lazyfree-lazy-eviction

針對redis內存使用達到maxmeory,并設置有淘汰策略時;在被動淘汰鍵時,是否采用lazy free機制;因為此場景開啟lazy free, 可能使用淘汰鍵的內存釋放不及時,導致redis內存超用,超過maxmemory的限制。此場景使用時,請結合業務測試。(生產環境不建議設置yes)

lazyfree-lazy-expire

針對設置有TTL的鍵,達到過期后,被redis清理刪除時是否采用lazy free機制;此場景建議開啟,因TTL本身是自適應調整的速度。

lazyfree-lazy-server-del

針對有些指令在處理已存在的鍵時,會帶有一個隱式的DEL鍵的操作。如rename命令,當目標鍵已存在,redis會先刪除目標鍵,如果這些目標鍵是一個big key,那就會引入阻塞刪除的性能問題。此參數設置就是解決這類問題,建議可開啟。

slave-lazy-flush

針對slave進行全量數據同步,slave在加載master的RDB文件前,會運行flushall來清理自己的數據場景, 參數設置決定是否采用異常flush機制。如果內存變動不大,建議可開啟??蓽p少全量同步耗時,從而減少主庫因輸出緩沖區爆漲引起的內存使用增長。

3)lazy free的監控

lazy free能監控的數據指標,只有一個值:lazyfree_pending_objects,表示redis執行lazy free操作,在等待被實際回收內容的鍵個數。并不能體現單個大鍵的元素個數或等待lazy free回收的內存大小。所以此值有一定參考值,可監測redis lazy free的效率或堆積鍵數量;比如在flushall async場景下會有少量的堆積。

#infomemory

#Memory
lazyfree_pending_objects:0

注意事項 :unlink命令入口函數unlinkCommand()和del調用相同函數delGenericCommand()進行刪除KEY操作,使用lazy標識是否為lazyfree調用。如果是lazyfree,則調用dbAsyncDelete()函數。

但并非每次unlink命令就一定啟用lazy free,redis會先判斷釋放KEY的代價(cost),當cost大于LAZYFREE_THRESHOLD(64)才進行lazy free.

釋放key代價計算函數lazyfreeGetFreeEffort(),集合類型鍵,且滿足對應編碼,cost就是集合鍵的元數個數,否則cost就是1。

舉例:

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

一個512MB的string key, 它的free cost是1 所以可以看出,redis的lazy free的cost計算主要時間復雜度相關。

9.AOF優化

Redis 提供了一個配置項,當子進程在 AOF rewrite 期間,可以讓后臺子線程不執行刷盤(不觸發 fsync 系統調用)操作。

這相當于在 AOF rewrite 期間,臨時把 appendfsync 設置為了 none,配置如下:

#AOFrewrite期間,AOF后臺子線程不進行刷盤操作
#相當于在這期間,臨時把appendfsync設置為了none
no-appendfsync-on-rewriteyes

當然,開啟這個配置項,在 AOF rewrite 期間,如果實例發生宕機,那么此時會丟失更多的數據,性能和數據安全性,你需要權衡后進行選擇。

如果占用磁盤資源的是其他應用程序,那就比較簡單了,你需要定位到是哪個應用程序在大量寫磁盤,然后把這個應用程序遷移到其他機器上執行就好了,避免對 Redis 產生影響。

當然,如果你對 Redis 的性能和數據安全都有很高的要求,那么建議從硬件層面來優化 ,更換為 SSD 磁盤,提高磁盤的 IO 能力,保證 AOF 期間有充足的磁盤資源可以使用。同時盡可能讓Redis運行在獨立的機器上。

10.Swap優化

1)增加機器的內存,讓 Redis 有足夠的內存可以使用

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

釋放 Redis 的 Swap 過程通常要重啟實例,為了避免重啟實例對業務的影響,一般會先進行主從切換,然后釋放舊主節點的 Swap,重啟舊主節點實例,待從庫數據同步完成后,再進行主從切換即可。

預防的辦法就是,你需要對 Redis 機器的內存和 Swap 使用情況進行監控,在內存不足或使用到 Swap 時報警出來,及時處理。

三、Redis變慢了排查步驟

1.獲取 Redis 實例在當前環境下的基線性能。

2.是否用了慢查詢命令?如果是的話,就使用其他命令替代慢查詢命令,或者把聚合計算命令放在客戶端做。

3.是否對過期 key 設置了相同的過期時間?對于批量刪除的 key,可以在每個 key 的過期時間上加一個隨機數,避免同時刪除。

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

5.Redis AOF 配置級別是什么?業務層面是否的確需要這一可靠性級別?如果我們需要高性能,同時也允許數據丟失,可以將配置項 no-appendfsync-on-rewrite 設置為 yes,避免 AOF 重寫和 fsync 競爭磁盤 IO 資源,導致 Redis 延遲增加。當然, 如果既需要高性能又需要高可靠性,最好使用高速固態盤作為 AOF 日志的寫入盤。

6.Redis 實例的內存使用是否過大?發生 swap 了嗎?如果是的話,就增加機器內存,或者是使用 Redis 集群,分攤單機 Redis 的鍵值對數量和內存壓力。同時,要避免出現 Redis 和其他內存需求大的應用共享機器的情況。

7.在 Redis 實例的運行環境中,是否啟用了透明大頁機制?如果是的話,直接關閉內存大頁機制就行了。

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

9.是否使用了多核 CPU 或 NUMA 架構的機器運行 Redis 實例?使用多核 CPU 時,可以給 Redis 實例綁定物理核;使用 NUMA 架構時,注意把 Redis 實例和網絡中斷處理程序運行在同一個 CPU Socket 上。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10698

    瀏覽量

    209328
  • 服務器
    +關注

    關注

    12

    文章

    8700

    瀏覽量

    84528
  • 內存
    +關注

    關注

    8

    文章

    2902

    瀏覽量

    73534
  • Redis
    +關注

    關注

    0

    文章

    368

    瀏覽量

    10780

原文標題:Redis10大性能優化策略

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    如何排查Redis性能問題 Redis內部實現原理解析

    作為業務開發人員,我們需要了解 Redis 的基本原理,例如各個命令執行的時間復雜度、數據過期策略、數據淘汰策略等,從而更合理地使用 Redis 命令,并且結合業務場景進行
    發表于 07-05 12:33 ?296次閱讀
    如何排查<b class='flag-5'>Redis</b><b class='flag-5'>性能</b>問題 <b class='flag-5'>Redis</b>內部實現原理解析

    用vivado HLS優化設計大規模矩陣相乘,求詳細具體的優化策略

    設計一個高性能的HLS, 可以用任何優化策略,在保持函數功能的同時盡可能提高性能。希望論壇里的大神給予具體優化的指導,最近幾天調試太費勁了,
    發表于 08-27 21:11

    Linux系統的性能優化策略

    近年來,世界上許多大軟件公司紛紛推出各種Linux服務器系統及Linux下的應用軟件。目前,Linux 已可以與各種傳統的商業操作系統分庭抗禮,在服務器市場,占據了相當大的份額。本文分別從磁盤調優,文件系統,內存管理以及編譯優化等方面來論述 Linux系統的優化調優
    發表于 07-16 06:23

    Redis的內存淘汰機制

    redis淘汰策略
    發表于 09-27 07:55

    淺析Redis的過期機制

    Redis數據過期策略詳解
    發表于 10-12 15:12

    FPGA設計應用及優化策略有哪些?

    EDA技術具有什么特征?FPGA是什么原理?FPGA設計應用及優化策略基于VHDL的FPGA系統行為級設計
    發表于 04-15 06:33

    全面分析Redis的最佳實踐優化

    這篇文章我想和你聊一聊 Redis 的最佳實踐。 你的項目或許已經使用 Redis 很長時間了,但在使用過程中,你可能還會或多或少地遇到以下問題: 我的 Redis 內存為什么增長這么快? 為什么我
    的頭像 發表于 04-26 10:51 ?1782次閱讀

    探究Redis 性能測試與監控

    很多人在安裝部署好Redis后,就沒有對Rredis的配置和部署等有效性和高可用性進行性能測試,最終導致上線出現緩存穿透、雪崩等現象,導致性能還是有問題,其實做為技術運維人員在部署好Redis
    的頭像 發表于 10-12 09:19 ?1361次閱讀
    探究<b class='flag-5'>Redis</b> <b class='flag-5'>性能</b>測試與監控

    針對Redis服務我們應該避免哪些性能浪費

    ],最新的用戶關系[2],都存儲在 Redis 中,大量的查詢擊中 Redis,而不走 MySQL。 那么,針對 Redis 服務,我們能做哪些性能
    的頭像 發表于 10-28 14:07 ?1270次閱讀

    數據庫索引使用策略優化

    索引使用策略優化 MySQL的優化主要分為結構優化(Scheme optimization)和查詢優化(Query optimizatio
    的頭像 發表于 11-02 15:13 ?1604次閱讀
    數據庫索引使用<b class='flag-5'>策略</b>及<b class='flag-5'>優化</b>

    Redis 的數據清理策略

    本文整理 Redis 的數據清理策略所有代碼來自 Redis version :5.0, 不同版本的 Redis 策略可能有調整
    發表于 09-19 14:24 ?305次閱讀
    <b class='flag-5'>Redis</b> 的數據清理<b class='flag-5'>策略</b>

    Redis的刪除策略和內存淘汰機制介紹

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

    redis連接數對性能測試影響

    Redis是一個基于內存的鍵值存儲數據庫,它以其高性能和低延遲而聞名。在使用Redis進行性能測試時,連接數是一個非常重要的因素。連接數的增加或減少會直接影響
    的頭像 發表于 12-04 11:33 ?808次閱讀

    redis集群性能測試工具有哪些

    Redis是一種高性能的內存鍵值存儲系統,它被廣泛應用于各種互聯網應用和大規模的數據存儲中。為了評估Redis在不同場景下的性能,我們需要使用一些
    的頭像 發表于 12-04 11:36 ?601次閱讀

    redis的淘汰策略

    Redis是一種基于內存的鍵值存儲系統,為了充分利用內存,Redis采用了一些淘汰策略來管理內存空間。淘汰策略的作用是當內存空間不足時,選擇合適的數據對象進行淘汰,釋放出更多的內存空間
    的頭像 發表于 12-04 16:23 ?456次閱讀