成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么我的Redis這么“慢”?

存儲 存儲軟件 Redis
Redis 作為內(nèi)存數(shù)據(jù)庫,擁有非常高的性能,單個實(shí)例的 QPS 能夠達(dá)到 10W 左右。

 Redis 作為內(nèi)存數(shù)據(jù)庫,擁有非常高的性能,單個實(shí)例的 QPS 能夠達(dá)到 10W 左右。

[[337766]]

 

圖片來自 Pexels

但我們在使用 Redis 時,經(jīng)常時不時會出現(xiàn)訪問延遲很大的情況,如果你不知道 Redis 的內(nèi)部實(shí)現(xiàn)原理,在排查問題時就會一頭霧水。

很多時候,Redis 出現(xiàn)訪問延遲變大,都與我們的使用不當(dāng)或運(yùn)維不合理導(dǎo)致的。

這篇文章我們就來分析一下 Redis 在使用過程中,經(jīng)常會遇到的延遲問題以及如何定位和分析。

使用復(fù)雜度高的命令

如果在使用 Redis 時,發(fā)現(xiàn)訪問延遲突然增大,如何進(jìn)行排查?

首先,第一步,建議你去查看一下 Redis 的慢日志。Redis 提供了慢日志命令的統(tǒng)計(jì)功能,我們通過以下設(shè)置,就可以查看有哪些命令在執(zhí)行時延遲比較大。

首先設(shè)置 Redis 的慢日志閾值,只有超過閾值的命令才會被記錄,這里的單位是微秒。

例如設(shè)置慢日志的閾值為 5 毫秒,同時設(shè)置只保留最近 1000 條慢日志記錄:

  1. # 命令執(zhí)行超過5毫秒記錄慢日志 
  2. CONFIG SET slowlog-log-slower-than 5000 
  3. # 只保留最近1000條慢日志 
  4. CONFIG SET slowlog-max-len 1000 

設(shè)置完成之后,所有執(zhí)行的命令如果延遲大于 5 毫秒,都會被 Redis 記錄下來,我們執(zhí)行 SLOWLOG get 5 查詢最近 5 條慢日志:

  1. 127.0.0.1:6379> SLOWLOG get 5 
  2. 1) 1) (integer) 32693       # 慢日志ID 
  3.    2) (integer) 1593763337  # 執(zhí)行時間 
  4.    3) (integer) 5299        # 執(zhí)行耗時(微妙) 
  5.    4) 1) "LRANGE"           # 具體執(zhí)行的命令和參數(shù) 
  6.       2) "user_list_2000" 
  7.       3) "0" 
  8.       4) "-1" 
  9. 2) 1) (integer) 32692 
  10.    2) (integer) 1593763337 
  11.    3) (integer) 5044 
  12.    4) 1) "GET" 
  13.       2) "book_price_1000" 
  14. ... 

通過查看慢日志記錄,我們就可以知道在什么時間執(zhí)行哪些命令比較耗時,如果你的業(yè)務(wù)經(jīng)常使用 O(n) 以上復(fù)雜度的命令。

例如 sort、sunion、zunionstore,或者在執(zhí)行 O(n) 命令時操作的數(shù)據(jù)量比較大,這些情況下 Redis 處理數(shù)據(jù)時就會很耗時。

如果你的服務(wù)請求量并不大,但 Redis 實(shí)例的 CPU 使用率很高,很有可能是使用了復(fù)雜度高的命令導(dǎo)致的。

解決方案就是,不使用這些復(fù)雜度較高的命令,并且一次不要獲取太多的數(shù)據(jù),每次盡量操作少量的數(shù)據(jù),讓 Redis 可以及時處理返回。

存儲大 Key

如果查詢慢日志發(fā)現(xiàn),并不是復(fù)雜度較高的命令導(dǎo)致的,例如都是 SET、DELETE 操作出現(xiàn)在慢日志記錄中,那么你就要懷疑是否存在 Redis 寫入了大 Key 的情況。

Redis 在寫入數(shù)據(jù)時,需要為新的數(shù)據(jù)分配內(nèi)存,當(dāng)從 Redis 中刪除數(shù)據(jù)時,它會釋放對應(yīng)的內(nèi)存空間。

如果一個 Key 寫入的數(shù)據(jù)非常大,Redis 在分配內(nèi)存時也會比較耗時。同樣的,當(dāng)刪除這個 Key 的數(shù)據(jù)時,釋放內(nèi)存也會耗時比較久。

你需要檢查你的業(yè)務(wù)代碼,是否存在寫入大 Key 的情況,需要評估寫入數(shù)據(jù)量的大小,業(yè)務(wù)層應(yīng)該避免一個 Key 存入過大的數(shù)據(jù)量。

