久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Redis常見的延遲問題有哪些

166次閱讀
沒有評論

共計 6734 個字符,預計需要花費 17 分鐘才能閱讀完成。

這篇文章主要介紹“Redis 常見的延遲問題有哪些”,在日常操作中,相信很多人在 Redis 常見的延遲問題有哪些問題上存在疑惑,丸趣 TV 小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Redis 常見的延遲問題有哪些”的疑惑有所幫助!接下來,請跟著丸趣 TV 小編一起來學習吧!

使用復雜度高的命令

如果在使用 Redis 時,發現訪問延遲突然增大,如何進行排查?

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

首先設置 Redis 的慢日志閾值

,只有超過閾值的命令才會被記錄,這里的單位是微秒,例如設置慢日志的閾值為 5 毫秒,同時設置只保留最近 1000 條慢日志記錄:

#  命令執行超過 5 毫秒記錄慢日志  CONFIG SET slowlog-log-slower-than 5000 #  只保留最近 1000 條慢日志  CONFIG SET slowlog-max-len 1000

設置完成之后,所有執行的命令如果延遲大于 5 毫秒,都會被 Redis 記錄下來,我們執行 SLOWLOG get 5

查詢最近 5 條慢日志

127.0.0.1:6379  SLOWLOG get5 1)1)(integer)32693#  慢日志 ID 2)(integer)1593763337#  執行時間  3)(integer)5299#  執行耗時(微秒) 4)1) LRANGE #  具體執行的命令和參數  2) user_list_2000  3) 0  4) -1  2)1)(integer)32692 2)(integer)1593763337 3)(integer)5044 4)1) GET  2) book_price_1000  ...

通過查看慢日志記錄,我們就可以知道在什么時間執行哪些命令比較耗時,如果你的業務經常使用 O(n)

以上復雜度的命令,例如 sort、sunion、zunionstore,

或者在執行 O(n)命令時操作的數據量比較大,這些情況下 Redis 處理數據時就會很耗時。

如果你的服務請求量并不大,但 Redis 實例的 CPU 使用率很高,很有可能是使用了復雜度高的命令導致的。

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

存儲大 key

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

Redis 在寫入數據時,需要為新的數據分配內存,當從 Redis 中刪除數據時,它會釋放對應的內存空間。

如果一個 key 寫入的數據非常大,Redis 在分配內存時也會比較耗時。

同樣的,當刪除這個 key 的數據時,釋放內存也會耗時比較久。

你需要檢查你的業務代碼,是否存在寫入大 key 的情況,需要評估寫入數據量的大小,業務層應該避免一個 key 存入過大的數據量。

那么有沒有什么辦法可以掃描現在 Redis 中是否存在大 key 的數據嗎?

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

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

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

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

使用這個命令的原理,其實就是 Redis 在內部執行 scan 命令,遍歷所有 key,然后針對不同類型的 key 執行 strlen、llen、hlen、scard、zcard 來獲取字符串的長度以及容器類型 (list/dict/set/zset) 的元素個數。

而對于容器類型的 key,只能掃描出元素最多的 key,但元素最多的 key 不一定占用內存最多,這一點需要我們注意下。不過使用這個命令一般我們是可以對整個實例中 key 的分布情況有比較清晰的了解。

針對大 key 的問題,Redis 官方在 4.0 版本推出了 lazy-free 的機制,用于異步釋放大 key 的內存,降低對 Redis 性能的影響。即使這樣,我們也不建議使用大 key,大 key 在集群的遷移過程中,也會影響到遷移的性能,這個后面在介紹集群相關的文章時,會再詳細介紹到。

集中過期

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

如果出現這種情況,就需要考慮是否存在大量 key 集中過期的情況。

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

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

兩種策略:

bull; 主動過期:Redis 內部維護一個定時任務,默認每隔 100 毫秒會從過期字典中隨機取出 20 個 key,刪除過期的 key,如果過期 key 的比例超過了 25%,則繼續獲取 20 個 key,刪除過期的 key,循環往復,直到過期 key 的比例下降到 25% 或者這次任務的執行耗時超過了 25 毫秒,才會退出循環

bull; 懶惰過期:只有當訪問某個 key 時,才判斷這個 key 是否已過期,如果已經過期,則從實例中刪除

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

