背景
Redis作為目前全球最流行的KV存儲,除了使用之外,還需要做好日常的運維工作。關於運維相關的工作,本文從以下方面進行介紹說明(Redis5.0以上):
- 內存方面
- 客戶端連接方面
- 工具方面
說明
內存方面
說明:第一個值是memory stats提供,第二個值是info memory提供
-
服務內存相關(單位:字節)
- 消耗的最大峰值內存
peak.allocated
used_memory_peak - 最大分配使用內存
total.allocated used_memory - 啟動時消耗的初始內存
startup.allocated used_memory_startup - 復制積壓的內存
replication.backlog repl_backlog_size
- 數據占用內存
dataset.bytes used_memory_dataset - 管理內部數據結構的所有開銷的內存
-- 包括startup.allocated, replication.backlog, clients.slaves, clients.normal, aof.buffer及用於管理Redis鍵空間的內部數據結構的總和 overhead.total used_memory_overhead
- 當前和重寫AOF緩沖區內存
aof.buffer mem_aof_buffer - 所有副本開銷(輸出和查詢緩沖區,連接上下文)的總內存
clients.slaves mem_clients_slaves - 所有客戶端開銷(輸出和查詢緩沖區,連接上下文)的總內存
clients.normal mem_clients_normal - Lua腳本的緩存開銷的總內存
lua.caches used_memory_lua - 服務內存占用物理內存比例
rss-overhead.ratio rss_overhead_ratio
更多內存相關的可以看memory stats和info memory
-
Key內存相關:查看單個key的大小
-
命令行查看
① DEBUG OBJECT(redis4.0之前)命令估算key的內存使用(字段serializedlength),但因為相差太大,參考價值不高> get b "cbd" > DEBUG OBJECT b Value at:0x7f24e2b33d40 refcount:1 encoding:embstr serializedlength:4 lru:445248 lru_seconds_idle:3
② MEMORY USAGE [SAMPLES count](redis4.0之后)命令估算key的value實際使用內存,不包含key的大小和過期屬性的內存占用
> get b "cbd" > MEMORY USAGE b (integer) 48
對於集合的數據類型(除string外), usage子命令采用類似LRU SAMPLES的抽樣方式,默認抽樣5個(count)元素求平均得出實際內存占用,所以計算是近似值。可以指定抽樣的SAMPLES個數,如:生成一個100w個字段的hash鍵:hkey, 每字段的value長度是從1~1024字節的隨機值:
> hlen hkey // hkey有100w了字段,每個字段的value長度介入1~1024個字節 (integer) 1000000 > MEMORY usage hkey //默認SAMPLES為5,分析hkey鍵內存占用521588753字節 (integer) 521588753 > MEMORY usage hkey SAMPLES 1000 //指定SAMPLES為1000,分析hkey鍵內存占用617977753字節 (integer) 617977753 > MEMORY usage hkey SAMPLES 10000 //指定SAMPLES為10000,分析hkey鍵內存占用624950853字節 (integer) 624950853
這是使用抽樣求平均的算法,要想獲取key較精確的內存值,就指定更大SAMPLES個數。但並不越大越好,因為memory usage越大其占用cpu時間分片就大。SAMPLES 為0則會對所有值進行采樣。memory usage時間復雜度,和指定的SAMPLES數有關。
- rdb工具分析rdb文件,獲得某個key的實際使用內存
Redis RDB 分析工具 rdbtools 說明
客戶端連接方面
說明:client 是一個客戶端的操作方法,可以查看當前ID、當前連接信息等,具體的命令可以看官網
> client help 1) CLIENT <subcommand> arg arg ... arg. Subcommands are: -- 返回當前的連接ID,可用於kill 2) ID -- Return the ID of the current connection. -- 返回當前連接的名字 3) GETNAME -- Return the name of the current connection. -- Kill 來自某個地址的連接 4) KILL <ip:port> -- Kill connection made from <ip:port>. -- Kill 連接 5) KILL <option> <value> [option value ...] -- Kill connections. Options are: -- Kill 來自某個地址的連接 6) ADDR <ip:port> -- Kill connection made from <ip:port> -- 按類型Kill連接 7) TYPE (normal|master|replica|pubsub) -- Kill connections by type. -- Kill通過該用戶身份驗證的連接 8) USER <username> -- Kill connections authenticated with such user. -- 跳過Kill當前連接,默認yes 9) SKIPME (yes|no) -- Skip killing current connection (default: yes). -- 返回客戶端連接的信息 10) LIST [options ...] -- Return information about client connections. Options: -- 返回指定類型的客戶端 11) TYPE (normal|master|replica|pubsub) -- Return clients of specified type. -- 暫停所有客戶端<timout>毫秒 12) PAUSE <timeout> -- Suspend all Redis clients for <timout> milliseconds. -- 控制服務器對當前客戶端的回復,ON:默認,回復;OFF:不回復客;SKIP:跳過回復 13) REPLY (on|off|skip) -- Control the replies sent to the current connection. -- 給當前連接設置名字 14) SETNAME <name> -- Assign the name <name> to the current connection. -- 取消指定的被阻止的客戶端 15) UNBLOCK <clientid> [TIMEOUT|ERROR] -- Unblock the specified blocked client. -- 客戶端緩存啟用key跟蹤 16) TRACKING (on|off) [REDIRECT <id>] [BCAST] [PREFIX first] [PREFIX second] [OPTIN] [OPTOUT]... -- Enable client keys tracking for client side caching. -- 啟用跟蹤時,返回重定向到的客戶端ID 17) GETREDIR -- Return the client ID we are redirecting to when tracking is enabled. -- 啟用跟蹤時,控制在連接執行的下一個命令中對鍵的跟蹤(在連接中設置一個狀態,該狀態僅對下一個命令執行有效) 18) CACHING (YES|NO) -- Basically the command sets a state in the connection, that is valid only for the next command execution, that will modify the behavior of client tracking.
- CLIENT ID:返回當前連接的ID
-- ID值單調遞增,不重復 > CLIENT ID (integer) 701
- CLIENT GETNAME:返回當前連接由
CLIENT SETNAME設置的名字
> CLIENT GETNAME "zjy"
- CLIENT SETNAME:為當前連接分配一個名字
-- client list 中的name會顯示 > CLIENT SETNAME zjy OK
CLIENT LIST:返回所有連接到服務器的客戶端信息和統計數據
-- 返回所有 > CLIENT LIST id=701 addr=192.168.163.134:52722 fd=16 name=zjy age=1225 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client user=default id=598 addr=192.168.163.134:36327 fd=12 name= age=9321 idle=1 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=replconf user=replica-user id=703 addr=192.168.163.1:64583 fd=9 name= age=115 idle=81 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=auth user=dba -- 返回指定類型:normal|master|replica|pubsub > CLIENT LIST type replica id=598 addr=192.168.163.134:36327 fd=12 name= age=9341 idle=0 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=replconf user=replica-user -- 返回指定類型:normal|master|replica|pubsub > CLIENT LIST type normal id=701 addr=192.168.163.134:52722 fd=16 name=zjy age=1254 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=48 qbuf-free=32720 obl=0 oll=0 omem=0 events=r cmd=client user=default id=703 addr=192.168.163.1:64583 fd=9 name= age=144 idle=110 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=auth user=dba
格式如下:
1. 每個已連接客戶端對應一行(以 LF 分割) 2. 每行字符串由一系列 屬性=值(property=value) 形式的域組成,每個域之間以空格分開。
各字段的含義:
id: 唯一的客戶端ID addr: 客戶端的地址和端口 fd: 套接字所使用的文件描述符 age: 以秒計算的已連接時長 idle: 以秒計算的空閑時長 flags: 客戶端 flag: -- O: 客戶端是 MONITOR 模式下的附屬節點(slave) -- S: 客戶端是一般模式下(normal)的附屬節點 -- M: 客戶端是主節點(master) -- x: 客戶端正在執行事務 -- b: 客戶端正在等待阻塞事件 -- i: 客戶端正在等待 VM I/O 操作(已廢棄) -- d: 一個受監視(watched)的鍵已被修改, EXEC 命令將失敗 -- c: 在將回復完整地寫出之后,關閉鏈接 -- u: 客戶端未被阻塞(unblocked) -- U: 通過Unix套接字連接的客戶端 -- r: 客戶端是只讀模式的集群節點 -- A: 盡可能快地關閉連接 -- N: 未設置任何 flag db: 該客戶端正在使用的數據庫 ID sub: 已訂閱頻道的數量 psub: 已訂閱模式的數量 multi: 在事務中被執行的命令數量 qbuf: 查詢緩沖區的長度(字節為單位, 0 表示沒有分配查詢緩沖區) qbuf-free: 查詢緩沖區剩余空間的長度(字節為單位, 0 表示沒有剩余空間) obl: 輸出緩沖區的長度(字節為單位, 0 表示沒有分配輸出緩沖區) oll: 輸出列表包含的對象數量(當輸出緩沖區沒有剩余空間時,命令回復會以字符串對象的形式被入隊到這個隊列里) omem: 輸出緩沖區占用的內存總量
tot-mem:客戶端在其各種緩沖區中消耗的總內存 events: 文件描述符事件: -- r: 客戶端套接字(在事件 loop 中)是可讀的(readable) -- w: 客戶端套接字(在事件 loop 中)是可寫的(writeable) cmd: 最近一次執行的命令 user: 連接的用戶
注意:6.0之后多了tot-mem參數:客戶端在其各種緩沖區中消耗的總內存;而omem只表示了輸出緩沖的大小。
- CLIENT PAUSE:連接控制,可以將所有客戶端的訪問暫停給定的毫秒數(slaves的交互除外)
-- 所有客戶端暫停10秒 > CLIENT PAUSE 10000 OK
場景:
當需要升級一個實例時,管理員可以作如下操作: 使用CLIENT PAUSE 暫停所有客戶端 等待數秒,讓slaves節點處理完所有來自master的復制命令 將一個salve節點切換為master 重配客戶端以來接新的master 節點 CLIENT KILL:按不同的屬性關閉連接:如id,user、addr:port
-- list > client list id=598 addr=192.168.163.134:36327 fd=12 name= age=23517 idle=0 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=replconf user=replica-user id=801 addr=192.168.163.134:53810 fd=13 name= age=208 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client user=default id=803 addr=192.168.163.1:54934 fd=9 name= age=14 idle=14 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=auth user=dba id=804 addr=192.168.163.1:54935 fd=14 name= age=10 idle=7 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=client user=default -- 根據地址屬性kill > CLIENT KILL addr 192.168.163.1:54935 (integer) 1 -- 根據用戶kill > CLIENT KILL user dba (integer) 1 -- 根據連接類型kill > CLIENT KILL type normal (integer) 1 -- 是否kill當前操作的連接 > CLIENT KILL type normal SKIPME no (integer) 1
注意:Redis的單線程屬性,不可能在客戶端執行命令時殺掉它. 從客戶端的角度看,永遠無法殺死一個正在執行命令的連接。 但是當客戶端發送下一條命令時會意識到連接已被關,原因為網絡錯誤。
- CLIENT UNBLOCK:解除客戶端的阻塞
-- Connection A (blocking connection): > CLIENT ID 2934 > BRPOP key1 key2 key3 0 (client is blocked) ... Now we want to add a new key ... -- Connection B (control connection): > CLIENT UNBLOCK 2934 1 -- Connection A (blocking connection): ... BRPOP reply with timeout ... NULL > BRPOP key1 key2 key3 key4 0 (client is blocked again)
- CLIENT REPLY:是否禁用redis服務器對當前客戶端的回復響應
-- 控制服務器是否將回復客戶端的命令 ON. 默認選項,回復客戶端每條命令 OFF. 不回復客戶端命令 SKIP. 跳過該命令的回復 當執行命令設置為OFF或SKIP,設置命令收不到任何回復,當設置為 ON時,返回OK
- CLIENT TRACKING:啟用Redis服務器的跟蹤功能,該功能用於服務器的客戶端緩存
- CLIENT CACHING:當在OPTIN或OPTOUT模式下啟用跟蹤時,此命令控制在連接執行的下一個命令中對鍵的跟蹤
說明:客戶端緩存是Redis6.0的一個新功能,利用應用程序服務器中的可用內存,提高性能。CLIENT TRACKING 和CLIENT CACHING是針對客戶端緩存進行跟蹤和管理,如果對客戶端緩存有興趣的可以看官網說明。 - HELLO protover [AUTH username password] [SETNAME clientname]:切換協議(RESP2、RESP3)
-- Redis 6或更高版本支持兩種協議,即舊協議RESP2和新協議RESP3。Redis 6連接以RESP2模式啟動,因此RESP2的客戶端無需更改 想要握手RESP3模式的客戶端需要使用“ 3”作為第一個參數來調用HELLO命令。 > HELLO 3 auth dba dba setname zjy 1# "server" => "redis" 2# "version" => "6.0.3" 3# "proto" => (integer) 3 4# "id" => (integer) 825 5# "mode" => "cluster" 6# "role" => "master" 7# "modules" => (empty array)
- COMMAND:以數組的形式返回有關所有Redis命令的詳細信息
-
COMMAND COUNT:返回Redis服務器命令的總數
- COMMAND GETKEYS:從完整的Redis命令中找到key
-- 返回key > COMMAND GETKEYS MSET a b c d e f 1) "a" 2) "c" 3) "e" > COMMAND GETKEYS SORT mylist ALPHA STORE outlist 1) "mylist" 2) "outlist"
- COMMAND INFO command-name [command-name ...]:返回的結果與
COMMAND相同,但是你可以指定返回哪些命令
> COMMAND INFO get set 1) 1) "get" 2) (integer) 2 3) 1~ readonly 2~ fast 4) (integer) 1 5) (integer) 1 6) (integer) 1 7) 1~ @read 2~ @string 3~ @fast 2) 1) "set" 2) (integer) -3 3) 1~ write 2~ denyoom 4) (integer) 1 5) (integer) 1 6) (integer) 1 7) 1~ @write 2~ @string 3~ @slow
- CONFIG RESETSTAT:重置INFO命令統計里面的一些計算器
- DEBUG SEGFAULT:模擬錯誤,讓server崩潰
- LASTSAVE:查看BGSAVE 命令執行的結果,返回時間戳
> LASTSAVE (integer) 1594473834
- SLOWLOG subcommand [argument]:用於讀取和重置Redis慢查詢日志
實際執行命令所需的時間:在命令執行過程中線程被阻塞且不能同時處理其他請求的階段。
> config get *slow* 1) "slowlog-max-len" -- 慢查詢長度 2) "128" 3) "slowlog-log-slower-than" --慢查詢閾值時間,微妙 4) "10000" > SLOWLOG get 3 -- 查看慢查詢記錄條數 (empty array) > SLOWLOG len -- 獲取慢查詢長度 (integer) 0 > SLOWLOG reset -- 重置慢查詢日志 OK
工具方面
redis-cli --help
# /usr/local/redis6.0/bin/redis-cli -h 192.168.163.134 -p 8379 --help redis-cli 6.0.3 Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]] -- 服務地址 -h <hostname> Server hostname (default: 127.0.0.1). -- 服務端口 -p <port> Server port (default: 6379). -- 服務套接字 -s <socket> Server socket (overrides hostname and port). -- 服務密碼 -a <password> Password to use when connecting to the server. You can also use the REDISCLI_AUTH environment variable to pass this password more safely (if both are used, this argument takes predecence). -- ACL設置的用戶 --user <username> Used to send ACL style 'AUTH username pass'. Needs -a. -- ACL設置的密碼 --pass <password> Alias of -a for consistency with the new --user option. -- 強制設置密碼 --askpass Force user to input password with mask from STDIN. If this argument is used, '-a' and REDISCLI_AUTH environment variable will be ignored. -- 服務URI -u <uri> Server URI. -- 指定執行的命令次數 -r <repeat> Execute specified command N times. -- 間隔多少秒執行指定的命令 -i <interval> When -r is used, waits <interval> seconds per command. It is possible to specify sub-second times like -i 0.1. -- 數據庫號 -n <db> Database number. -- RESP協議 -3 Start session in RESP3 protocol mode. -- 讀取標准輸入的最后一個參數 -x Read last argument from STDIN. -- 分隔符,默認\n -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \n). -- 開啟集群模式 -c Enable cluster mode (follow -ASK and -MOVED redirections). -- 回復請求格式 --raw Use raw formatting for replies (default when STDOUT is not a tty). -- 格式化輸出 --no-raw Force formatted output even when STDOUT is not a tty. -- 導出格式 --csv Output in CSV format. -- 打印服務器的統計數據 --stat Print rolling stats about server: mem, clients, ... -- 持續采樣延遲模式,在交互式會話中使用此模式,顯示實時統計信息。 如果指定了--raw或--csv,或者將輸出重定向到非TTY,則它將對延遲進行采樣1秒鍾(可以使用-i更改間隔),然后生成單個輸出並退出 --latency Enter a special mode continuously sampling latency. If you use this mode in an interactive session it runs forever displaying real-time stats. Otherwise if --raw or --csv is specified, or if you redirect the output to a non TTY, it samples the latency for 1 second (you can use -i to change the interval), then produces a single output and exits. -- 像--latency一樣,但是跟蹤延遲隨時間變化。 默認時間間隔是15秒。 使用-i進行更改。 --latency-history Like --latency but tracking latency changes over time. Default time interval is 15 sec. Change it using -i. -- 將延遲顯示為頻譜,需要xterm 256色。 默認時間間隔是1秒。 使用-i進行更改。 --latency-dist Shows latency as a spectrum, requires xterm 256 colors. Default time interval is 1 sec. Change it using -i. -- 模擬工作負載 --lru-test <keys> Simulate a cache workload with an 80-20 distribution. -- 模擬從主接收到的命令的副本 --replica Simulate a replica showing commands received from the master. -- 將遠程服務的RDB轉存到本地 --rdb <filename> Transfer an RDB dump from remote server to local file. -- 將原始Redis協議從stdin傳輸到服務器 --pipe Transfer raw Redis protocol from stdin to server. -- pipe模式下的超時時間,默認30秒。 --pipe-timeout <n> In --pipe mode, abort with error if after sending all data. no reply is received within <n> seconds. Default timeout: 30. Use 0 to wait forever. -- 查找具有每個類型最多元素的key --bigkeys Sample Redis keys looking for keys with many elements (complexity). -- 查找每個類型消耗大量內存的key --memkeys Sample Redis keys looking for keys consuming a lot of memory. -- 定義要采樣的key元素的數量 --memkeys-samples <n> Sample Redis keys looking for keys consuming a lot of memory. And define number of key elements to sample -- 查找熱key,在maxmemory-policy為* lfu時有效 --hotkeys Sample Redis keys looking for hot keys. only works when maxmemory-policy is *lfu. -- 使用SCAN命令列出所有鍵 --scan List all keys using the SCAN command. -- 與scan一起使用以指定掃描模式 --pattern <pat> Useful with --scan to specify a SCAN pattern. -- 運行測試以測量內部系統延遲,測試將運行指定的秒數。 --intrinsic-latency <sec> Run a test to measure intrinsic system latency. The test will run for the specified amount of seconds. -- 使用<file>處的Lua腳本發送EVAL命令 --eval <file> Send an EVAL command using the Lua script at <file>. -- 與--eval一起使用,啟用Redis Lua調試器 --ldb Used with --eval enable the Redis Lua debugger. -- 與--ldb一樣,但使用同步Lua調試器,在這種模式下,服務器被阻止,腳本更改不會從服務器內存中回滾 --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in this mode the server is blocked and script changes are not rolled back from the server memory. -- 集群管理 --cluster <command> [args...] [opts...] Cluster Manager command and arguments (see below). -- 詳細模式 --verbose Verbose mode. -- 命令行界面上使用密碼時,不顯示警告消息 --no-auth-warning Don't show warning message when using password on command line interface. --help Output this help and exit. --version Output version and exit. Cluster Manager Commands: Use --cluster help to list all available cluster manager commands. -- 示例 Examples: cat /etc/passwd | redis-cli -x set mypasswd redis-cli get mypasswd redis-cli -r 100 lpush mylist x redis-cli -r 100 -i 1 info | grep used_memory_human: redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3 redis-cli --scan --pattern '*:12345*' (Note: when using --eval the comma separates KEYS[] from ARGV[] items) When no command is given, redis-cli starts in interactive mode. Type "help" in interactive mode for information on available commands and settings.
注意的參數:
1:--pipe echo -e "*3\r\n\$3\r\nset\r\n\$8\r\nstring_a\r\n\$3\r\ndba\r\n" | /usr/local/redis6.0/bin/redis-cli -h 192.168.163.134 -p 9379 --pipe 等同於 echo -e "*3\r\n\$3\r\nset\r\n\$8\r\nstring_a\r\n\$3\r\ndba\r\n" | nc 127.0.0.1 15391 2:--bigkeys 使用scan方式對每個類型的key進行統計,無需擔心對redis造成阻塞,最大key只有string類型是以字節長度為衡量標准的。list,set,zset等都是以元素個數作為衡量標准,不能說明其占的內存就一定多 3:--memkeys 查找每個類型消耗大量內存的key 4:--hotkeys 需要用LFU才能使用 5:--rdb 導出遠程的rdb到本地 6:--scan 遍歷所有的key 7:--raw 使用原始格式 8:--cluster 集群操作
總結
本文大致說明了平時運維的時候需要注意的一些事情,比如內存、連接、rdb、key等,后續如果有一些tips,會持續更新到本文當中。