那么有沒有什么辦法可以掃描現(xiàn)在 Redis 中是否存在大 Key 的數(shù)據(jù)嗎?

Redis 也提供了掃描大 Key 的方法:

  1. redis-cli -h $host -p $port --bigkeys -i 0.01 

使用上面的命令就可以掃描出整個實(shí)例 Key 大小的分布情況,它是以類型維度來展示的。

需要注意的是當(dāng)我們在線上實(shí)例進(jìn)行大 Key 掃描時,Redis 的 QPS 會突增,為了降低掃描過程中對 Redis 的影響,我們需要控制掃描的頻率,使用 -i 參數(shù)控制即可,它表示掃描過程中每次掃描的時間間隔,單位是秒。

使用這個命令的原理,其實(shí)就是 Redis 在內(nèi)部執(zhí)行 Scan 命令,遍歷所有 Key。

然后針對不同類型的 Key 執(zhí)行 strlen、llen、hlen、scard、zcard 來獲取字符串的長度以及容器類型(list/dict/set/zset)的元素個數(shù)。

而對于容器類型的 Key,只能掃描出元素最多的 Key,但元素最多的 Key 不一定占用內(nèi)存最多,這一點(diǎn)需要我們注意下。

不過使用這個命令一般我們是可以對整個實(shí)例中 Key 的分布情況有比較清晰的了解。

針對大 Key 的問題,Redis 官方在 4.0 版本推出了 lazy-free 的機(jī)制,用于異步釋放大 Key 的內(nèi)存,降低對 Redis 性能的影響。

即使這樣,我們也不建議使用大 Key,大 Key 在集群的遷移過程中,也會影響到遷移的性能,這個后面在介紹集群相關(guān)的文章時,會再詳細(xì)介紹到。

集中過期

有時你會發(fā)現(xiàn),平時在使用 Redis 時沒有延時比較大的情況,但在某個時間點(diǎn)突然出現(xiàn)一波延時,而且報慢的時間點(diǎn)很有規(guī)律,例如某個整點(diǎn),或者間隔多久就會發(fā)生一次。

如果出現(xiàn)這種情況,就需要考慮是否存在大量 Key 集中過期的情況。

如果有大量的 Key 在某個固定時間點(diǎn)集中過期,在這個時間點(diǎn)訪問 Redis 時,就有可能導(dǎo)致延遲增加。

Redis 的過期策略采用主動過期+懶惰過期兩種策略:

  • 主動過期:Redis 內(nèi)部維護(hù)一個定時任務(wù),默認(rèn)每隔 100 毫秒會從過期字典中隨機(jī)取出 20 個 Key,刪除過期的 Key。

如果過期 Key 的比例超過了 25%,則繼續(xù)獲取 20 個 Key,刪除過期的 Key,循環(huán)往復(fù),直到過期 Key 的比例下降到 25% 或者這次任務(wù)的執(zhí)行耗時超過了 25 毫秒,才會退出循環(huán)。

  • 懶惰過期:只有當(dāng)訪問某個 Key 時,才判斷這個 Key 是否已過期,如果已經(jīng)過期,則從實(shí)例中刪除。

注意,Redis 的主動過期的定時任務(wù),也是在 Redis 主線程中執(zhí)行的,也就是說如果在執(zhí)行主動過期的過程中,出現(xiàn)了需要大量刪除過期 Key 的情況。

那么在業(yè)務(wù)訪問時,必須等這個過期任務(wù)執(zhí)行結(jié)束,才可以處理業(yè)務(wù)請求。此時就會出現(xiàn),業(yè)務(wù)訪問延時增大的問題,最大延遲為 25 毫秒。

而且這個訪問延遲的情況,不會記錄在慢日志里。慢日志中只記錄真正執(zhí)行某個命令的耗時,Redis 主動過期策略執(zhí)行在操作命令之前。

如果操作命令耗時達(dá)不到慢日志閾值,它是不會計(jì)算在慢日志統(tǒng)計(jì)中的,但我們的業(yè)務(wù)卻感到了延遲增大。

此時你需要檢查你的業(yè)務(wù),是否真的存在集中過期的代碼,一般集中過期使用的命令是 expireat 或 pexpireat 命令,在代碼中搜索這個關(guān)鍵字就可以了。

如果你的業(yè)務(wù)確實(shí)需要集中過期掉某些 Key,又不想導(dǎo)致 Redis 發(fā)生抖動,有什么優(yōu)化方案?

解決方案是,在集中過期時增加一個隨機(jī)時間,把這些需要過期的 Key 的時間打散即可。

偽代碼可以這么寫:

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

