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

Redis有哪些慢操作?

開發
Redis是否變慢了?從業務服務器到Redis服務器這條調用鏈路中變慢的原因可能有2個,不過大多數情況下都是Redis服務的問題。但是應該如何衡量Redis變慢了呢?

Redis是否變慢了?

從業務服務器到Redis服務器這條調用鏈路中變慢的原因可能有2個

  • 業務服務器到Redis服務器之間出現了網絡問題,例如網絡丟包,延遲比較嚴重
  • Redis本身的執行出現問題,此時我們就需要排查Redis的問題

但是大多數情況下都是Redis服務的問題。但是應該如何衡量Redis變慢了呢?命令執行時間大于1s,大于2s?這其實并沒有一個固定的標準。

例如在一個配置較高的服務器中,0.5毫秒就認為Redis變慢了,在一個配置較低的服務器中,3毫秒才認為Redis變慢了。所以我們要針對自己的機器做基準測試,看平常情況下Redis處理命令的時間是多長?

我們可以使用如下命令來監測和統計測試期間的最大延遲(以微秒為單位)

redis-cli --latency -h `host` -p `port`

比如執行如下命令

[root@VM-0-14-centos src]# ./redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60
Max latency so far: 1 microseconds.
Max latency so far: 12 microseconds.
Max latency so far: 55 microseconds.
Max latency so far: 124 microseconds.
Max latency so far: 133 microseconds.
Max latency so far: 142 microseconds.
Max latency so far: 982 microseconds.
Max latency so far: 1049 microseconds.
Max latency so far: 2366 microseconds.
Max latency so far: 3725 microseconds.

52881684 total runs (avg latency: 1.1346 microseconds / 1134.61 nanoseconds per run).
Worst run took 3283x longer than the average latency.

參數中的60是測試執行的秒數,可以看到最大延遲為3725微秒(3毫秒左右),如果命令的執行遠超3毫秒,此時Redis就有可能很慢了!

那么Redis有哪些慢操作呢?

Redis有哪些慢操作?

Redis的各種命令是在一個線程中依次執行的,如果一個命令在Redis中執行的時間過長,就會影響整體的性能,因為后面的請求要等到前面的請求被處理完才能被處理,這些耗時的操作有如下幾個部分

Redis可以通過日志記錄那些耗時長的命令,使用如下配置即可

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

執行如下命令,就可以查詢到最近記錄的慢日志

127.0.0.1:6379> SLOWLOG get 5
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) "user_info:1000"
...

使用復雜度過高的命令

之前的文章我們已經介紹了Redis的底層數據結構,它們的時間復雜度如下表所示

名稱 時間復雜度 dict(字典) O(1) ziplist (壓縮列表) O(n) zskiplist (跳表) O(logN) quicklist(快速列表) O(n) intset(整數集合) O(n)

「單元素操作」:對集合中的元素進行增刪改查操作和底層數據結構相關,如對字典進行增刪改查時間復雜度為O(1),對跳表進行增刪查時間復雜為O(logN)

「范圍操作」:對集合進行遍歷操作,比如Hash類型的HGETALL,Set類型的SMEMBERS,List類型的LRANGE,ZSet類型的ZRANGE,時間復雜度為O(n),避免使用,用SCAN系列命令代替。(hash用hscan,set用sscan,zset用zscan)

「聚合操作」:這類操作的時間復雜度通常大于O(n),比如SORT、SUNION、ZUNIONSTORE

「統計操作」:當想獲取集合中的元素個數時,如LLEN或者SCARD,時間復雜度為O(1),因為它們的底層數據結構如quicklist,dict,intset保存了元素的個數

「邊界操作」:list底層是用quicklist實現的,quicklist保存了鏈表的頭尾節點,因此對鏈表的頭尾節點進行操作,時間復雜度為O(1),如LPOP、RPOP、LPUSH、RPUSH

「當想獲取Redis中的key時,避免使用keys *」 ,Redis中保存的鍵值對是保存在一個字典中的(和Java中的HashMap類似,也是通過數組+鏈表的方式實現的),key的類型都是string,value的類型可以是string,set,list等

例如當我們執行如下命令后,redis的字典結構如下

set bookName redis;
rpush fruits banana apple;

我們可以用keys命令來查詢Redis中特定的key,如下所示

# 查詢所有的key
keys *
# 查詢以book為前綴的key
keys book*

keys命令的復雜度是O(n),它會遍歷這個dict中的所有key,如果Redis中存的key非常多,所有讀寫Redis的指令都會被延遲等待,所以千萬不用在生產環境用這個命令(如果你已經準備離職的話,祝你玩的開心)。

「既然不讓你用keys,肯定有替代品,那就是scan」

scan是通過游標逐步遍歷的,因此不會長時間阻塞Redis

「用用zscan遍歷zset,hscan遍歷hash,sscan遍歷set的原理和scan命令類似,因為hash,set,zset的底層實現的數據結構中都有dict。」

操作bigkey