也就是說如果在執行主動過期的過程中,出現了需要大量刪除過期 key 的情況,那么在業務訪問時,必須等這個過期任務執行結束,才可以處理業務請求。此時就會出現,業務訪問延時增大的問題,最大延遲為 25 毫秒。

而且這個訪問延遲的情況,不會記錄在慢日志里。慢日志中只記錄真正執行某個命令的耗時,Redis 主動過期策略執行在操作命令之前,如果操作命令耗時達不到慢日志閾值,它是不會計算在慢日志統計中的,但我們的業務卻感到了延遲增大。

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

如果你的業務確實需要集中過期掉某些 key,又不想導致 Redis 發生抖動,有什么優化方案?

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

偽代碼可以這么寫:

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

這樣 Redis 在處理過期時,不會因為集中刪除 key 導致壓力過大,阻塞主線程。

另外,除了業務使用需要注意此問題之外,還可以通過運維手段來及時發現這種情況。

做法是我們需要把 Redis 的各項運行數據監控起來,執行 info 可以拿到所有的運行數據,在這里我們需要重點關注 expired_keys 這一項,它代表整個實例到目前為止,累計刪除過期 key 的數量。

我們需要對這個指標監控,當在很短時間內這個指標出現突增時,需要及時報警出來,然后與業務報慢的時間點對比分析,確認時間是否一致,如果一致,則可以認為確實是因為這個原因導致的延遲增大。

實例內存達到上限

有時我們把 Redis 當做純緩存使用,就會給實例設置一個內存上限 maxmemory,然后開啟 LRU 淘汰策略。

當實例的內存達到了 maxmemory 后,你會發現之后的每次寫入新的數據,有可能變慢了。

導致變慢的原因是,當 Redis 內存達到 maxmemory 后,每次寫入新的數據之前,必須先踢出一部分數據,讓內存維持在 maxmemory 之下。

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

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

bull;volatile-lru:只淘汰最近最少訪問并設置過期的 key

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

bull;volatile-random:只隨機淘汰有設置過期的 key

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

bull;noeviction:不淘汰任何 key,滿容后再寫入直接報錯

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

bull;volatile-lfu:只淘汰訪問頻率最低的過期 key(4.0+ 支持)

備注:allkeys-xxx 表示從所有的鍵值中淘汰數據,而 volatile-xxx 表示從設置了過期鍵的鍵值中淘汰數據。

具體使用哪種策略,需要根據業務場景來決定。

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

如果使用的是 allkeys-random 或 volatile-random 策略,那么就會快很多,因為是隨機淘汰,那么就少了比較 key 訪問頻率時間的消耗了,隨機拿出一批 key 后直接淘汰即可,因此這個策略要比上面的 LRU 策略執行快一些。

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

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

如果你的業務訪問量非常大,并且必須設置 maxmemory 限制實例的內存上限,同時面臨淘汰 key 導致延遲增大的的情況,要想緩解這種情況,除了上面說的避免存儲大 key、使用隨機淘汰策略之外,也可以考慮拆分實例的方法來緩解,拆分實例可以把一個實例淘汰 key 的壓力分攤到多個實例上,可以在一定程度降低延遲。

fork 耗時嚴重

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

遇到這種情況,一般就是執行生成 RDB 和 AOF 重寫任務導致的。

生成 RDB 和 AOF 都需要父進程 fork 出一個子進程進行數據的持久化,在 fork 執行過程中,父進程需要拷貝內存頁表給子進程,如果整個實例內存占用很大,那么需要拷貝的內存頁表會比較耗時,此過程會消耗大量的 CPU 資源,在完成 fork 之前,整個實例會被阻塞住,無法處理任何請求,如果此時 CPU 資源緊張,那么 fork 的時間會更長,甚至達到秒級。這會嚴重影響 Redis 的性能。

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

除了因為備份的原因生成 RDB 之外,在主從節點第一次建立數據同步時,主節點也會生成 RDB 文件給從節點進行一次全量同步,這時也會對 Redis 產生性能影響。

要想避免這種情況,我們需要規劃好數據備份的周期,建議在從節點上執行備份,而且最好放在低峰期執行。如果對于丟失數據不敏感的業務,那么不建議開啟 AOF 和 AOF 重寫功能。