這樣 Redis 在處理過期時,不會因?yàn)榧袆h除 Key 導(dǎo)致壓力過大,阻塞主線程。

另外,除了業(yè)務(wù)使用需要注意此問題之外,還可以通過運(yùn)維手段來及時發(fā)現(xiàn)這種情況。

做法是我們需要把 Redis 的各項(xiàng)運(yùn)行數(shù)據(jù)監(jiān)控起來,執(zhí)行 info 可以拿到所有的運(yùn)行數(shù)據(jù)。

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

我們需要對這個指標(biāo)監(jiān)控,當(dāng)在很短時間內(nèi)這個指標(biāo)出現(xiàn)突增時,需要及時報警出來,然后與業(yè)務(wù)報慢的時間點(diǎn)對比分析,確認(rèn)時間是否一致,如果一致,則可以認(rèn)為確實(shí)是因?yàn)檫@個原因?qū)е碌难舆t增大。

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

有時我們把 Redis 當(dāng)做純緩存使用,就會給實(shí)例設(shè)置一個內(nèi)存上限 maxmemory,然后開啟 LRU 淘汰策略。

當(dāng)實(shí)例的內(nèi)存達(dá)到了 maxmemory 后,你會發(fā)現(xiàn)之后的每次寫入新的數(shù)據(jù),有可能變慢了。

導(dǎo)致變慢的原因是,當(dāng) Redis 內(nèi)存達(dá)到 maxmemory 后,每次寫入新的數(shù)據(jù)之前,必須先踢出一部分?jǐn)?shù)據(jù),讓內(nèi)存維持在 maxmemory 之下。

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

  • allkeys-lru:不管 Key 是否設(shè)置了過期,淘汰最近最少訪問的 Key。
  • volatile-lru:只淘汰最近最少訪問并設(shè)置過期的 Key。
  • allkeys-random:不管 Key 是否設(shè)置了過期,隨機(jī)淘汰。
  • volatile-random:只隨機(jī)淘汰有設(shè)置過期的 Key。
  • allkeys-ttl:不管 Key 是否設(shè)置了過期,淘汰即將過期的 Key。
  • noeviction:不淘汰任何 Key,滿容后再寫入直接報錯。
  • allkeys-lfu:不管 Key 是否設(shè)置了過期,淘汰訪問頻率最低的 Key(4.0+支持)。
  • volatile-lfu:只淘汰訪問頻率最低的過期 Key(4.0+支持)。

具體使用哪種策略,需要根據(jù)業(yè)務(wù)場景來決定。

我們最常使用的一般是 allkeys-lru 或 volatile-lru 策略,它們的處理邏輯是,每次從實(shí)例中隨機(jī)取出一批 Key(可配置),然后淘汰一個最少訪問的 Key。

之后把剩下的 Key 暫存到一個池子中,繼續(xù)隨機(jī)取出一批 Key,并與之前池子中的 Key 比較,再淘汰一個最少訪問的 Key。以此循環(huán),直到內(nèi)存降到 maxmemory 之下。

如果使用的是 allkeys-random 或 volatile-random 策略,那么就會快很多。

因?yàn)槭请S機(jī)淘汰,那么就少了比較 Key 訪問頻率時間的消耗了,隨機(jī)拿出一批 Key 后直接淘汰即可,因此這個策略要比上面的 LRU 策略執(zhí)行快一些。

但以上這些邏輯都是在訪問 Redis 時,真正命令執(zhí)行之前執(zhí)行的,也就是它會影響我們訪問 Redis 時執(zhí)行的命令。

另外,如果此時 Redis 實(shí)例中有存儲大 Key,那么在淘汰大 Key 釋放內(nèi)存時,這個耗時會更加久,延遲更大,這需要我們格外注意。

如果你的業(yè)務(wù)訪問量非常大,并且必須設(shè)置 maxmemory 限制實(shí)例的內(nèi)存上限,同時面臨淘汰 Key 導(dǎo)致延遲增大的的情況,要想緩解這種情況。

除了上面說的避免存儲大 Key、使用隨機(jī)淘汰策略之外,也可以考慮拆分實(shí)例的方法來緩解,拆分實(shí)例可以把一個實(shí)例淘汰 Key 的壓力分?jǐn)偟蕉鄠€實(shí)例上,可以在一定程度降低延遲。

Fork 耗時嚴(yán)重

如果你的 Redis 開啟了自動生成 RDB 和 AOF 重寫功能,那么有可能在后臺生成 RDB 和 AOF 重寫時導(dǎo)致 Redis 的訪問延遲增大,而等這些任務(wù)執(zhí)行完畢后,延遲情況消失。