「如果一個key對應的value非常大,那么這個key就被稱為bigkey。寫入bigkey在分配內存時需要消耗更長的時間。同樣,刪除bigkey釋放內存也需要消耗更長的時間」

如果在慢日志中發現了SET/DEL這種復雜度不高的命令,此時你就應該排查一下是否是由于寫入bigkey導致的。

「如何定位bigkey?」

Redis提供了掃描bigkey的命令

$ redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

...
-------- summary -------

Sampled 829675 keys in the keyspace!
Total key length in bytes is 10059825 (avg len 12.13)

Biggest string found 'key:291880' has 10 bytes
Biggest list found 'mylist:004' has 40 items
Biggest set found 'myset:2386' has 38 members
Biggest hash found 'myhash:3574' has 37 fields
Biggest zset found 'myzset:2704' has 42 members

36313 strings with 363130 bytes (04.38% of keys, avg size 10.00)
787393 lists with 896540 items (94.90% of keys, avg size 1.14)
1994 sets with 40052 members (00.24% of keys, avg size 20.09)
1990 hashs with 39632 fields (00.24% of keys, avg size 19.92)
1985 zsets with 39750 members (00.24% of keys, avg size 20.03)

可以看到命令的輸入有如下3個部分

  • 內存中key的數量,已經占用的總內存,每個key占用的平均內存
  • 每種類型占用的最大內存,已經key的名字
  • 每種數據類型的占比,以及平均大小

這個命令的原理就是redis在內部執行了scan命令,遍歷實例中所有的key,然后正對key的類型,分別執行strlen,llen,hlen,scard,zcard命令,來獲取string類型的長度,容器類型(list,hash,set,zset)的元素個數

使用這個命令需要注意如下兩個問題

  • 對線上實例進行bigkey掃描時,為避免ops(operation per second 每秒操作次數)突增,可以通過-i增加一個休眠參數,上面的含義為,每隔100條scan指令就會休眠0.01s
  • 對于容器類型(list,hash,set,zset),掃描出的是元素最多的key,但一個key的元素數量多,不一定代表占用的內存多

「如何解決bigkey帶來的性能問題?」

  • 盡量避免寫入bigkey
  • 如果使用的是redis4.0以上版本,可以用unlink命令代替del,此命令可以把釋放key內存的操作,放到后臺線程中去執行
  • 如果使用的是redis6.0以上版本,可以開啟lazy-free機制(lazyfree-lazy-user-del yes),執行del命令的時候,也會放到后臺線程中去執行

大量key集中過期

我們可以給Redis中的key設置過期時間,那么當key過期了,它在什么時候會被刪除呢?

「如果讓我們寫Redis過期策略,我們會想到如下三種方案」

  • 定時刪除,在設置鍵的過期時間的同時,創建一個定時器。當鍵的過期時間來臨時,立即執行對鍵的刪除操作
  • 惰性刪除,每次獲取鍵的時候,判斷鍵是否過期,如果過期的話,就刪除該鍵,如果沒有過期,則返回該鍵
  • 定期刪除,每隔一段時間,對鍵進行一次檢查,刪除里面的過期鍵 定時刪除策略對CPU不友好,當過期鍵比較多的時候,Redis線程用來刪除過期鍵,會影響正常請求的響應

定時刪除策略對CPU不友好,當過期鍵比較多的時候,Redis線程用來刪除過期鍵,會影響正常請求的響應

惰性刪除讀CPU是比較有好的,但是會浪費大量的內存。如果一個key設置過期時間放到內存中,但是沒有被訪問到,那么它會一直存在內存中

定期刪除策略則對CPU和內存都比較友好

redis過期key的刪除策略選擇了如下兩種

  • 惰性刪除
  • 定期刪除

「惰性刪除」 客戶端在訪問key的時候,對key的過期時間進行校驗,如果過期了就立即刪除

「定期刪除」 Redis會將設置了過期時間的key放在一個獨立的字典中,定時遍歷這個字典來刪除過期的key,遍歷策略如下

  • 每秒進行10次過期掃描,每次從過期字典中隨機選出20個key
  • 刪除20個key中已經過期的key
  • 如果過期key的比例超過1/4,則進行步驟一
  • 每次掃描時間的上限默認不超過25ms,避免線程卡死

「因為Redis中過期的key是由主線程刪除的,為了不阻塞用戶的請求,所以刪除過期key的時候是少量多次」。源碼可以參考expire.c中的activeExpireCycle方法

  • 為了避免主線程一直在刪除key,我們可以采用如下兩種方案
  • 給同時過期的key增加一個隨機數,打散過期時間,降低清除key的壓力

如果你使用的是redis4.0版本以上的redis,可以開啟lazy-free機制(lazyfree-lazy-expire yes),當刪除過期key時,把釋放內存的操作放到后臺線程中執行

內存達到上限,觸發淘汰策略

Redis是一個內存數據庫,當Redis使用的內存超過物理內存的限制后,內存數據會和磁盤產生頻繁的交換,交換會導致Redis性能急劇下降。所以在生產環境中我們通過配置參數maxmemoey來限制使用的內存大小。

