redis-cli是Redis的命令行接口,用来直接从终端发送命令给Redis并接受服务器的响应。
redis-cli有两个主要的运行模式:一个是交互式模式,用户输入命令并接受Redis的响应;另外一个模式下,命令被作为redis-cli的参数发送、执行并打印返回结果在标准控制台。
除了以上两种模式,有一些很有趣的模式,他们均是可以通过传递参数给redis-cli来实现的。所以它可以做一些 更重要的任务,如模仿一个slave打印从master中接受到的复制流、检查Redis服务器的隐藏信息、展示Redis的统计信息等。这篇文章将会从易到难逐步深入地介绍redis-cli的不同方面。
如果想要广泛地用Redis或者你已经在用,使用redis-cli会是一个好的机会。花点儿时间熟悉命令行工具是非常有用的,因为如果你对命令行接口比较熟悉后,你将会发现工作效率可以获得更好的提升。
命令行的使用范围
仅仅运行一个命令并将它的响应结果打印在标准输出上和将命令作为参数传给redis-cli一样简单:
bogon:~ yfangjun$ redis-cli incrby counter 100
(integer) 100
命令返回值实际上是"100",因为响应结果是被渲染在标准输出上的,所以你可以在货号中看到输出结果的类型,这个类型可以使Integer、strings、arrays、null、error等等。但是这并不是一个好的主意,尤其是当一个命令的输出作为另一个命令的输入、或者我们本就像直接将结果转储到文件中时。
事实上,只有在Redis检测到标准输出是一个ttl终端时,才会打印一些附件的信息以便提高可读性。否则,redis-cli自动设置为行输出模式,其效果如下:
bogon:~ yfangjun$ redis-cli incrby counter 100 >./out.txt
bogon:~ yfangjun$ cat out.txt
200
这次括号中的信息并未被打印出来,因为命令行接口发现这次输出不是在写到终端。不过,在结果输出到终端时可以强制行输出:
bogon:~ yfangjun$ redis-cli --raw incrby counter 100
300
类似地,可以禁用行输出:
bogon:~ yfangjun$ redis-cli --no-raw incrby counter 100 >out.tmp
bogon:~ yfangjun$ cat out.tmp
(integer) 400
主机地址、端口、密码和数据库
默认情况下redis-cli连接服务器地址为127.0.0.1,端口是6379。但是可以使用命令行选项非常方便地修改。-h被用来指定主机名或者ip地址,-p被用来指定端口号。
bogon:~ yfangjun$ redis-cli -h localhost -p 6379 dbsize
(integer) 2
如果Redis是密码保护的,-a
bogon:~ yfangjun$ redis-cli
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth redis
OK
127.0.0.1:6379> exit
bogon:~ yfangjun$ redis-cli -a redis
127.0.0.1:6379> keys *
(empty list or set)
如上所示,当在redis.conf用requirepass
最后,在执行写入数据时候,需要用-n
bogon:~ yfangjun$ redis-cli -a redis -n 1 incr a
(integer) 1
bogon:~ yfangjun$ redis-cli
127.0.0.1:6379> auth redis
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "a"
从其他程序中读取输入
有两种方法可以从别的程序读取输入(一般只标准输入)。第一种从标准输入读取,例如,我要将redis.conf的内容设置为键 redis-config的value:
bogon:~ yfangjun$ redis-cli -a redis -x set redis-config
如你所见,我们使用-x选项,并使用重定向符号<将文件redis.conf中的内容设置为redis-config的value,之后我们又使用get命令查看了执行情况,一切都如我们所预见的。这种方式对于批量的脚本任务执行是一个非常有用的方法。
另一种方法是,将命令写入一个文件,通过管道或者输入重定向符执行之:
bogon:~ yfangjun$ cat cmd.txt
auth redis
set foo 100
get foo
incr foo
get foo
append foo xxx
get foo
bogon:~ yfangjun$ cat cmd.txt |redis-cli
OK
OK
"100"
(integer) 101
"101"
(integer) 6
"101xxx"
cmd.txt中所有的命令被读入并一个接一个的一次执行。若是有必要,也可以在文件中使用引号。其中,命令之间用换行符隔开,命令参数之间用空格隔开。
连续不断的执行同一个命令
在shell中有一个命令是yes,它可以反复不断的向终端输出同样的信息。在redis-cl中也有一个类似好玩选项,它可以使cli在指定的时间内反复执行同一个命令,它的格式是-r -i :
bogon:~ yfangjun$ redis-cli -a redis flushall
676:M 29 Mar 15:06:22.813 * DB saved on disk
OK
bogon:~ yfangjun$ redis-cli -a redis -r 10 -i 10 incr foo
(integer) 1
(integer) 2
(integer) 3
(integer) 4
(integer) 5
(integer) 6
(integer) 7
(integer) 8
(integer) 9
(integer) 10
其中的count是指重复执行的次数,delay是重复执行的时间间隔,以秒计,默认是0。 如果想要永远不停的重复执行该命令,只需要将count的值设置为-1即可。
使用redis-cli批量插入数据
批量插入是一个非常值得研究的话题,并且也有许多指定的讨论的问题,仔细的研究可以看我的另外一篇文章《Redis批量插入》,其中包含了使用redis-cli工具和一些其他的一些方法的批量插入方法。
CSV格式输出
在有的时候,想要快速从Redis中导出一些数据,可以使用redis-cli工具的--csv选项完成。但是需要注意的是,这种方式并不能导出库中所有的数据,而仅仅是将单个命令的输出以CSV的格式输出。
bogon:~ yfangjun$ redis-cli -a redis --csv lrange mylist 0 -1
"d","c","b","a"
交互模式
到目前为止,我们一直都在探索将Redis CLI作为一个命令行程序。这对于测试和脚本化任务非常有用,但是更多的时候,我们都选择交互模式运行。
在交互模式下,用户根据用户根据提示键入命令,命令被发送到服务器端、执行并将响应解析渲染成特定的格式以便阅读,如下:
bogon:~ yfangjun$ redis-cli
127.0.0.1:6379> auth redis
OK
字符串127.0.0.1:6379>就是提示符,它会随着连接的服务器的变化而变化。当你需要在不同的数据库中执行操作时,可以使用select指令选择数据库:
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> dbsize
(integer) 0
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> dbsize
(integer) 1
Redis连接和重连接
在交互模式下,连接至别的数据库是允许的,并且当连接一个无法连接的数据库时,redis-cli进入未连接模式,以后每次执行命令时都会尝试重连。
127.0.0.1:6379> connect localhost 6379
localhost:6379> connect localhost 8888
Could not connect to Redis at localhost:8888: Connection refused
not connected> ping
Could not connect to Redis at localhost:8888: Connection refused
通常情况下,一旦被检测到失去连接,CLI总是会尝试重连:如果尝试失败,redis-cli将会打印错误信息并且进入未连接状态。当重连接成功后,redis-cli将自动选择进入失连钱最后一个数据库,除此之外,所有的其他连接信息均会丧失,如在执行事务时发生失连:
localhost:6379> multi
OK
localhost:6379> ping
QUEUED
localhost:6379> 676:M 29 Mar 16:39:03.155 # User requested shutdown...
676:M 29 Mar 16:39:03.155 * Saving the final RDB snapshot before exiting.
676:M 29 Mar 16:39:03.156 * DB saved on disk
676:M 29 Mar 16:39:03.156 # Redis is now ready to exit, bye bye...
localhost:6379> exec
Could not connect to Redis at localhost:6379: Connection refused
(重新启动Redis后)
not connected> exec
(error) ERR EXEC without MULTI
这在交互模式下做测试用并不是一个很重要的问题,但是需要时刻注意这点。
编辑、历史命令、自动补全
这些功能是与其他命令行工具一致的。
将一个命令执行N次
在命令前添加一个数字会使得该命令执行N次。
localhost:6379> 5 incr counter
(integer) 1
(integer) 2
(integer) 3
(integer) 4
(integer) 5
help命令
Redis有许多的命令,在你测试的时候或许记不清楚那么多的参数。redis-cli提供了大多数命令的在线帮助,那就是使用help命令,主要有以下两种格式:
1)help @,给出所有属于category种类的命令,这些category是以下的其中一种:@generic、@list、@hash、@set、@sorted_set、@string、@hyperloglog、@server、@connection、@scripting、@pubsub、@transactions。
2)help ,给出关于给定命令的用法。特别地,command给出所有的命令。
举个例子,给出pfadd命令的详细用法:
127.0.0.1:6379> help pfadd
PFADD key element [element ...]
summary: Adds the specified elements to the specified HyperLogLog.
since: 2.8.9
group: hyperloglog
redis-cli的清屏
使用clear命令,或者contol+l是其快捷键。特殊的connect在交互式下连接其他Redis。
一些特殊的模式
到目前为止,我们学习了两种模式:
1)交互式
2)在命令行直接运行
接下来我们讲学习其他的针对特殊用途的Redis的运行模式:
3)作为Redis服务器运行的监控,持续展示其统计信息
这恐怕是redis-cli的特性中最少为人知的了,但也是实时监视Redis运行实例的最有用的工具。可以使用
--stat开启该模式 ,它的输出非常简洁:
YoungdeMBP:~ yfangjun$ redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
1 985.77K 1 0 0 (+0) 2
1 985.77K 1 0 1 (+0) 2
1 985.77K 1 0 2 (+1) 2
1 985.77K 1 0 3 (+1) 2
运行这个命令时,默认每隔一秒钟会打印一行有用的信息,这个信息展示了此刻与上一个时间点的老数据的差别。可以用-i 更改时间间隔。从上面可以看到内存使用情况、客户端连接情况、阻塞情况等。
4)查看Redis中最长的keys
在这种模式下,redis-cli并用作keys空间分析器。它可以扫描数据集寻找最长的key,同时提供这个key所属数据类型的有用信息。
YoungdeMBP:~ yfangjun$ redis-cli --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
[00.00%] Biggest string found so far 'counter' with 3 bytes
-------- summary -------
Sampled 1 keys in the keyspace!
Total key length in bytes is 7 (avg len 7.00)
Biggest string found 'counter' has 3 bytes
1 strings with 3 bytes (100.00% of keys, avg size 3.00)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)
在输出的第一部分,每种数据类型中的最长的keys都被输出。总结部分提供了Redis中常规统计信息。进程使用了 scan命令,所以并不会影响服务器的正常运行。-i选项可以控制scan进程中每一秒钟每100个keys请求的扫描进度。
总结部分以一种简洁的格式输出了每次发现的最长的key。最开始的输出是提供了最近的有趣的信息。
5)通过模式匹配查看key空间
可以反复地扫描key空间而并不阻塞Redis服务器(使用keys *这样的命令是会发生阻塞的),并且打印所有的key的名称,或者啊按照匹配模式过滤它。这种模式,就像使用--bigkeys选项一样,使用的是scan命令,所以如果现在扫描到的key是迭代器的第一个key的话,它会可能打印多次如果数据集在变化,但是从不会发生key的丢失。
YoungdeMBP:~ yfangjun$ redis-cli --scan |head -7
bitstring
myset
mylist
user-1
myhyperloglog
counter
myset_sorted
--pattern这个选项可以用来过滤key的名称:
YoungdeMBP:~ yfangjun$ redis-cli --scan --pattern '*my*'
myset
mylist
myhyperloglog
myset_sorted
使用管道工具将其作为输入:
YoungdeMBP:~ yfangjun$ redis-cli --scan --pattern '*my*' |wc -l
4
6)作为一个pub/sub客户端
CLI可以使用publish命令向Pub/Sub通道发布消息。订阅这个通道可以接受发布的消息,在这种情况下,进程将会被阻塞等待消息,所以这种情况在redis-cli中被实现为另外的一个模式。不像其他的模式,它无法通过选择的方式开启,而是简单的使用subscribe和psubscribe命令,这在交互模式或者非交互模式下均是可以使用的,其中subscribe用来监听指定通道的消息,而psubscribe监听指定模式的通道,'*'表示监听所有的,我们进入pub/sub模式,然后在另外一个CLI实例发布通道消息:
YoungdeMBP:~ yfangjun$ redis-cli subscribe channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
1) "message"
2) "channel-1"
3) "hello,time"
1) "message"
2) "channel-1"
3) "good day"
127.0.0.1:6379> publish channel-1 hello,time
(integer) 1
127.0.0.1:6379> publish channel-1 good day
(error) ERR wrong number of arguments for 'publish' command
127.0.0.1:6379> publish channel-1 "good day"
(integer) 1
可以看得出,所有在channel-1中发布的消息均被接受到了。要退出这种模式,直接使用快捷键ctrl+c。
7)监视命令在Redis中的执行情况
与Pub/Sub模式类似,这种模式是当你使用monitor命令时自动进入的,而不需要使用选项开启。它将会打印自进入后所有的Redis接收到的命令,知道使用ctrl+c退出该模式:
YoungdeMBP:~ yfangjun$ redis-cli monitor
OK
1490813660.641238 [0 127.0.0.1:55182] "set" "foo" "bar"
1490813666.279520 [0 127.0.0.1:55182] "get" "foor"
1490813672.133449 [0 127.0.0.1:55182] "del" "foo"
1490813677.066599 [0 127.0.0.1:55182] "keys" "*"
8)检查Redis服务器延迟
Redis经常被用在非常危险的环境下,这些延迟源于很多动态变化的部分,从客户端函数库到网络堆栈甚至是Redis本身。CLI有多重的工具研究Redis实例的延迟,并且试着去理解其最大程度、平均程度以及分布情况,最基本的工具是使用--latency选项。使用该模式会启动一个循环一直向Redis发送ping命令,并估计响应的时间。ping命令每分钟发生100次,在控制台将会看到实时更新的统计信息:
YoungdeMBP:~ yfangjun$ redis-cli --latency
min: 0, max: 8, avg: 0.24 (20532 samples)
统计结果是以毫秒计算的,并且平均延迟总是被高估一个位因为内核调度器运行redis-cli本身的的缘故。所以0.24的平均延迟或许只有0.2甚至更低,但这并不重要,因为我们关心的是延迟更少或者更多的事件。
有时对于研究延迟的最大值或者平均值是如何变化的非常有用。选项--latterncy-history被用作这种目的:像
--latterncy一样,但是默认每隔15分钟才会选择样例:
YoungdeMBP:~ yfangjun$ redis-cli --latency-history
min: 0, max: 1, avg: 0.23 (516 samples)
最高级的延迟研究工具是谁用带颜色的终端工具表示延迟的光谱范围,但对于没有经验的用户来说是比较困难的。通过它的图谱看,不同的颜色代表不同的样例的百分比,不同的ASCII码表示不同的延迟数字,可以通过--latency-disk选项开启该模式:
9)检查宿主机延迟
还有一个非常聪明但是却不常用的工具,它不会去检查Redis实例的延迟,而是检测运行redis-cli的计算机的延迟。或许你想问什么是延迟?延迟的本质就是内核调度、就是超级管理程序的虚拟实例等等。
我们调用该工具分析延迟因为它通常是是对程序员不透明的。如果你的Redis因为忽略了显而易见的事情导致延迟过大,这应该就是源码本身造成的,这就需要在你的机器上运行该模式从而分析你的及其做的最好的方面。
通过测量这种内在的延迟,就可以知道你的及其最好能做到什么程度,因为它不可能好过这个极限。为了调运这个工具,需要使用--intrinsic-latency ,test-time指定应该花费多少时间检查你的电脑系统。
bogon:~ yfangjun$ redis-cli --intrinsic-latency 10
Max latency so far: 1 microseconds.
Max latency so far: 14 microseconds.
Max latency so far: 63 microseconds.
Max latency so far: 67 microseconds.
Max latency so far: 101 microseconds.
Max latency so far: 116 microseconds.
Max latency so far: 216 microseconds.
118904116 total runs (avg latency: 0.0841 microseconds / 841.01 nanoseconds per run).
Worst run took 2568x longer than the average latency.
重点是,这个命令测试的是Redis所在服务器的内在延迟,所以是在要安装Redis的计算机上运行,但是不需要连接Redis服务端。
在上面的例子中,我的电脑最坏情况下将会有216微妙的延迟,我可以确定运行一个查询会花费不会超过大约216微妙。
10)从用远程Redis服务器RDB备份数据到本地
在复制集的首次同步时,master和slave会以RDB文件的形式交换数据集。这个特性可以被用来提供一个远程的备份工具,通过redis-cli我们可以将任何Redis实例中的RDB文件被分到本地计算机上。要使用该功能,只需要指出rdb 选项:
bogon:~ yfangjun$ redis-cli --rdb ./dump.rdb
547:M 30 Mar 10:53:32.362 * Slave 127.0.0.1: asks for synchronization
547:M 30 Mar 10:53:32.362 * Starting BGSAVE for SYNC with target: disk
547:M 30 Mar 10:53:32.362 * Background saving started by pid 549
549:C 30 Mar 10:53:32.364 * DB saved on disk
547:M 30 Mar 10:53:32.458 * Background saving terminated with success
SYNC sent to master, writing 225 bytes to './dump.rdb'
547:M 30 Mar 10:53:32.458 * Synchronization with slave 127.0.0.1: succeeded
547:M 30 Mar 10:53:32.459 # Connection with slave 127.0.0.1: lost.
Transfer finished with success.
这个功能是复制集的功能,我的计算机只开了一个单独的实例,所以它将本机的rdb文件备份到了当前目录下。这个功能非常简单但是很有用,在实际使用时,要注意检查退出状态吗,如果不是0,一定是备份过程除了问题。
11)slave模式
slave模式是Redis开发和调试的CLI高级特性。它检查主从复制流中master传给slave的集体内容。这对于检查同步过程中的详细内容有很大的帮助。详细介绍放在下次的文章中。
12)评估LRU的工作量显示keys的命中情况
在我的之前的文章专门讨论了《Redis用作缓存服务器》,其中关于数据回收策略中提到LRU这种算法。b本节讨论redis-cli评估其命中情况。根据keys的数量和使用maxmemory指令分配的缓存的不同,缓存的命中率和不命中比率会有所不同。评估命中率对调整缓存配置非常有用。
CLI有一个特殊的模式可模拟get和set操作,发现在请求分配中遵循2-8定律,就是80%的请求都是发生在20%的keys中。
理论上讲,给出请求分配和内存的大小,就可以按照数学方式计算出命中率。但是Redis可以配置LRU算法中的取样大小和LRU算法的实现算法,这在不同版本的Redis中的变化并不太大。相似的是,每个key中的内存占有在每个版本的Redis中有小的差别。这就是构建这个工具的初衷:测量Redis中的LRU算法实现的高效性,但现在也常常用来测量同一个配置在不同版本中的表现。
在使用的时候,需要指出被用作测试的keys的数量。在第一次测试的时候,可以设置的大一些。Redis中的最大内存的配置是非常重要的,因为如果没有内存限制,命中率会达到100%,我们的研究就是去了既定的价值。如果配置非常多的测试key,而没有指定最大的内存,计算机的RAM将会被耗尽,同时,数据回收策略也是需要指定的,大多数情况下,我们都选择allkeys-lru。在下面的例子中,我配置了100MB的内存,并模拟1千万keys的执行情况:
bogon:~ yfangjun$ redis-cli --lru-test 10000000
547:M 30 Mar 11:32:03.693 * 100 changes in 300 seconds. Saving...
547:M 30 Mar 11:32:03.693 * Background saving started by pid 567
567:C 30 Mar 11:32:03.702 * DB saved on disk
547:M 30 Mar 11:32:03.793 * Background saving terminated with success
146750 Gets/sec | Hits: 4123 (2.81%) | Misses: 142627 (97.19%)
146000 Gets/sec | Hits: 11737 (8.04%) | Misses: 134263 (91.96%)
147250 Gets/sec | Hits: 18988 (12.90%) | Misses: 128262 (87.10%)
147000 Gets/sec | Hits: 25608 (17.42%) | Misses: 121392 (82.58%)
138000 Gets/sec | Hits: 29736 (21.55%) | Misses: 108264 (78.45%)
148500 Gets/sec | Hits: 38078 (25.64%) | Misses: 110422 (74.36%)
147750 Gets/sec | Hits: 43330 (29.33%) | Misses: 104420 (70.67%)
143250 Gets/sec | Hits: 47012 (32.82%) | Misses: 96238 (67.18%)
111250 Gets/sec | Hits: 39561 (35.56%) | Misses: 71689 (64.44%)
113750 Gets/sec | Hits: 40947 (36.00%) | Misses: 72803 (64.00%)
可以看到,一开始缓存一直在增加,在最后基本稳定,命中率基本固定在我们期望的大小。对于不命中的比率而言,64%是太高了,所以我们分配的内存是不够用的。在其他条件不变的情况下,我将maxmemory的值改为500MB,其结果如下:
22250 Gets/sec | Hits: 120036 (98.19%) | Misses: 2214 (1.81%)
118500 Gets/sec | Hits: 116317 (98.16%) | Misses: 2183 (1.84%)
122000 Gets/sec | Hits: 119738 (98.15%) | Misses: 2262 (1.85%)
116250 Gets/sec | Hits: 114122 (98.17%) | Misses: 2128 (1.83%)
112000 Gets/sec | Hits: 109963 (98.18%) | Misses: 2037 (1.82%)
106500 Gets/sec | Hits: 104563 (98.18%) | Misses: 1937 (1.82%)
115250 Gets/sec | Hits: 113134 (98.16%) | Misses: 2116 (1.84%)
122000 Gets/sec | Hits: 119732 (98.14%) | Misses: 2268 (1.86%)
114750 Gets/sec | Hits: 112580 (98.11%) | Misses: 2170 (1.89%)
上图是使用内存达到500MB这个我们设置的阈值后的命中情况,这个结果来看,我们的内存显然是够用的,Redis在这种配置下,其性能相当不错。
13)一个LUA脚本的调试器(略)