遇到這種情況,一般就是執(zhí)行生成 RDB 和 AOF 重寫任務(wù)導(dǎo)致的。

生成 RDB 和 AOF 都需要父進(jìn)程 Fork 出一個子進(jìn)程進(jìn)行數(shù)據(jù)的持久化,在 Fork 執(zhí)行過程中,父進(jìn)程需要拷貝內(nèi)存頁表給子進(jìn)程。

如果整個實(shí)例內(nèi)存占用很大,那么需要拷貝的內(nèi)存頁表會比較耗時,此過程會消耗大量的 CPU 資源,在完成 Fork 之前,整個實(shí)例會被阻塞住,無法處理任何請求。

如果此時 CPU 資源緊張,那么 Fork 的時間會更長,甚至達(dá)到秒級。這會嚴(yán)重影響 Redis 的性能。

我們可以執(zhí)行 info 命令,查看最后一次 Fork 執(zhí)行的耗時 latest_fork_usec,單位微秒。這個時間就是整個實(shí)例阻塞無法處理請求的時間。

除了因?yàn)閭浞莸脑蛏?RDB 之外,在主從節(jié)點(diǎn)第一次建立數(shù)據(jù)同步時,主節(jié)點(diǎn)也會生成 RDB 文件給從節(jié)點(diǎn)進(jìn)行一次全量同步,這時也會對 Redis 產(chǎn)生性能影響。

要想避免這種情況,我們需要規(guī)劃好數(shù)據(jù)備份的周期,建議在從節(jié)點(diǎn)上執(zhí)行備份,而且最好放在低峰期執(zhí)行。

如果對于丟失數(shù)據(jù)不敏感的業(yè)務(wù),那么不建議開啟 RDB 和 AOF 重寫功能。

另外,F(xiàn)ork 的耗時也與系統(tǒng)有關(guān),如果把 Redis 部署在虛擬機(jī)上,那么這個時間也會增大。所以使用 Redis 時建議部署在物理機(jī)上,降低 Fork 的影響。

綁定 CPU

很多時候,我們在部署服務(wù)時,為了提高性能,降低程序在使用多個 CPU 時上下文切換的性能損耗,一般會采用進(jìn)程綁定 CPU 的操作。

但在使用 Redis 時,我們不建議這么干,原因如下。

綁定 CPU 的 Redis,在進(jìn)行數(shù)據(jù)持久化時,F(xiàn)ork 出的子進(jìn)程,子進(jìn)程會繼承父進(jìn)程的 CPU 使用偏好。

而此時子進(jìn)程會消耗大量的 CPU 資源進(jìn)行數(shù)據(jù)持久化,子進(jìn)程會與主進(jìn)程發(fā)生 CPU 爭搶,這也會導(dǎo)致主進(jìn)程的 CPU 資源不足訪問延遲增大。

所以在部署 Redis 進(jìn)程時,如果需要開啟 RDB 和 AOF 重寫機(jī)制,一定不能進(jìn)行 CPU 綁定操作!

開啟 AOF

上面提到了,當(dāng)執(zhí)行 AOF 文件重寫時會因?yàn)?Fork 執(zhí)行耗時導(dǎo)致 Redis 延遲增大,除了這個之外,如果開啟 AOF 機(jī)制,設(shè)置的策略不合理,也會導(dǎo)致性能問題。

開啟 AOF 后,Redis 會把寫入的命令實(shí)時寫入到文件中,但寫入文件的過程是先寫入內(nèi)存,等內(nèi)存中的數(shù)據(jù)超過一定閾值或達(dá)到一定時間后,內(nèi)存中的內(nèi)容才會被真正寫入到磁盤中。

AOF 為了保證文件寫入磁盤的安全性,提供了三種刷盤機(jī)制:

  • appendfsync always:每次寫入都刷盤,對性能影響最大,占用磁盤 IO 比較高,數(shù)據(jù)安全性最高。
  • appendfsync everysec:1 秒刷一次盤,對性能影響相對較小,節(jié)點(diǎn)宕機(jī)時最多丟失 1 秒的數(shù)據(jù)。
  • appendfsync no:按照操作系統(tǒng)的機(jī)制刷盤,對性能影響最小,數(shù)據(jù)安全性低,節(jié)點(diǎn)宕機(jī)丟失數(shù)據(jù)取決于操作系統(tǒng)刷盤機(jī)制。

當(dāng)使用第一種機(jī)制 appendfsync always 時,Redis 每處理一次寫命令,都會把這個命令寫入磁盤,而且這個操作是在主線程中執(zhí)行的。

內(nèi)存中的的數(shù)據(jù)寫入磁盤,這個會加重磁盤的 IO 負(fù)擔(dān),操作磁盤成本要比操作內(nèi)存的代價大得多。