當實際使用的內存超過maxmemoey后,Redis提供了如下幾種可選策略。

「Redis的淘汰策略也是在主線程中執行的。但內存超過Redis上限后,每次寫入都需要淘汰一些key,導致請求時間變長」

可以通過如下幾個方式進行改善

  • 增加內存或者將數據放到多個實例中
  • 淘汰策略改為隨機淘汰,一般來說隨機淘汰比lru快很多
  • 避免存儲bigkey,降低釋放內存的耗時

寫AOF日志的方式為always

Redis的持久化機制有RDB快照和AOF日志,每次寫命令之后后,Redis提供了如下三種刷盤機制

「當aof的刷盤機制為always,redis每處理一次寫命令,都會把寫命令刷到磁盤中才返回,整個過程是在Redis主線程中進行的,勢必會拖慢redis的性能」

當aof的刷盤機制為everysec,redis寫完內存后就返回,刷盤操作是放到后臺線程中去執行的,后臺線程每隔1秒把內存中的數據刷到磁盤中

當aof的刷盤機制為no,宕機后可能會造成部分數據丟失,一般不采用。

「一般情況下,aof刷盤機制配置為everysec即可」

fork耗時過長

在持久化一節中,我們已經提到「Redis生成rdb文件和aof日志重寫,都是通過主線程fork子進程的方式,讓子進程來執行的,主線程的內存越大,阻塞時間越長?!?/p>

可以通過如下方式優化

  • 控制Redis實例的內存大小,盡量控制到10g以內,因為內存越大,阻塞時間越長
  • 配置合理的持久化策略,如在slave節點生成rdb快照

使用swap分區

當機器的內存不夠時,操作系統會將部分內存的數據置換到磁盤上,這塊磁盤區域就是Swap分區,當應用程序再次訪問這些數據的時候,就需要從磁盤上讀取,導致性能嚴重下降

「當Redis性能急劇下降時就有可能是數據被換到Swap分區,我們該如何排查Redis數據是否被換到Swap分區呢?」

# 先找到redis-server的進程id
ps -ef | grep redis-server

# 查看redis swap的使用情況
cat /proc/$pid/smaps | egrep '^(Swap|Size)'
[root@VM-0-14-centos ~]# cat /proc/2370/smaps | egrep '^(Swap|Size)'
Size: 1568 kB
Swap: 0 kB
Size: 8 kB
Swap: 0 kB
Size: 24 kB
Swap: 0 kB
Size: 2200 kB
Swap: 0 kB

每一行Size表示Redis所用的一塊內存大小,Size下面的Swap表示這塊大小的內存,有多少已經被換到磁盤上了,如果這2個值相等,說明這塊內存的數據都已經被換到磁盤上了

我們可以通過如下方式來解決

  • 增加機器內存
  • 整理內存碎片

最后我們總結一下Redis的慢操作

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2023-10-16 23:12:02

Redis數據結構

2018-09-13 09:42:30

數據庫Redis慢查詢

2022-02-09 15:36:49

Redis主從模式哨兵模式

2010-06-18 12:37:04

SQL Server查

2014-01-21 09:29:45

國產操作系統操作系統

2013-05-07 14:05:53

2010-06-10 09:54:54

MySQL編碼

2010-07-27 09:09:07

JDBC連接DB2

2010-08-13 13:31:14

DB2編程序

2019-06-26 09:10:07

操作系統調度算法

2024-10-25 16:31:17

Redis數據預處理線程

2024-09-10 12:15:24

2024-02-06 10:31:15

Redis工具運維

2019-12-24 17:05:56

CIO正版化Office

2020-04-26 17:04:18

Python代碼數據

2020-08-14 09:11:29

RedisQPS數據庫

2023-06-28 15:49:35

2024-12-30 08:32:36

2023-05-06 08:09:37

Redis命令服務器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 伊人天堂网 | 国产在线视频一区二区 | 一区二区在线不卡 | 91视频88av | 老子午夜影院 | 精品久久久久久中文字幕 | 国产成人精品午夜视频免费 | 日韩成人高清在线 | 亚洲视频在线观看 | 免费午夜剧场 | 日韩av电影院 | 日本一本在线 | 一级做a爰片性色毛片视频停止 | www国产成人免费观看视频 | www.亚洲一区二区三区 | 亚洲区在线 | 亚洲福利在线观看 | 久久久久成人精品亚洲国产 | 亚洲精品久久久久久下一站 | 欧美a在线| 日韩欧美在线观看视频 | 成人精品国产免费网站 | 97伊人| 人人99| 国产国语精品 | 自拍第一页 | 一区二区播放 | 欧美久久久久久久久中文字幕 | 国产精品日日做人人爱 | 青青草华人在线视频 | 亚洲欧美日韩中文字幕一区二区三区 | 久久在线视频 | 人成久久 | 性色的免费视频 | 亚洲精品在线免费观看视频 | 国产成人免费网站 | 亚洲福利片 | 在线成人av| 国产欧美一区二区三区在线看 | 丝袜天堂| 欧美一级毛片免费观看 |