《Redis性能問題排查解決手冊》
《Redis的基本操作以及info命令》
《redis object命令》
《清理 redis 死鍵》
1.redis登錄
redis-cli -h 127.0.0.1 -p 6377
2. Redis 配置文件位置查詢
在redis內部執行命令: CONFIG GET *
一般情況下配置文件叫:redis.conf
3. 查詢Redis進程
ps -ef | grep redis-server 可以查看 redis進程,以及可以查看到安裝路徑等信息
4. redis key值獲取
keys * 獲取當前數據下所有KEY值
get key
select 2 切換到第二個數據庫
5. info命令
轉自:http://www.runoob.com/redis/server-info.html
info server : 一般 Redis 服務器信息,包含以下域:
- redis_version : Redis 服務器版本
- redis_git_sha1 : Git SHA1
- redis_git_dirty : Git dirty flag
- os : Redis 服務器的宿主操作系統 arch_bits : 架構(32 或 64 位)
- multiplexing_api : Redis 所使用的事件處理機制
- gcc_version : 編譯 Redis 時所使用的 GCC 版本
- process_id : 服務器進程的 PID
- run_id : Redis 服務器的隨機標識符(用於 Sentinel 和集群)
- tcp_port : TCP/IP 監聽端口 uptime_in_seconds : 自 Redis 服務器啟動以來,經過的秒數
- uptime_in_days : 自 Redis 服務器啟動以來,經過的天數
- lru_clock : 以分鍾為單位進行自增的時鍾,用於 LRU 管理
info clients 表示已連接客戶端信息 包含以下內容:
- connected_clients 已連接客戶端的數量(不包括通過從屬服務器連接的客戶端)
- client_longest_output_list 當前連接的客戶端當中,最長的輸出列表
- client_longest_input_buf 當前連接的客戶端當中,最大輸入緩存
- blocked_clients 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客戶端的數量
info cpu CPU 計算量統計信息
info mem 內存信息,包含以下:
- used_memory : 由 Redis 分配器分配的內存總量,以字節(byte)為單位
- used_memory_human : 以人類可讀的格式返回 Redis 分配的內存總量
- used_memory_rss : 從操作系統的角度,返回 Redis 已分配的內存總量(俗稱常駐集大小)。這個值和 top 、 ps 等命令的輸出一致。
- used_memory_peak : Redis 的內存消耗峰值(以字節為單位)
- used_memory_peak_human : 以人類可讀的格式返回 Redis 的內存消耗峰值
- used_memory_lua : Lua 引擎所使用的內存大小(以字節為單位)
- mem_fragmentation_ratio : used_memory_rss 和 used_memory 之間的比率 內存碎片率
- mem_allocator : 在編譯時指定的, Redis 所使用的內存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。
在理想情況下, used_memory_rss 的值應該只比 used_memory 稍微高一點兒。
當 rss > used ,且兩者的值相差較大時,表示存在(內部或外部的)內存碎片。
內存碎片的比率可以通過 mem_fragmentation_ratio 的值看出。
當 used > rss 時,表示 Redis 的部分內存被操作系統換出到交換空間了,在這種情況下,操作可能會產生明顯的延遲。--指標
當 Redis 釋放內存時,分配器可能會,也可能不會,將內存返還給操作系統。
如果 Redis 釋放了內存,卻沒有將內存返還給操作系統,那么 used_memory 的值可能和操作系統顯示的 Redis 內存占用並不一致。
查看 used_memory_peak 的值可以驗證這種情況是否發生
info persistence RDB 和 AOF 的相關信息
info stats : 一般統計信息
info replication : 主/從復制信息
info commandstats Redis 命令統計信息
info cluster Redis 集群信息
info keyspace redis 數據庫相關的統計信息
6. redis慢查詢語句
slow log get 10 慢查詢語句, 在上一個節中有講過
http://www.cnblogs.com/huamei2008/p/8850047.html
7.redis查詢延時
Redis-cli --latency
8. Redis自身性能壓測
命令:
redis-benchmark -p 6379 -c 20000 -n 50000
-h 表示IP
-p 表示端口
-c 表示連接數
-n表示請求數
-t 后面跟請求方式, 如get
9.scan命令
有時,我們需要針對符合條件的一部分命令進行操作,比如刪除以test_開頭的key。那么怎么獲取到這些key呢?在Redis2.8版本之前,我們可以使用keys命令按照正則匹配得到我們需要的key。但是這個命令有兩個缺點:
- 沒有limit,我們只能一次性獲取所有符合條件的key,如果結果有上百萬條,那么等待你的就是“無窮無盡”的字符串輸出。
- keys命令是遍歷算法,時間復雜度是O(N)。如我們剛才所說,這個命令非常容易導致Redis服務卡頓。因此,我們要盡量避免在生產環境使用該命令。
在滿足需求和存在造成Redis卡頓之間究竟要如何選擇呢?面對這個兩難的抉擇,Redis在2.8版本給我們提供了解決辦法——scan命令。
相比於keys命令,scan命令有兩個比較明顯的優勢:
- scan命令的時間復雜度雖然也是O(N),但它是分次進行的,不會阻塞線程。
- scan命令提供了limit參數,可以控制每次返回結果的最大條數。
這兩個優勢就幫助我們解決了上面的難題,不過scan命令也並不是完美的,它返回的結果有可能重復,因此需要客戶端去重。至於為什么會重復,相信你看完本文之后就會有答案了。
關於scan命令的基本用法,可以參看Redis命令詳解:Keys一文中關於SCAN命令的介紹。
今天我們主要從底層的結構和源碼的角度來討論scan是如何工作的。
Redis的結構
Redis使用了Hash表作為底層實現,原因不外乎高效且實現簡單。說到Hash表,很多Java程序員第一反應就是HashMap。沒錯,Redis底層key的存儲結構就是類似於HashMap那樣數組+鏈表的結構。其中第一維的數組大小為2n(n>=0)。每次擴容數組長度擴大一倍。
scan命令就是對這個一維數組進行遍歷。每次返回的游標值也都是這個數組的索引。limit參數表示遍歷多少個數組的元素,將這些元素下掛接的符合條件的結果都返回。因為每個元素下掛接的鏈表大小不同,所以每次返回的結果數量也就不同。
SCAN的遍歷順序
關於scan命令的遍歷順序,我們可以用一個小栗子來具體看一下。
127.0.0.1:6379> keys *
1) "db_number" 2) "key1" 3) "myKey" 127.0.0.1:6379> scan 0 MATCH * COUNT 1 1) "2" 2) 1) "db_number" 127.0.0.1:6379> scan 2 MATCH * COUNT 1 1) "1" 2) 1) "myKey" 127.0.0.1:6379> scan 1 MATCH * COUNT 1 1) "3" 2) 1) "key1" 127.0.0.1:6379> scan 3 MATCH * COUNT 1 1) "0" 2) (empty list or set)
我們的Redis中有3個key,我們每次只遍歷一個一維數組中的元素。如上所示,SCAN命令的遍歷順序是
0->2->1->3
這個順序看起來有些奇怪。我們把它轉換成二進制就好理解一些了。
00->10->01->11
我們發現每次這個序列是高位加1的。普通二進制的加法,是從右往左相加、進位。而這個序列是從左往右相加、進位的。這一點我們在redis的源碼中也得到印證。
在dict.c文件的dictScan函數中對游標進行了如下處理
v = rev(v); v++; v = rev(v);
意思是,將游標倒置,加一后,再倒置,也就是我們所說的“高位加1”的操作。
這里大家可能會有疑問了,為什么要使用這樣的順序進行遍歷,而不是用正常的0、1、2……這樣的順序呢,這是因為需要考慮遍歷時發生字典擴容與縮容的情況(不得不佩服開發者考慮問題的全面性)。
我們來看一下在SCAN遍歷過程中,發生擴容時,遍歷會如何進行。加入我們原始的數組有4個元素,也就是索引有兩位,這時需要把它擴充成3位,並進行rehash。
原來掛接在xx下的所有元素被分配到0xx和1xx下。在上圖中,當我們即將遍歷10時,dict進行了rehash,這時,scan命令會從010開始遍歷,而000和100(原00下掛接的元素)不會再被重復遍歷。
再來看看縮容的情況。假設dict從3位縮容到2位,當即將遍歷110時,dict發生了縮容,這時scan會遍歷10。這時010下掛接的元素會被重復遍歷,但010之前的元素都不會被重復遍歷了。所以,縮容時還是可能會有些重復元素出現的。