如果寫入量很大,那么每次更新都會寫入磁盤,此時機(jī)器的磁盤 IO 就會非常高,拖慢 Redis 的性能,因此我們不建議使用這種機(jī)制。

與第一種機(jī)制對比,appendfsync everysec 會每隔 1 秒刷盤,而 appendfsync no 取決于操作系統(tǒng)的刷盤時間,安全性不高。

因此我們推薦使用 appendfsync everysec 這種方式,在最壞的情況下,只會丟失 1 秒的數(shù)據(jù),但它能保持較好的訪問性能。

當(dāng)然,對于有些業(yè)務(wù)場景,對丟失數(shù)據(jù)并不敏感,也可以不開啟 AOF。

使用 Swap

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

我們知道,操作系統(tǒng)提供了 Swap 機(jī)制,目的是為了當(dāng)內(nèi)存不足時,可以把一部分內(nèi)存中的數(shù)據(jù)換到磁盤上,以達(dá)到對內(nèi)存使用的緩沖。

但當(dāng)內(nèi)存中的數(shù)據(jù)被換到磁盤上后,訪問這些數(shù)據(jù)就需要從磁盤中讀取,這個速度要比內(nèi)存慢太多!

尤其是針對 Redis 這種高性能的內(nèi)存數(shù)據(jù)庫來說,如果 Redis 中的內(nèi)存被換到磁盤上,對于 Redis 這種性能極其敏感的數(shù)據(jù)庫,這個操作時間是無法接受的。

我們需要檢查機(jī)器的內(nèi)存使用情況,確認(rèn)是否確實(shí)是因?yàn)閮?nèi)存不足導(dǎo)致使用到了 Swap。

如果確實(shí)使用到了 Swap,要及時整理內(nèi)存空間,釋放出足夠的內(nèi)存供 Redis 使用,然后釋放 Redis 的 Swap,讓 Redis 重新使用內(nèi)存。

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

可見,當(dāng) Redis 使用到 Swap 后,此時的 Redis 的高性能基本被廢掉,所以我們需要提前預(yù)防這種情況。

我們需要對 Redis 機(jī)器的內(nèi)存和 Swap 使用情況進(jìn)行監(jiān)控,在內(nèi)存不足和使用到 Swap 時及時報警出來,及時進(jìn)行相應(yīng)的處理。

網(wǎng)卡負(fù)載過高

如果以上產(chǎn)生性能問題的場景,你都規(guī)避掉了,而且 Redis 也穩(wěn)定運(yùn)行了很長時間,但在某個時間點(diǎn)之后開始,訪問 Redis 開始變慢了,而且一直持續(xù)到現(xiàn)在,這種情況是什么原因?qū)е碌?

之前我們就遇到這種問題,特點(diǎn)就是從某個時間點(diǎn)之后就開始變慢,并且一直持續(xù)。這時你需要檢查一下機(jī)器的網(wǎng)卡流量,是否存在網(wǎng)卡流量被跑滿的情況。

網(wǎng)卡負(fù)載過高,在網(wǎng)絡(luò)層和 TCP 層就會出現(xiàn)數(shù)據(jù)發(fā)送延遲、數(shù)據(jù)丟包等情況。

Redis 的高性能除了內(nèi)存之外,就在于網(wǎng)絡(luò) IO,請求量突增會導(dǎo)致網(wǎng)卡負(fù)載變高。

如果出現(xiàn)這種情況,你需要排查這個機(jī)器上的哪個 Redis 實(shí)例的流量過大占滿了網(wǎng)絡(luò)帶寬,然后確認(rèn)流量突增是否屬于業(yè)務(wù)正常情況,如果屬于那就需要及時擴(kuò)容或遷移實(shí)例,避免這個機(jī)器的其他實(shí)例受到影響。

運(yùn)維層面,我們需要對機(jī)器的各項(xiàng)指標(biāo)增加監(jiān)控,包括網(wǎng)絡(luò)流量,在達(dá)到閾值時提前報警,及時與業(yè)務(wù)確認(rèn)并擴(kuò)容。

小結(jié):以上我們總結(jié)了 Redis 中常見的可能導(dǎo)致延遲增大甚至阻塞的場景,這其中既涉及到了業(yè)務(wù)的使用問題,也涉及到 Redis 的運(yùn)維問題。

可見,要想保證 Redis 高性能的運(yùn)行,其中涉及到 CPU、內(nèi)存、網(wǎng)絡(luò),甚至磁盤的方方面面,其中還包括操作系統(tǒng)的相關(guān)特性的使用。