另外,fork 的耗時也與系統有關,如果把 Redis 部署在虛擬機上,那么這個時間也會增大。所以使用 Redis 時建議部署在物理機上,降低 fork 的影響。

綁定 CPU

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

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

綁定 CPU 的 Redis,在進行數據持久化時,fork 出的子進程,子進程會繼承父進程的 CPU 使用偏好,而此時子進程會消耗大量的 CPU 資源進行數據持久化,子進程會與主進程發生 CPU 爭搶,這也會導致主進程的 CPU 資源不足訪問延遲增大。

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

開啟 AOF

上面提到了,當執行 AOF 文件重寫時會因為 fork 執行耗時導致 Redis 延遲增大,除了這個之外,如果開啟 AOF 機制,設置的策略不合理,也會導致性能問題。

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

AOF 為了保證文件寫入磁盤的安全性,提供了 3 種刷盤機制:

bull;appendfsync always:每次寫入都刷盤,對性能影響最大,占用磁盤 IO 比較高,數據安全性最高

bull;appendfsync everysec:1 秒刷一次盤,對性能影響相對較小,節點宕機時最多丟失 1 秒的數據

bull;appendfsync no:按照操作系統的機制刷盤,對性能影響最小,數據安全性低,節點宕機丟失數據取決于操作系統刷盤機制

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

內存中的的數據寫入磁盤,這個會加重磁盤的 IO 負擔,操作磁盤成本要比操作內存的代價大得多。如果寫入量很大,那么每次更新都會寫入磁盤,此時機器的磁盤 IO 就會非常高,拖慢 Redis 的性能,因此我們不建議使用這種機制。

與第一種機制對比,appendfsync everysec 會每隔 1 秒刷盤,而 appendfsync no 取決于操作系統的刷盤時間,安全性不高。因此我們推薦使用 appendfsync everysec 這種方式,在最壞的情況下,只會丟失 1 秒的數據,但它能保持較好的訪問性能。

當然,對于有些業務場景,對丟失數據并不敏感,也可以不開啟 AOF。

使用 Swap

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

我們知道,操作系統提供了 Swap 機制,目的是為了當內存不足時,可以把一部分內存中的數據換到磁盤上,以達到對內存使用的緩沖。

但當內存中的數據被換到磁盤上后,訪問這些數據就需要從磁盤中讀取,這個速度要比內存慢太多!

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

我們需要檢查機器的內存使用情況,確認是否確實是因為內存不足導致使用到了 Swap。

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

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

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

我們需要對 Redis 機器的內存和 Swap 使用情況進行監控,在內存不足和使用到 Swap 時及時報警出來,及時進行相應的處理。

網卡負載過高

如果以上產生性能問題的場景,你都規避掉了,而且 Redis 也穩定運行了很長時間,但在某個時間點之后開始,訪問 Redis 開始變慢了,而且一直持續到現在,這種情況是什么原因導致的?

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

網卡負載過高,在網絡層和 TCP 層就會出現數據發送延遲、數據丟包等情況。Redis 的高性能除了內存之外,就在于網絡 IO,請求量突增會導致網卡負載變高。

如果出現這種情況,你需要排查這個機器上的哪個 Redis 實例的流量過大占滿了網絡帶寬,然后確認流量突增是否屬于業務正常情況,如果屬于那就需要及時擴容或遷移實例,避免這個機器的其他實例受到影響。

運維層面,我們需要對機器的各項指標增加監控,包括網絡流量,在達到閾值時提前報警,及時與業務確認并擴容。

到此,關于“Redis 常見的延遲問題有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注丸趣 TV 網站,丸趣 TV 小編會繼續努力為大家帶來更多實用的文章!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-27發表,共計6734字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 徐闻县| 平谷区| 霍林郭勒市| 五台县| 鄱阳县| 海南省| 安平县| 晴隆县| 七台河市| 鸡东县| 肥东县| 天台县| 乳源| 墨脱县| 饶河县| 德兴市| 柳河县| 福海县| 宣武区| 兴安县| 汕尾市| 海盐县| 普陀区| 棋牌| 永康市| 孝义市| 淮安市| 新闻| 巨鹿县| 林周县| 温州市| 牙克石市| 灵川县| 略阳县| 龙胜| 安陆市| 绥江县| 翁源县| 潢川县| 陆良县| 固原市|