作為開發(fā)人員,我們需要了解 Redis 的運(yùn)行機(jī)制,例如各個命令的執(zhí)行時間復(fù)雜度、數(shù)據(jù)過期策略、數(shù)據(jù)淘汰策略等,使用合理的命令,并結(jié)合業(yè)務(wù)場景進(jìn)行優(yōu)化。

作為 DBA 運(yùn)維人員,需要了解數(shù)據(jù)持久化、操作系統(tǒng) Fork 原理、Swap 機(jī)制等,并對 Redis 的容量進(jìn)行合理規(guī)劃,預(yù)留足夠的機(jī)器資源,對機(jī)器做好完善的監(jiān)控,才能保證 Redis 的穩(wěn)定運(yùn)行。

Redis 最佳實(shí)踐:業(yè)務(wù)層面和運(yùn)維層面優(yōu)化

在上文中,主要講解了 Redis 常見的導(dǎo)致變慢的場景以及問題定位和分析,主要是由業(yè)務(wù)使用不合理和運(yùn)維不當(dāng)導(dǎo)致的。

我們在了解了導(dǎo)致 Redis 變慢的原因之后,針對性地優(yōu)化,就可以讓 Redis 穩(wěn)定發(fā)揮出更高性能。

接下來我們就來總結(jié)一下,在使用 Redis 時的最佳實(shí)踐方式,主要包含兩個層面:

  • 業(yè)務(wù)層面
  • 運(yùn)維層面

由于我之前寫過很多 UGC 后端服務(wù),在大量場景下用到了 Redis,這個過程中也踩過很多坑,所以在使用過程中也總結(jié)了一套合理的使用方法。

后來做基礎(chǔ)架構(gòu),開發(fā) Codis、Redis 相關(guān)的中間件,在這個階段關(guān)注領(lǐng)域從使用層面下沉到 Redis 的開發(fā)和運(yùn)維,更多聚焦在 Redis 的內(nèi)部實(shí)現(xiàn)和運(yùn)維過程中產(chǎn)生的各種問題,在這塊也積累了一些經(jīng)驗(yàn)。

下面就針對這兩塊,分享一下我認(rèn)為比較合理的 Redis 使用和運(yùn)維方法,不一定最全面,也可能與你使用 Redis 的方法不同,但以下這些方法都是我在踩坑之后總結(jié)的實(shí)際經(jīng)驗(yàn),供你參考。

業(yè)務(wù)層面

業(yè)務(wù)層面主要是開發(fā)人員需要關(guān)注,也就是開發(fā)人員在寫業(yè)務(wù)代碼時,如何合理地使用 Redis。

開發(fā)人員需要對 Redis 有基本的了解,才能在合適的業(yè)務(wù)場景使用 Redis,從而避免業(yè)務(wù)層面導(dǎo)致的延遲問題。

在開發(fā)過程中,業(yè)務(wù)層面的優(yōu)化建議如下:

  • Key 的長度盡量要短,在數(shù)據(jù)量非常大時,過長的 Key 名會占用更多的內(nèi)存。
  • 一定避免存儲過大的數(shù)據(jù)(大 Value),過大的數(shù)據(jù)在分配內(nèi)存和釋放內(nèi)存時耗時嚴(yán)重,會阻塞主線程。
  • Redis 4.0 以上建議開啟 lazy-free 機(jī)制,釋放大 Value 時異步操作,不阻塞主線程。
  • 建議設(shè)置過期時間,把 Redis 當(dāng)做緩存使用,尤其在數(shù)量很大的時,不設(shè)置過期時間會導(dǎo)致內(nèi)存的無限增長。
  • 不使用復(fù)雜度過高的命令,例如 SORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE,使用這些命令耗時較久,會阻塞主線程。
  • 查詢數(shù)據(jù)時,一次盡量獲取較少的數(shù)據(jù),在不確定容器元素個數(shù)的情況下,避免使用 LRANGE key 0 -1,ZRANGE key 0 -1 這類操作,應(yīng)該設(shè)置具體查詢的元素個數(shù),推薦一次查詢 100 個以下元素。
  • 寫入數(shù)據(jù)時,一次盡量寫入較少的數(shù)據(jù),例如 HSET key value1 value2 value3...,控制一次寫入元素的數(shù)量,推薦在 100 以下,大數(shù)據(jù)量分多個批次寫入。
  • 批量操作數(shù)據(jù)時,用 MGET/MSET 替換 GET/SET、HMGET/MHSET 替換 HGET/HSET,減少請求來回的網(wǎng)絡(luò) IO 次數(shù),降低延遲,對于沒有批量操作的命令,推薦使用 Pipeline,一次性發(fā)送多個命令到服務(wù)端。
  • 禁止使用 KEYS 命令,需要掃描實(shí)例時,建議使用 SCAN,線上操作一定要控制掃描的頻率,避免對 Redis 產(chǎn)生性能抖動。
  • 避免某個時間點(diǎn)集中過期大量的 Key,集中過期時推薦增加一個隨機(jī)時間,把過期時間打散,降低集中過期 Key 時 Redis 的壓力,避免阻塞主線程。
  • 根據(jù)業(yè)務(wù)場景,選擇合適的淘汰策略,通常隨機(jī)過期要比 LRU 過期淘汰數(shù)據(jù)更快。
  • 使用連接池訪問 Redis,并配置合理的連接池參數(shù),避免短連接,TCP 三次握手和四次揮手的耗時也很高。
  • 只使用 db0,不推薦使用多個 db,使用多個 db 會增加 Redis 的負(fù)擔(dān),每次訪問不同的 db 都需要執(zhí)行 SELECT 命令,如果業(yè)務(wù)線不同,建議拆分多個實(shí)例,還能提高單個實(shí)例的性能。
  • 讀的請求量很大時,推薦使用讀寫分離,前提是可以容忍從節(jié)數(shù)據(jù)更新不及時的問題。
  • 寫請求量很大時,推薦使用集群,部署多個實(shí)例分?jǐn)倢憠毫Α?/li>

運(yùn)維層面

運(yùn)維層面主要是 DBA 需要關(guān)注的,目的是合理規(guī)劃 Redis 的部署和保障 Redis 的穩(wěn)定運(yùn)行。

主要優(yōu)化如下:

  • 不同業(yè)務(wù)線部署不同的實(shí)例,各自獨(dú)立,避免混用,推薦不同業(yè)務(wù)線使用不同的機(jī)器,根據(jù)業(yè)務(wù)重要程度劃分不同的分組來部署,避免某一個業(yè)務(wù)線出現(xiàn)問題影響其他業(yè)務(wù)線。
  • 保證機(jī)器有足夠的 CPU、內(nèi)存、帶寬、磁盤資源,防止負(fù)載過高影響 Redis 性能。
  • 以 master-slave 集群方式部署實(shí)例,并分布在不同機(jī)器上,避免單點(diǎn),Slave 必須設(shè)置為 Readonly。
  • Master 和 Slave 節(jié)點(diǎn)所在機(jī)器,各自獨(dú)立,不要交叉部署實(shí)例,通常備份工作會在 Slave 上做,做備份時會消耗機(jī)器資源,交叉部署會影響到 Master 的性能。
  • 推薦部署哨兵節(jié)點(diǎn)增加可用性,節(jié)點(diǎn)數(shù)量至少 3 個,并分布在不同機(jī)器上,實(shí)現(xiàn)故障自動故障轉(zhuǎn)移。
  • 提前做好容量規(guī)劃,一臺機(jī)器部署實(shí)例的內(nèi)存上限,最好是機(jī)器內(nèi)存的一半,主從全量同步時會占用最多額外一倍的內(nèi)存空間,防止網(wǎng)絡(luò)大面積故障引發(fā)所有 master-slave 的全量同步導(dǎo)致機(jī)器內(nèi)存被吃光。
  • 做好機(jī)器的 CPU、內(nèi)存、帶寬、磁盤監(jiān)控,在資源不足時及時報警處理,Redis 使用 Swap 后性能急劇下降,網(wǎng)絡(luò)帶寬負(fù)載過高訪問延遲明顯增大,磁盤 IO 過高時開啟 AOF 會拖慢 Redis 的性能。
  • 設(shè)置最大連接數(shù)上限,防止過多的客戶端連接導(dǎo)致服務(wù)負(fù)載過高。
  • 單個實(shí)例的使用內(nèi)存建議控制在 20G 以下,過大的實(shí)例會導(dǎo)致備份時間久、資源消耗多,主從全量同步數(shù)據(jù)時間阻塞時間更長。
  • 設(shè)置合理的 slowlog 閾值,推薦 10 毫秒,并對其進(jìn)行監(jiān)控,產(chǎn)生過多的慢日志需要及時報警。
  • 設(shè)置合理的復(fù)制緩沖區(qū) repl-backlog 大小,適當(dāng)調(diào)大 repl-backlog 可以降低主從全量復(fù)制的概率。
  • 設(shè)置合理的 Slave 節(jié)點(diǎn) client-output-buffer-limit 大小,對于寫入量很大的實(shí)例,適當(dāng)調(diào)大可以避免主從復(fù)制中斷問題。
  • 備份時推薦在 Slave 節(jié)點(diǎn)上做,不影響 Master 性能。
  • 不開啟 AOF 或開啟 AOF 配置為每秒刷盤,避免磁盤 IO 消耗降低 Redis 性能。
  • 當(dāng)實(shí)例設(shè)置了內(nèi)存上限,需要調(diào)大內(nèi)存上限時,先調(diào)整 Slave 再調(diào)整 Master,否則會導(dǎo)致主從節(jié)點(diǎn)數(shù)據(jù)不一致。
  • 對 Redis 增加監(jiān)控,監(jiān)控采集 info 信息時,使用長連接,頻繁的短連接也會影響 Redis 性能。
  • 線上掃描整個實(shí)例數(shù)時,記得設(shè)置休眠時間,避免掃描時 QPS 突增對 Redis 產(chǎn)生性能抖動。
  • 做好 Redis 的運(yùn)行時監(jiān)控,尤其是 expired_keys、evicted_keys、latest_fork_usec 指標(biāo),短時間內(nèi)這些指標(biāo)值突增可能會阻塞整個實(shí)例,引發(fā)性能問題。

總結(jié)

以上就是我在使用 Redis 和開發(fā) Redis 相關(guān)中間件時,總結(jié)出來 Redis 推薦的實(shí)踐方法,以上提出的這些方面,都或多或少在實(shí)際使用中遇到過。

可見,要想穩(wěn)定發(fā)揮 Redis 的高性能,需要在各個方面做好工作,但凡某一個方面出現(xiàn)問題,必然會影響到 Redis 的性能,這對我們使用和運(yùn)維提出了更高的要求。

如果你在使用 Redis 過程中,遇到更多的問題或者有更好的使用經(jīng)驗(yàn),可以留言一起探討!

作者:Kaito

簡介:90 后,坐標(biāo)北京,6 年+工作經(jīng)驗(yàn),就職于一家移動互聯(lián)網(wǎng)公司,目前從事基礎(chǔ)架構(gòu)和數(shù)據(jù)庫中間件研發(fā)。

編輯:陶家龍

出處:http://kaito-kidd.com/

責(zé)任編輯:武曉燕 來源: kaito-kidd
相關(guān)推薦

2018-08-16 08:03:21

Python語言解釋器

2016-12-28 11:28:19

.NET反射

2022-06-30 08:01:53

mysqlmyisamcount

2021-05-29 06:23:47

webpack esbuild

2015-09-09 11:04:28

Wi-Fi網(wǎng)速

2025-06-20 04:55:00

Wi-Fi組網(wǎng)CSSR

2018-10-28 15:40:23

Python編程語言

2023-03-21 08:02:36

Redis6.0IO多線程

2019-12-18 09:42:19

技術(shù) Linux網(wǎng)絡(luò)

2023-08-29 07:46:08

Redis數(shù)據(jù)ReHash

2020-12-22 09:10:05

SQLMysql 數(shù)據(jù)庫

2020-08-10 11:20:59

索引MySQL數(shù)據(jù)庫

2020-10-21 09:17:52

Redis面試內(nèi)存

2022-01-04 08:54:32

Redis數(shù)據(jù)庫數(shù)據(jù)類型

2024-07-24 08:38:07

2025-03-04 07:30:00

開發(fā)前端Node.js

2019-08-30 14:58:47

JavaScript程序員編程語言

2024-02-26 21:15:20

Kafka緩存參數(shù)

2013-03-04 10:10:36

WebKit瀏覽器

2022-06-02 08:03:19

PyCharmPython代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品高清一区二区三区 | 国产网站在线免费观看 | 久久久久久久99 | 一级a爱片久久毛片 | 秋霞在线一区二区 | 中文字幕 亚洲一区 | 国产99久久精品一区二区永久免费 | 欧美激情欧美激情在线五月 | 久久久久国产精品一区三寸 | 亚洲视频欧美视频 | 久久久精品一区二区 | 欧美视频在线免费 | 久久久精品 | 美女视频一区二区三区 | 一区二区三区在线观看视频 | 精品久久精品 | 欧美精品在线看 | 国产精品久久久久久久久久99 | 久久精品国产清自在天天线 | 精品伦精品一区二区三区视频 | 国产一区二区不卡 | 久久精品中文字幕 | 色综合色综合网色综合 | 亚洲五码久久 | 热99视频| 天天综合91 | 在线观看av网站 | 精品久久久久国产免费第一页 | 91影院在线观看 | 91视频久久久久 | 欧美激情在线播放 | 国产日韩精品视频 | 99热热精品 | 久久天堂 | 精品久久中文 | 久久久久国产 | 自拍亚洲 | 日韩一区在线视频 | 欧州一区 | 99这里只有精品视频 | 国产福利在线视频 |