yanpenggong 大数据实验室

一个专注于科研前线的大数据团队,致力于打造更好更牛的大数据平台

0%

Redis教程

Redis教程
Author: yanpenggong       Email: yanpenggong@163.com
Github: kungs8      CSDN: https://blog.csdn.net/yanpenggong

[toc]

1. Linux 安装 Redis 并配置

1.1 下载,执行编译并安装

下载地址:http://redis.io/download,下载最新稳定版本。

本教程使用的最新文档版本为 6.2.6,下载并安装:

1
2
3
4
5
[root@localhost ~]# cd /opt/software/
[root@localhost software]# wget http://download.redis.io//releases/redis-6.2.6.tar.gz # 下载redis安装包
[root@localhost software]# tar -xzf redis-6.2.6.tar.gz # 下载redis安装包
[root@localhost software]# cd redis-6.2.6
[root@localhost redis-6.2.6]# make

注意

  1. 如果没有wget,则会报错,通过使用yum install wget 就行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    [root@localhost Redis_dir]# wget http://download.redis.io//releases/redis-6.2.6.tar.gz
    -bash: wget: 未找到命令
    [root@localhost Redis_dir]# yum install wget
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 wget.x86_64.0.1.14-18.el7_6.1 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    =======================================================================================================================
    Package 架构 版本 源 大小
    ============================================================================```=====================================
    正在安装:
    wget x86_64 1.14-18.el7_6.1 base 547 k

    事务概要
    =======================================================================================================================
    安装 1 软件包

    总下载量:547 k
    安装大小:2.0 M
    Is this ok [y/d/N]: y
    Downloading packages:
    wget-1.14-18.el7_6.1.x86_64.rpm | 547 kB 00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : wget-1.14-18.el7_6.1.x86_64 1/1
    验证中 : wget-1.14-18.el7_6.1.x86_64 1/1

    已安装:
    wget.x86_64 0:1.14-18.el7_6.1

    完毕!
    [root@localhost Redis_dir]#
  2. 系统缺少gcc环境的报错(安装Redis执行make命令时遇到此错误)

    问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    make[3]: cc:命令未找到
    make[3]: *** [alloc.o] 错误 127
    make[3]: 离开目录"/opt/software/redis-6.2.6/deps/hiredis"
    make[2]: *** [hiredis] 错误 2
    make[2]: 离开目录"/opt/software/redis-6.2.6/deps"
    make[1]: [persist-settings] 错误 2 (忽略)
    CC adlist.o
    /bin/sh: cc: 未找到命令
    make[1]: *** [adlist.o] 错误 127
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make: *** [all] 错误 2

    解决办法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    [root@localhost redis-6.2.6]# yum install gcc c++
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    没有可用软件包 c++。
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 gcc.x86_64.0.4.8.5-44.el7 将被 安装
    --> 正在处理依赖关系 cpp = 4.8.5-44.el7,它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在处理依赖关系 glibc-devel >= 2.2.90-12,它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在处理依赖关系 libmpfr.so.4()(64bit),它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在处理依赖关系 libmpc.so.3()(64bit),它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在检查事务
    ---> 软件包 cpp.x86_64.0.4.8.5-44.el7 将被 安装
    ---> 软件包 glibc-devel.x86_64.0.2.17-325.el7_9 将被 安装
    --> 正在处理依赖关系 glibc-headers = 2.17-325.el7_9,它被软件包 glibc-devel-2.17-325.el7_9.x86_64 需要
    --> 正在处理依赖关系 glibc-headers,它被软件包 glibc-devel-2.17-325.el7_9.x86_64 需要
    ---> 软件包 libmpc.x86_64.0.1.0.1-3.el7 将被 安装
    ---> 软件包 mpfr.x86_64.0.3.1.1-4.el7 将被 安装
    --> 正在检查事务
    ---> 软件包 glibc-headers.x86_64.0.2.17-325.el7_9 将被 安装
    --> 正在处理依赖关系 kernel-headers >= 2.2.1,它被软件包 glibc-headers-2.17-325.el7_9.x86_64 需要
    --> 正在处理依赖关系 kernel-headers,它被软件包 glibc-headers-2.17-325.el7_9.x86_64 需要
    --> 正在检查事务
    ---> 软件包 kernel-headers.x86_64.0.3.10.0-1160.62.1.el7 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    =======================================================================================================================
    Package 架构 版本 源 大小
    =======================================================================================================================
    正在安装:
    gcc x86_64 4.8.5-44.el7 base 16 M
    为依赖而安装:
    cpp x86_64 4.8.5-44.el7 base 5.9 M
    glibc-devel x86_64 2.17-325.el7_9 updates 1.1 M
    glibc-headers x86_64 2.17-325.el7_9 updates 691 k
    kernel-headers x86_64 3.10.0-1160.62.1.el7 updates 9.1 M
    libmpc x86_64 1.0.1-3.el7 base 51 k
    mpfr x86_64 3.1.1-4.el7 base 203 k

    事务概要
    =======================================================================================================================
    安装 1 软件包 (+6 依赖软件包)

    总下载量:33 M
    安装大小:60 M
    Is this ok [y/d/N]: r
    Is this ok [y/d/N]: y
    Downloading packages:
    (1/7): glibc-headers-2.17-325.el7_9.x86_64.rpm | 691 kB 00:00:00
    (2/7): glibc-devel-2.17-325.el7_9.x86_64.rpm | 1.1 MB 00:00:00
    (3/7): cpp-4.8.5-44.el7.x86_64.rpm | 5.9 MB 00:00:01
    (4/7): libmpc-1.0.1-3.el7.x86_64.rpm | 51 kB 00:00:00
    (5/7): mpfr-3.1.1-4.el7.x86_64.rpm | 203 kB 00:00:00
    (6/7): kernel-headers-3.10.0-1160.62.1.el7.x86_64.rpm | 9.1 MB 00:00:01
    (7/7): gcc-4.8.5-44.el7.x86_64.rpm | 16 MB 00:00:02
    -----------------------------------------------------------------------------------------------------------------------
    总计 11 MB/s | 33 MB 00:00:02
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : mpfr-3.1.1-4.el7.x86_64 1/7
    正在安装 : libmpc-1.0.1-3.el7.x86_64 2/7
    正在安装 : cpp-4.8.5-44.el7.x86_64 3/7
    正在安装 : kernel-headers-3.10.0-1160.62.1.el7.x86_64 4/7
    正在安装 : glibc-headers-2.17-325.el7_9.x86_64 5/7
    正在安装 : glibc-devel-2.17-325.el7_9.x86_64 6/7
    正在安装 : gcc-4.8.5-44.el7.x86_64 7/7
    验证中 : kernel-headers-3.10.0-1160.62.1.el7.x86_64 1/7
    验证中 : mpfr-3.1.1-4.el7.x86_64 2/7
    验证中 : glibc-devel-2.17-325.el7_9.x86_64 3/7
    验证中 : gcc-4.8.5-44.el7.x86_64 4/7
    验证中 : glibc-headers-2.17-325.el7_9.x86_64 5/7
    验证中 : libmpc-1.0.1-3.el7.x86_64 6/7
    验证中 : cpp-4.8.5-44.el7.x86_64 7/7

    已安装:
    gcc.x86_64 0:4.8.5-44.el7

    作为依赖被安装:
    cpp.x86_64 0:4.8.5-44.el7 glibc-devel.x86_64 0:2.17-325.el7_9
    glibc-headers.x86_64 0:2.17-325.el7_9 kernel-headers.x86_64 0:3.10.0-1160.62.1.el7
    libmpc.x86_64 0:1.0.1-3.el7 mpfr.x86_64 0:3.1.1-4.el7

    完毕!
    [root@localhost redis-6.2.6]#
  3. 安装好gcc 和c++ 后,必须清空后再编译,否则会报如下错误

    问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@localhost redis-6.2.6]# make
    cd src && make all
    make[1]: 进入目录"/opt/software/redis-6.2.6/src"
    CC Makefile.dep
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make[1]: 进入目录"/opt/software/redis-6.2.6/src"
    CC adlist.o
    In file included from adlist.c:34:0:
    zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录
    #include <jemalloc/jemalloc.h>
    ^
    编译中断。
    make[1]: *** [adlist.o] 错误 1
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make: *** [all] 错误 2
    [root@localhost redis-6.2.6]#

    解决办法:

    1
    2
    [root@localhost redis-6.2.6]# make distclean  # 清空上次编译失败残留文件
    [root@localhost redis-6.2.6]# make && make install # 执行编译及安装

执行完 make 命令后,redis-6.2.6 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli,两个程序位于安装目录 src 目录下。

1.2 启动Redis服务

下面启动 redis 服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost src]# cd src/
[root@localhost src]# ./redis-server ../redis.conf
7061:C 16 May 2022 12:09:22.469 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7061:C 16 May 2022 12:09:22.469 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=7061, just started
7061:C 16 May 2022 12:09:22.469 # Configuration loaded
7061:M 16 May 2022 12:09:22.470 * Increased maximum number of open files to 10032 (it was originally set to 1024).
7061:M 16 May 2022 12:09:22.470 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.6 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 7061
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

7061:M 16 May 2022 12:09:22.472 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
7061:M 16 May 2022 12:09:22.472 # Server initialized
7061:M 16 May 2022 12:09:22.472 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
7061:M 16 May 2022 12:09:22.472 * Ready to accept connections

redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。

启动 redis 服务进程后,就可以使用测试客户端程序( redis-cli )和 redis 服务交互了。 比如:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# cd /opt/software/redis-6.2.6/src
[root@localhost src]# ./redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379>

1.3 Redis 配置后台服务和访问密码

配置 Redis 为后台服务 将配置文件中的 daemonize no 改成 daemonize yes,配置 redis 为后台启动。

Redis 设置访问密码 在配置文件中找到 requirepass,去掉前面的注释,并修改后面的密码。

常用配置文件例子 redis.conf 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#默认端口6379
port 6379
#绑定ip,如果是内网可以直接绑定 127.0.0.1, 或者忽略, 0.0.0.0是外网
bind 0.0.0.0
#守护进程启动
daemonize yes
#超时
timeout 300
loglevel notice
#分区
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
#存储文件
dbfilename dump.rdb
#密码 abcd123
requirepass yanpenggong

修改protected-mode 参数,将其改为 protected-mode no。这样就可以解除redis的保护机制,可以被其他主机连接。

同时还要把对应的端口打开:

1
2
3
4
5
6
7
8
[root@localhost src]# firewall-cmd --query-port=6379/tcp  # 检测端口是否打开
no
[root@localhost src]# firewall-cmd --add-port=6379/tcp --permanent # 返回success说明开启成功,加permanent代表永久有效 不会因为重启防火墙失效
success
[root@localhost src]# firewall-cmd --reload # 配置立即生效
success
[root@localhost src]# firewall-cmd --query-port=6379/tcp # 查看防火墙开放的端口
yes
  1. 查看防火墙所有开放的端口

    1
    firewall-cmd --zone=public --list-ports
  2. 关闭端口

    1
    firewall-cmd --zone=public --remove-port=6379/tcp --permanent
  3. 关闭防火墙

    如果要开放的端口太多,嫌麻烦,可以关闭防火墙,安全性自行评估

    1
    systemctl stop firewalld.service
  4. 查看防火墙状态

    1
    2
    [root@localhost src]# firewall-cmd --state
    running
  5. 查看监听的端口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@localhost src]# netstat -lnpt
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
    tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 7293/./redis-server
    tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1062/sshd
    tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1237/master
    tcp6 0 0 ::1:6379 :::* LISTEN 7293/./redis-server
    tcp6 0 0 :::22 :::* LISTEN 1062/sshd
    tcp6 0 0 ::1:25 :::* LISTEN 1237/master

    linux命令报错信息:-bash: netstat: 未找到命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    [root@localhost src]# netstat -lnpt
    -bash: netstat: 未找到命令
    [root@localhost src]# yum -y install net-tools
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 net-tools.x86_64.0.2.0-0.25.20131004git.el7 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    =======================================================================================================================
    Package 架构 版本 源 大小
    =======================================================================================================================
    正在安装:
    net-tools x86_64 2.0-0.25.20131004git.el7 base 306 k

    事务概要
    =======================================================================================================================
    安装 1 软件包

    总下载量:306 k
    安装大小:917 k
    Downloading packages:
    net-tools-2.0-0.25.20131004git.el7.x86_64.rpm | 306 kB 00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1
    验证中 : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1

    已安装:
    net-tools.x86_64 0:2.0-0.25.20131004git.el7

    完毕!
    [root@localhost src]#
  6. 检查端口被哪个进程占用

    1
    2
    3
    4
    [root@localhost src]# netstat -lnpt |grep 6379
    tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 7293/./redis-server
    tcp6 0 0 ::1:6379 :::* LISTEN 7293/./redis-server
    [root@localhost src]#
  7. 查看进程的详细信息

    1
    2
    3
    4
    5
    6
    7
    [root@localhost src]# ps -ef | grep redis
    root 7293 1 0 14:23 ? 00:00:07 ./redis-server 127.0.0.1:6379
    root 7379 1390 0 14:41 pts/0 00:00:00 grep --color=auto redis
    [root@localhost src]# ps 7293
    PID TTY STAT TIME COMMAND
    7293 ? Ssl 0:07 ./redis-server 127.0.0.1:6379
    [root@localhost src]#
  8. 终止进程

    1
    kill -9 7293

2. Redis 配置

2.1 获取Redis 配置

在 Redis 中,Redis 的根目录中有一个配置文件(redis.conf)。您可以通过 Redis CONFIG 命令获取和设置所有 Redis 配置。

  1. 语法

    以下是 Redis CONFIG 命令的基本语法。

    1
    127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME
  2. 实例1: CONFIG GET loglevel

    1
    2
    3
    4
    127.0.0.1:6379> CONFIG GET "loglevel"
    1) "loglevel"
    2) "notice"
    127.0.0.1:6379>
  3. 实例2:CONFIG GET *

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    127.0.0.1:6379> CONFIG GET *
    1) "rdbchecksum"
    2) "yes"
    3) "daemonize"
    4) "yes"
    5) "io-threads-do-reads"
    6) "no"
    7) "lua-replicate-commands"
    8) "yes"
    9) "always-show-logo"
    10) "no"
    11) "protected-mode"
    12) "no"
    13) "rdbcompression"
    14) "yes"
    15) "rdb-del-sync-files"
    16) "no"
    17) "activerehashing"
    18) "yes"
    19) "stop-writes-on-bgsave-error"
    20) "yes"
    21) "set-proc-title"
    22) "yes"
    23) "dynamic-hz"
    24) "yes"
    25) "lazyfree-lazy-eviction"
    26) "no"
    27) "lazyfree-lazy-expire"
    28) "no"
    29) "lazyfree-lazy-server-del"
    30) "no"
    31) "lazyfree-lazy-user-del"
    32) "no"
    33) "lazyfree-lazy-user-flush"
    34) "no"
    35) "repl-disable-tcp-nodelay"
    36) "no"
    37) "repl-diskless-sync"
    38) "no"
    39) "gopher-enabled"
    40) "no"
    41) "aof-rewrite-incremental-fsync"
    42) "yes"
    43) "no-appendfsync-on-rewrite"
    44) "no"
    45) "cluster-require-full-coverage"
    46) "yes"
    47) "rdb-save-incremental-fsync"
    48) "yes"
    49) "aof-load-truncated"
    50) "yes"
    51) "aof-use-rdb-preamble"
    52) "yes"
    53) "cluster-replica-no-failover"
    54) "no"
    55) "cluster-slave-no-failover"
    56) "no"
    57) "replica-lazy-flush"
    58) "no"
    59) "slave-lazy-flush"
    60) "no"
    61) "replica-serve-stale-data"
    62) "yes"
    63) "slave-serve-stale-data"
    64) "yes"
    65) "replica-read-only"
    66) "yes"
    67) "slave-read-only"
    68) "yes"
    69) "replica-ignore-maxmemory"
    70) "yes"
    71) "slave-ignore-maxmemory"
    72) "yes"
    73) "jemalloc-bg-thread"
    74) "yes"
    75) "activedefrag"
    76) "no"
    77) "syslog-enabled"
    78) "no"
    79) "cluster-enabled"
    80) "no"
    81) "appendonly"
    82) "no"
    83) "cluster-allow-reads-when-down"
    84) "no"
    85) "crash-log-enabled"
    86) "yes"
    87) "crash-memcheck-enabled"
    88) "yes"
    89) "use-exit-on-panic"
    90) "no"
    91) "disable-thp"
    92) "yes"
    93) "cluster-allow-replica-migration"
    94) "yes"
    95) "replica-announced"
    96) "yes"
    97) "aclfile"
    98) ""
    99) "unixsocket"
    100) ""
    101) "pidfile"
    102) "/var/run/redis_6379.pid"
    103) "replica-announce-ip"
    104) ""
    105) "slave-announce-ip"
    106) ""
    107) "masteruser"
    108) ""
    109) "cluster-announce-ip"
    110) ""
    111) "syslog-ident"
    112) "redis"
    113) "dbfilename"
    114) "dump.rdb"
    115) "appendfilename"
    116) "appendonly.aof"
    117) "server_cpulist"
    118) ""
    119) "bio_cpulist"
    120) ""
    121) "aof_rewrite_cpulist"
    122) ""
    123) "bgsave_cpulist"
    124) ""
    125) "ignore-warnings"
    126) ""
    127) "proc-title-template"
    128) "{title} {listen-addr} {server-mode}"
    129) "masterauth"
    130) ""
    131) "requirepass"
    132) "yanpenggong"
    133) "supervised"
    134) "no"
    135) "syslog-facility"
    136) "local0"
    137) "repl-diskless-load"
    138) "disabled"
    139) "loglevel"
    140) "notice"
    141) "maxmemory-policy"
    142) "noeviction"
    143) "appendfsync"
    144) "everysec"
    145) "oom-score-adj"
    146) "no"
    147) "acl-pubsub-default"
    148) "allchannels"
    149) "sanitize-dump-payload"
    150) "no"
    151) "databases"
    152) "16"
    153) "port"
    154) "6379"
    155) "io-threads"
    156) "1"
    157) "auto-aof-rewrite-percentage"
    158) "100"
    159) "cluster-replica-validity-factor"
    160) "10"
    161) "cluster-slave-validity-factor"
    162) "10"
    163) "list-max-ziplist-size"
    164) "-2"
    165) "tcp-keepalive"
    166) "300"
    167) "cluster-migration-barrier"
    168) "1"
    169) "active-defrag-cycle-min"
    170) "1"
    171) "active-defrag-cycle-max"
    172) "25"
    173) "active-defrag-threshold-lower"
    174) "10"
    175) "active-defrag-threshold-upper"
    176) "100"
    177) "lfu-log-factor"
    178) "10"
    179) "lfu-decay-time"
    180) "1"
    181) "replica-priority"
    182) "100"
    183) "slave-priority"
    184) "100"
    185) "repl-diskless-sync-delay"
    186) "5"
    187) "maxmemory-samples"
    188) "5"
    189) "maxmemory-eviction-tenacity"
    190) "10"
    191) "timeout"
    192) "300"
    193) "replica-announce-port"
    194) "0"
    195) "slave-announce-port"
    196) "0"
    197) "tcp-backlog"
    198) "511"
    199) "cluster-announce-bus-port"
    200) "0"
    201) "cluster-announce-port"
    202) "0"
    203) "cluster-announce-tls-port"
    204) "0"
    205) "repl-timeout"
    206) "60"
    207) "repl-ping-replica-period"
    208) "10"
    209) "repl-ping-slave-period"
    210) "10"
    211) "list-compress-depth"
    212) "0"
    213) "rdb-key-save-delay"
    214) "0"
    215) "key-load-delay"
    216) "0"
    217) "active-expire-effort"
    218) "1"
    219) "hz"
    220) "10"
    221) "min-replicas-to-write"
    222) "0"
    223) "min-slaves-to-write"
    224) "0"
    225) "min-replicas-max-lag"
    226) "10"
    227) "min-slaves-max-lag"
    228) "10"
    229) "maxclients"
    230) "10000"
    231) "active-defrag-max-scan-fields"
    232) "1000"
    233) "slowlog-max-len"
    234) "128"
    235) "acllog-max-len"
    236) "128"
    237) "lua-time-limit"
    238) "5000"
    239) "cluster-node-timeout"
    240) "15000"
    241) "slowlog-log-slower-than"
    242) "10000"
    243) "latency-monitor-threshold"
    244) "0"
    245) "proto-max-bulk-len"
    246) "536870912"
    247) "stream-node-max-entries"
    248) "100"
    249) "repl-backlog-size"
    250) "1048576"
    251) "maxmemory"
    252) "0"
    253) "hash-max-ziplist-entries"
    254) "512"
    255) "set-max-intset-entries"
    256) "512"
    257) "zset-max-ziplist-entries"
    258) "128"
    259) "active-defrag-ignore-bytes"
    260) "104857600"
    261) "hash-max-ziplist-value"
    262) "64"
    263) "stream-node-max-bytes"
    264) "4096"
    265) "zset-max-ziplist-value"
    266) "64"
    267) "hll-sparse-max-bytes"
    268) "3000"
    269) "tracking-table-max-keys"
    270) "1000000"
    271) "client-query-buffer-limit"
    272) "1073741824"
    273) "repl-backlog-ttl"
    274) "3600"
    275) "auto-aof-rewrite-min-size"
    276) "67108864"
    277) "logfile"
    278) ""
    279) "watchdog-period"
    280) "0"
    281) "dir"
    282) "/opt/software/redis-6.2.6"
    283) "save"
    284) "900 1 300 10 60 10000"
    285) "client-output-buffer-limit"
    286) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
    287) "unixsocketperm"
    288) "0"
    289) "slaveof"
    290) ""
    291) "notify-keyspace-events"
    292) ""
    293) "bind"
    294) "0.0.0.0"
    295) "oom-score-adj-values"
    296) "0 200 800"
    127.0.0.1:6379>

2.2 编辑配置

要更新配置,可以直接编辑 redis.conf 文件,也可以通过 CONFIG set 命令更新配置。

  1. 语法

    1
    127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
  2. 实例

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> CONFIG SET loglevel "notice"
    OK
    127.0.0.1:6379> CONFIG GET loglevel
    1) "loglevel"
    2) "notice"
    127.0.0.1:6379>
  3. 常用配置参数说明

    redis.conf 配置项说明如下:

    | 序号 | 配置项 | 说明 |
    | —— | —————————————————————————————— | —————————————————————————————— |
    | 1 | daemonize no | Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no ) |
    | 2 | pidfile /var/run/redis.pid | 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定 |
    | 3 | port 6379 | 指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口,因为 6379 在手机按键上 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字 |
    | 4 | bind 127.0.0.1 | 绑定的主机地址 |
    | 5 | timeout 300 | 当客户端闲置多长秒后关闭连接,如果指定为 0 ,表示关闭该功能 |
    | 6 | loglevel notice | 指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice |
    | 7 | logfile stdout | 日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null |
    | 8 | databases 16 | 设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id |
    | 9 | save <seconds> <changes>
    Redis 默认配置文件中提供了三个条件:
    - save 900 1: 900 秒(15 分钟)内有 1 个更改
    - save 300 10: 300 秒(5 分钟)内有 10 个更改
    - save 60 10000: 60 秒内有 10000 个更改 | 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 |
    | 10 | rdbcompression yes | 指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大 |
    | 11 | dbfilename dump.rdb | 指定本地数据库文件名,默认值为 dump.rdb |
    | 12 | dir ./ | 指定本地数据库存放目录 |
    | 13 | slaveof <masterip> <masterport> | 设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 |
    | 14 | masterauth <master-password> | 当 master 服务设置了密码保护时,slave 服务连接 master 的密码 |
    | 15 | requirepass foobared | 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭 |
    | 16 | maxclients 128 | 设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 |
    | 17 | maxmemory <bytes> | 指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区 |
    | 18 | appendonly no | 指定是否在每次更新操作后进行日志记录,
    Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。
    因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no |
    | 19 | appendfilename appendonly.aof | 指定更新日志文件名,默认为 appendonly.aof |
    | 20 | appendfsync everysec | 指定更新日志条件,共有 3 个可选值:
    - no:表示等操作系统进行数据缓存同步到磁盘(快)
    - always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全)
    - everysec:表示每秒同步一次(折中,默认值) |
    | 21 | vm-enabled no | 指定是否启用虚拟内存机制,默认值为 no,
    简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的内容会仔细分析 Redis 的 VM 机制) |
    | 22 | vm-swap-file /tmp/redis.swap | 虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享 |
    | 23 | vm-max-memory 0 | 将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis 的索引数据 就是 keys),
    也就是说,当 vm-max-memory 设置为 0 的时候,其实是所有 value 都存在于磁盘。默认值为 0 |
    | 24 | vm-page-size 32 | Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,
    vm-page-size 是要根据存储的 数据大小来设定的,
    建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;
    如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值 |
    | 25 | vm-pages 134217728 | 设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。 |
    | 26 | vm-max-threads 4 | 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 |
    | 27 | glueoutputbuf yes | 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 |
    | 28 | hash-max-zipmap-entries 64
    hash-max-zipmap-value 512 | 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 |
    | 29 | activerehashing yes | 指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍) |
    | 30 | include /path/to/local.conf | 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 |

3. Redis数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合), 位图(Bitmaps), 基数统计(HyperLogLogs)。

各个数据类型应用场景:

类型 简介 特性 场景
String(字符串) 二进制安全 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M —-
Hash(字典) 键值对集合,即编程语言中的Map类型 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) 存储、读取、修改用户属性
List(列表) 链表(双向链表) 增删快,提供了操作某一段元素的API 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
Set(集合) 哈希表实现,元素不重复 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set(有序集合) 将Set中的元素增加一个权重参数score,元素按score有序排列 数据插入集合时,已经进行天然排序 1、排行榜 2、带权重的消息队列

3.1 string(字符串)

string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

可以在Redis中使用字符串做一些有趣的事情,例如,您可以:

  • 使用INCR系列中的命令将字符串用作原子计数器:INCRDECRINCRBY
  • 使用 APPEND 命令附加到字符串。
  • 使用字符串作为 <a href=”#GETRANGESETRANGE 的随机访问向量。
  • 在小空间中编码大量数据,或使用 GETBITSETBIT 创建Redis支持的Bloom过滤器。

检查所有 可用的字符串命令 以获取更多信息,或阅读==Redis数据类型的简介==。

实例:

1
2
3
4
5
127.0.0.1:6379> SET kungs "yanpenggong"
OK
127.0.0.1:6379> get kungs
"yanpenggong"
127.0.0.1:6379>

在以上实例中,使用了 Redis 的 SETGET 命令。键为 kungs,对应的值为 yanpenggong

注意:一个键最大能存储 512MB。

3.2 hash(哈希)

Redis hash 是一个键值(key=>value)对集合。

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

实例:

DEL kungs 用于删除前面测试用过的 key,不然会报错:(error) WRONGTYPE Operation against a key holding the wrong kind of value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> SET kungs "yanpenggong"
OK
127.0.0.1:6379> GET kungs
"yanpenggong"
127.0.0.1:6379> HMSET kungs field1 "Hello" field2 "World"
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> DEL kungs
(integer) 1
127.0.0.1:6379> HMSET kungs field1 "Hello" field2 "World"
OK
127.0.0.1:6379> HGET kungs field1
"Hello"
127.0.0.1:6379> HGET kungs field2
"World"
127.0.0.1:6379>

实例中我们使用了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value

每个 hash 可以存储 232 -1 键值对(40多亿)。

3.3 list(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> DEL kungs
(integer) 1
127.0.0.1:6379> lpush kungs redis
(integer) 1
127.0.0.1:6379> lpush kungs mongodb
(integer) 2
127.0.0.1:6379> lpush kungs rabbitmq
(integer) 3
127.0.0.1:6379> lpush kungs cassandra
(integer) 4
127.0.0.1:6379> lrange kungs 0 10
1) "cassandra"
2) "rabbitmq"
3) "mongodb"
4) "redis"
127.0.0.1:6379>

列表最多可存储 $2^{32} - 1$ 元素 (4294967295, 每个列表可存储40多亿)。

3.4 set(集合)

Redis 的 Set 是 string 类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

  1. sadd 命令

    添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。

    1
    sadd key member
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> sadd kungs redis
    (integer) 1
    127.0.0.1:6379> sadd kungs mongodb
    (integer) 1
    127.0.0.1:6379> sadd kungs rabbitmq
    (integer) 1
    127.0.0.1:6379> sadd kungs rabbitmq
    (integer) 0
    127.0.0.1:6379> smembers kungs
    1) "rabbitmq"
    2) "mongodb"
    3) "redis"
    127.0.0.1:6379>

    注意:以上实例中 rabbitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

    集合中最大的成员数为 $2^{32} - 1$ (4294967295, 每个集合可存储40多亿个成员)。

3.5 zset(sorted set:有序集合)。

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

  1. zadd 命令

    添加元素到集合,元素在集合中存在则更新对应score

    1
    zadd key score member 
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    127.0.0.1:6379> DEL kungs
    Error: Server closed the connection
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 redis
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 mongodb
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 rabbitmq
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 rabbitmq
    (integer) 0
    127.0.0.1:6379> zrangebyscore kungs 0 1000
    1) "mongodb"
    2) "rabbitmq"
    3) "redis"
    127.0.0.1:6379>

3.6 位图(Bitmaps)

Redis Bitmap 通过类似 map 结构存放 0 或 1 ( bit 位 ) 作为值。

Redis Bitmap 可以用来统计状态,如日活是否浏览过某个东西。

  1. Redis setbit 命令

    1
    SETBIT key offset value
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> setbit kungs:001 10001 1
    (integer) 0
    127.0.0.1:6379> setbit kungs:001 10002 2
    (error) ERR bit is not an integer or out of range
    127.0.0.1:6379> setbit kungs:001 10002 0
    (integer) 0
    127.0.0.1:6379> setbit kungs:001 10003 1
    (integer) 0
    127.0.0.1:6379> getbit kungs:001 10001
    (integer) 1
    127.0.0.1:6379> getbit kungs:001 10002
    (integer) 0
    127.0.0.1:6379> getbit kungs:001 10003
    (integer) 1
    127.0.0.1:6379>

3.7 基数统计(HyperLogLogs)

Redis HyperLogLog 可以接受多个元素作为输入,并给出输入元素的基数估算值

  • 基数

集合中不同元素的数量,比如 {‘apple’, ‘banana’, ‘cherry’, ‘banana’, ‘apple’} 的基数就是 3

  • 估算值

算法给出的基数并不是精确的,可能会比实际稍微多一些或者稍微少一些,但会控制在合 理的范围之内

HyperLogLog 的优点是:即使输入元素的数量或者体积非常非常大,计算基数所需的空间总是固定的、并且是很小的

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 264个不同元素的基数。

这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

  1. Redis PFADD命令

    Redis PFADD 命令将元素添加至 HyperLogLog

    1
    PFADD key element [element ...]
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD unique::ip::counter "192.168.0.1"
    (integer) 1
    127.0.0.1:6379> PFADD unique::ip::counter "127.0.0.1"
    (integer) 1
    127.0.0.1:6379> PFADD unique::ip::counter "255.255.255.255"
    (integer) 1
    127.0.0.1:6379> PFCOUNT unique::ip::counter
    (integer) 3
    127.0.0.1:6379>

3.8 数据库的数据注意事项

注意:Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。

Redis是一个字典结构的存储服务器,而实际上一个Redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系数据库实例中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。

每个数据库对外都是一个从0开始的递增数字命名,Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库,如要选择1号数据库:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> set kungs1 "Hello"
OK
127.0.0.1:6379> get kungs1
Hello
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get kungs1

127.0.0.1:6379[1]>

然而这些以数字命名的数据库又与我们理解的数据库有所区别。

  • 首先Redis不支持自定义数据库的名字,每个数据库都以编号命名,开发者必须自己记录哪些数据库存储了哪些数据。
  • 另外Redis也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问全部数据库,要么连一个数据库也没有权限访问。
  • 最重要的一点是多个数据库之间并不是完全隔离的,比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。

综上所述,这些数据库更像是一种命名空间,而不适宜存储不同应用程序的数据。

比如可以使用0号数据库存储某个应用生产环境中的数据,使用1号数据库存储测试环境中的数据,但不适宜使用0号数据库存储A应用的数据而使用1号数据库B应用的数据,不同的应用应该使用不同的Redis实例存储数据。

由于Redis非常轻量级,一个空Redis实例占用的内存只有1M左右,所以不用担心多个Redis实例会额外占用很多内存。

4. Redis 命令

4.0 Redis 命令

4.0.1 本地执行命令

Redis 命令用于在 redis 服务上执行操作。

要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。

  1. 语法

    1
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong
  2. 实例

    以下实例讲解了如何启动 redis 客户端:

    启动 redis 服务器,打开终端并输入命令 redis-cli,该命令会连接本地的 redis 服务。

    1
    2
    3
    4
    5
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379>

    在以上实例中我们连接到本地的 redis 服务并执行 PING 命令,该命令用于检测 redis 服务是否启动。

4.0.2 在远程服务上执行命令

如果需要在远程 redis 服务上执行命令,同样我们使用的也是 redis-cli 命令。

  1. 语法

    1
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -h host -p port -a password
  2. 实例

    以下实例演示了如何连接到主机为 127.0.0.1,端口为 6379 ,密码为 yanpengong 的 redis 服务上。

    1
    2
    3
    4
    5
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -h 127.0.0.1 -p 6379 -a "yanpenggong"
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379>

4.0.3 中文乱码解决办法

有时候会有中文乱码。要在 redis-cli 后面加上 --raw

1
2
3
[root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong --raw
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379>

4.1 Redis 键(Keys)

Redis 键命令用于管理 redis 的键。

4.1.1 基本操作

  1. 语法

    1
    127.0.0.1:6379> COMMAND KEY_NAME
  1. 实例

    实例中 DEL 是一个命令, kungs 是一个键。 如果键被删除成功,命令执行后输出 1,否则将输出 0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET kungs redis
    OK
    127.0.0.1:6379> get kungs
    redis
    127.0.0.1:6379> DEL kungs
    1
    127.0.0.1:6379> DEL kungs
    0
    127.0.0.1:6379>

4.1.2 keys 基本命令汇总

序号 命令 描述
1 DEL key 用于在 key 存在时删除 key
2 DUMP key 序列化给定 key ,并返回被序列化的值
3 EXISTS key 检查给定 key 是否存在
4 EXPIRE key seconds 为给定 key 设置过期时间,以秒计
5 EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。
不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)
6 PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计
7 PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
8 KEYS pattern 查找所有符合给定模式( pattern)的 key
9 MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中
10 PERSIST key 移除 key 的过期时间,key 将持久保持
11 PTTL key 以毫秒为单位返回 key 的剩余的过期时间
12 TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)
13 RANDOMKEY 从当前数据库中随机返回一个 key
14 RENAME key newkey 修改 key 的名称
15 RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey
16 SCAN cursor [MATCH pattern] [COUNT count] 迭代数据库中的数据库键
17 TYPE key 返回 key 所储存的值的类型

4.2 String(字符串)

Redis 字符串命令用于管理 Redis 中的字符串值。

4.2.1 基本操作

  1. 语法:

    1
    127.0.0.1:6379> COMMAND KEY_NAME
  2. 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET kungs yanpenggong
    OK
    127.0.0.1:6379> GET kungs
    "yanpenggong"
    127.0.0.1:6379>

    这里,SET 和 GET 是命令,”kungs” 是键。

4.2.2 String 基本命令汇总

序号 命令 描述
1 SET 设置指定 key 的值
2 GET 获取指定 key 的值
3 GETRANGE 返回 key 中字符串值的子字符
4 GETSET 将给定 key 的值设为 value ,并返回 key 的旧值 ( old value )
5 GETBIT 对 key 所储存的字符串值,获取指定偏移量上的位 ( bit )
6 MGET 获取所有(一个或多个)给定 key 的值
7 SETBIT 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
8 SETEX 设置 key 的值为 value 同时将过期时间设为 seconds
9 SETNX 只有在 key 不存在时设置 key 的值
10 SETRANGE 从偏移量 offset 开始用 value 覆写给定 key 所储存的字符串值
11 STRLEN 返回 key 所储存的字符串值的长度
12 MSET 同时设置一个或多个 key-value 对
13 MSETNX 同时设置一个或多个 key-value 对
14 PSETEX 以毫秒为单位设置 key 的生存时间
15 INCR 将 key 中储存的数字值增一
16 INCRBY 将 key 所储存的值加上给定的增量值 ( increment )
17 INCRBYFLOAT 将 key 所储存的值加上给定的浮点增量值 ( increment )
18 DECR 将 key 中储存的数字值减一
19 DECRBY 将 key 所储存的值减去给定的减量值 ( decrement )
20 APPEND 将 value 追加到 key 原来的值的末尾

4.3 Hashes(哈希)

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

Redis 中每个 hash 可以存储 $2^{32} - 1$ 键值对(40多亿)。

4.3.1 基本操作

实例:

在例子中,rediscomcn 是 Redis 哈希,它包含详细信息(name,url,rank,visitors)属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> HMSET rediscomcn name "yanpenggong" url "https://blog.csdn.net/yanpenggong" rank 1 visitors 2888
OK
127.0.0.1:6379> HGETALL redisconmcn
(empty array)
127.0.0.1:6379> HGETALL rediscomcn
1) "name"
2) "yanpenggong"
3) "url"
4) "https://blog.csdn.net/yanpenggong"
5) "rank"
6) "1"
7) "visitors"
8) "2888"
127.0.0.1:6379>

4.3.2 Hashes 基本命令汇总

序号 命令 描述
1 HDEL 删除一个或多个哈希表字段
2 HEXISTS 查看哈希表 key 中,指定的字段是否存在
3 HGET 获取存储在哈希表中指定字段的值
4 HGETALL 获取在哈希表中指定 key 的所有字段和值
5 HINCRBY 为哈希表 key 中的指定字段的整数值加上增量 increment
6 HINCRBYFLOAT 为哈希表 key 中的指定字段的浮点数值加上增量 increment
7 HKEYS 获取所有哈希表中的字段
8 HLEN 获取哈希表中字段的数量
9 HMGET 获取所有给定字段的值
10 HMSET 同时将多个 field-value (域-值)对设置到哈希表 key 中
11 HSET 将哈希表 key 中的字段 field 的值设为 value
12 HSETNX 只有在字段 field 不存在时,设置哈希表字段的值
13 HVALS 获取哈希表中所有值
14 HSCAN 迭代哈希表中的键值对
15 HSTRLEN 返回哈希表 key 中, 与给定域 field 相关联的值的字符串长度

4.4 List(列表)

Redis 列表是按插入顺序排序的字符串列表。可以在列表的头部(左边)或尾部(右边)添加元素。

列表可以包含超过 40 亿 个元素 ( $2^{32} - 1$ )。

4.4.1 基本操作

用 LPUSH 命令将三个值插入了名为 language 的列表当中:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> LPUSH dbs sql
(integer) 1
127.0.0.1:6379> LPUSH dbs mysql
(integer) 2
127.0.0.1:6379> LPUSH dbs mongodb
(integer) 3
127.0.0.1:6379> LRANGE dbs 0 10
1) "mongodb"
2) "mysql"
3) "sql"
127.0.0.1:6379>

4.4.2 List 基本命令汇总

序号 命令 描述
1 BLPOP 移出并获取列表的第一个元素
2 BRPOP 移出并获取列表的最后一个元素
3 BRPOPLPUSH 从列表中弹出一个值,并将该值插入到另外一个列表中并返回它
4 LINDEX 通过索引获取列表中的元素
5 LINSERT 在列表的元素前或者后插入元素
6 LLEN 获取列表长度
7 LPOP 移出并获取列表的第一个元素
8 LPUSH 将一个或多个值插入到列表头部
9 LPUSHX 将一个值插入到已存在的列表头部
10 LRANGE 获取列表指定范围内的元素
11 LREM 移除列表元素
12 LSET 通过索引设置列表元素的值
13 LTRIM 对一个列表进行修剪(trim)
14 RPOP 移除并获取列表最后一个元素
15 RPOPLPUSH 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
16 RPUSH 在列表中添加一个或多个值
17 RPUSHX 为已存在的列表添加值

4.5 Set(集合)

Redis 的 Set 是 string 类型的无序集合。

集合成员是唯一的,这就意味着集合中没有重复的数据。

在 Redis 中,添加、删除和查找的时间复杂都是 O(1)(不管 Set 中包含多少元素)。

集合中最大的成员数为 $2^{32} – 1$ (4294967295), 每个集合可存储 40 多亿个成员。

4.5.1 基本操作

通过 SADD 命令向名为 rediscomcn 的集合插入的三个元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> SADD rediscomcn db2
(integer) 1
127.0.0.1:6379> SADD rediscomcn mongodb
(integer) 1
127.0.0.1:6379> SADD rediscomcn db2
(integer) 0
127.0.0.1:6379> SADD rediscomcn cassandra
(integer) 1
127.0.0.1:6379> SMEMBERS rediscomcn
1) "cassandra"
2) "mongodb"
3) "db2"
127.0.0.1:6379>

在上面的示例中,我们使用 SADD 命令在集合中添加了 4 个元素。但是,使用 SMEMBERS 命令只检索了 3 个元素,因为有一个元素是重复的,Redis 只集合只含唯一元素。

4.5.2 基本命令汇总

序号 命令 描述
1 SADD 向集合添加一个或多个成员
2 SCARD 获取集合的成员数
3 SDIFF 返回给定所有集合的差集
4 SDIFFSTORE 返回给定所有集合的差集并存储在 destination 中
5 SINTER 返回给定所有集合的交集
6 SINTERSTORE 返回给定所有集合的交集并存储在 destination 中
7 SISMEMBER 判断 member 元素是否是集合 key 的成员
8 SMEMBERS 返回集合中的所有成员
9 SMOVE 将 member 元素从 source 集合移动到 destination 集合
10 SPOP 移除并返回集合中的一个随机元素
11 SRANDMEMBER 返回集合中一个或多个随机数
12 SREM 移除集合中一个或多个成员
13 SUNION 返回所有给定集合的并集
14 SUNIONSTORE 所有给定集合的并集存储在 destination 集合中
15 SSCAN 迭代集合中的元素

4.6 Sorted Sets(有序集合)

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数 ( score ) 却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

集合中最大的成员数为 $2^{32} – 1$ ( 4294967295 ) , 每个集合可存储 40 多亿个成员。

4.6.1 基本操作

通过 ZADD 命令向 Redis 的有序集合中添加了三个值并关联分数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
127.0.0.1:6379> ZADD rediscomcn 1 redis
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 2 mongodb
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 3 mongodb
(integer) 0
127.0.0.1:6379> ZADD rediscomcn 3 mysql
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 4 mysql
(integer) 0
127.0.0.1:6379> ZRANGE rediscomcn 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "3"
5) "mysql"
6) "4"
127.0.0.1:6379>

4.6.2 基本命令汇总

序号 命令 描述
1 ZADD 向有序集合添加一个或多个成员,或者更新已存在成员的分数
2 ZCARD 获取有序集合的成员数
3 ZCOUNT 计算在有序集合中指定区间分数的成员数
4 ZINCRBY 有序集合中对指定成员的分数加上增量 increment
5 ZINTERSTORE 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
6 ZLEXCOUNT 在有序集合中计算指定字典区间内成员数量
7 ZRANGE 通过索引区间返回有序集合成指定区间内的成员
8 ZRANGEBYLEX 通过字典区间返回有序集合的成员
9 ZRANGEBYSCORE 通过分数返回有序集合指定区间内的成员
10 ZRANK 返回有序集合中指定成员的索引
11 ZREM 移除有序集合中的一个或多个成员
12 ZREMRANGEBYLEX 移除有序集合中给定的字典区间的所有成员
13 ZREMRANGEBYRANK 移除有序集合中给定的排名区间的所有成员
14 ZREMRANGEBYSCORE 移除有序集合中给定的分数区间的所有成员
15 ZREVRANGE 返回有序集中指定区间内的成员,通过索引,分数从高到底
16 ZREVRANGEBYSCORE 返回有序集中指定分数区间内的成员,分数从高到低排序
17 ZREVRANK 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
18 ZSCORE 返回有序集中,成员的分数值
19 ZUNIONSTORE 计算一个或多个有序集的并集,并存储在新的 key 中
20 ZSCAN 迭代有序集合中的元素(包括元素成员和元素分值)

4.7 Pub/Sub(发布订阅)

Redis 发布/订阅是一种消息传模式,其中发送者(在Redis术语中称为发布者)发送消息,而接收者(订阅者)接收消息。传递消息的通道称为channel

在Redis中,客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

1
2
3
4
graph BT;
client1-->|subscribe|channel1;
client2-->|subscribe|channel1;
client5-->|subscribe|channel1;

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

1
2
3
4
5
6
7
8
9
10
graph TB;
start(PUBLISH channel1 message)-->channel1(channel1);
channel1-->|message|client1(client1);
channel1-->|message|client2(client2);
channel1-->|message|client5(client5);
style start fill:#aaf
style channel1 fill:#90EE90
style client1 fill:#87CEFA
style client2 fill:#87CEFA
style client5 fill:#87CEFA

4.7.1 基本操作

以下实例演示了发布订阅是如何工作的,需要开启两个 redis-cli 客户端。

在我们实例中我们创建了订阅频道名为 rediscomcnChat:

  1. 第一个 redis-cli 客户端

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1

    现在,我们先重新开启个 redis 客户端(第二个redis-cli 客户端),然后在同一个频道 rediscomcnChat 发布两次消息,订阅者就能接收到消息。

  2. 第二个 redis-cli 客户端

    1
    2
    3
    4
    5
    127.0.0.1:6379> PUBLISH rediscomcnChat "Redis PUBLISH test"
    (integer) 1
    127.0.0.1:6379> PUBLISH rediscomcnChat "Learn redis with python"
    (integer) 1
    127.0.0.1:6379>
  1. 第一个redis-cli 客户端的最新接受信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Redis PUBLISH test"
    1) "message"
    2) "rediscomcnChat"
    3) "Learn redis with python"

4.7.2 基本命令汇总

序号 命令 描述
1 PSUBSCRIBE 订阅一个或多个符合给定模式的频道。
2 PUBSUB 查看订阅与发布系统状态。
3 PUBLISH 将信息发送到指定的频道。
4 PUNSUBSCRIBE 退订所有给定模式的频道。
5 SUBSCRIBE 订阅给定的一个或多个频道的信息。
6 UNSUBSCRIBE 指退订给定的频道。

4.8 Transaction(事务)

事务是指一个完整的动作,要么全部执行,要么什么也没有做

Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

Redis 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

MULTI、EXEC、DISCARD、WATCH 这四个指令构成了 redis 事务处理的基础。

  1. MULTI 用来组装一个事务;
  2. EXEC 用来执行一个事务;
  3. DISCARD 用来取消一个事务;
  4. WATCH 用来监视一些 key,一旦这些 key 在事务执行之前被改变,则取消事务的执行。

在 Redis 中,通过使用MULTI命令启动事务,然后需要传递应在事务中执行的命令列表,之后整个事务由EXEC命令执行。

1
2
3
4
5
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> EXEC
(empty array)
127.0.0.1:6379>

4.8.1 基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET myset redis
QUEUED
127.0.0.1:6379(TX)> GET myset
QUEUED
127.0.0.1:6379(TX)> INCR kungs
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) "redis"
3) (integer) 1
127.0.0.1:6379>

在上面的例子中,我们看到了 QUEUED 的字样,这表示我们在用 MULTI 组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现 QUEUED 则表示我们这个命令成功插入了缓存队列,在将来执行 EXEC 时,这些被 QUEUED 的命令都会被组装成一个事务来执行。

对于事务的执行来说,如果 redis 开启了 AOF 持久化的话,那么一旦事务被成功执行,事务中的命令就会通过 write 命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了 AOF 持久化,这时 AOF 文件就会出现不完整的情况,这时,我们可以使用 redis-check-aof 工具来修复这一问题,这个工具会将 AOF 文件中不完整的信息移除,确保 AOF 文件完整可用。

Redis 事务错误

有关事务,大家经常会遇到的是两类错误:

  • 调用 EXEC 之前的错误
  • 调用 EXEC 之后的错误

调用 EXEC 之前的错误,有可能是由于语法有误导致的,也可能时由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis 都会进行记录,在客户端调用 EXEC 时,redis 会拒绝执行这一事务。(这是 2.6.5 版本之后的策略。在 2.6.5 之前的版本中,redis 会忽略那些入队失败的命令,只执行那些入队成功的命令)。我们来看一个这样的例子:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> multi
OK
127.0.0.1:6379> haha //一个明显错误的指令
(error) ERR unknown command 'haha'
127.0.0.1:6379> ping
QUEUED
127.0.0.1:6379> exec
//redis无情的拒绝了事务的执行,原因是“之前出现了错误”
(error) EXECABORT Transaction discarded because of previous errors.

而对于调用 EXEC 之后的错误,redis 则采取了完全不同的策略,即 redis 不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面的错误,并不是 redis 自身需要考虑和处理的问题,所以一个事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。我们也来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 23
QUEUED
//age不是集合,所以如下是一条明显错误的指令
127.0.0.1:6379> sadd age 15
QUEUED
127.0.0.1:6379> set age 29
QUEUED
127.0.0.1:6379> exec //执行事务时,redis不会理睬第2条指令执行错误
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"29" //可以看出第3条指令被成功执行了

最后,我们来说说最后一个指令WATCH,这是一个很好用的指令,它可以帮我们实现类似于“乐观锁”的效果,即CAS(check and set)

WATCH 本身的作用是监视 key 是否被改动过,而且支持同时监视多个 key,只要还没真正触发事务,WATCH 都会尽职尽责的监视,一旦发现某个 key 被修改了,在执行 EXEC 时就会返回 nil,表示事务无法触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> watch age //开始监视age
OK
127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec //触发EXEC
(nil) //事务无法被执行

4.8.2 基本命令汇总

序号 命令 描述
1 DISCARD 取消事务,放弃执行事务块内的所有命令
2 EXEC 执行所有事务块内的命令
3 MULTI 标记一个事务块的开始
4 UNWATCH 取消 WATCH 命令对所有 key 的监视
5 WATCH 监视一个(或多个) key

4.9 Script(脚本)

Redis 脚本使用 Lua 解释器来执行脚本。

自版本 2.6.0 开始内嵌于 Redis 中。

用于编写脚本的命令是 EVAL。

4.9.1 基本操作

  • 语法:

    1
    127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]
  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    127.0.0.1:6379>

4.9.2 基本命令汇总

序号 命令 描述
1 EVAL script numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。
2 EVALSHA sha1 numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。
3 SCRIPT EXISTS sha1 [sha1 ...] 查看指定的脚本是否已经被保存在缓存当中。
4 SCRIPT FLUSH 从脚本缓存中移除所有脚本。
5 SCRIPT KILL 杀死当前正在运行的 Lua 脚本。
6 SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

4.10 Connection(连接)

Redis 连接命令用于控制和管理到 Redis Server 的客户端连接。

4.10.1 基本操作

示例说明客户端如何向 Redis 服务器验证自身并检查服务器是否正在运行。

1
2
3
4
5
6
7
8
[root@localhost redis-6.2.6]# src/redis-cli
127.0.0.1:6379> PING
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379>

注意:在这里您可以看到未设置“密码”,因此您可以直接访问任何命令。

4.10.2 基本命令汇总

序号 命令 描述
1 AUTH password 验证密码是否正确
2 ECHO message 打印字符串
3 PING 查看服务是否运行
4 QUIT 关闭当前连接
5 SELECT index 切换到指定的数据库

4.11 Server(服务器)

Redis Server 命令用于管理 Redis 服务器。

有不同的服务器命令可用于获取服务器信息,统计信息和其他特征。

4.11.1 基本操作

如何获取有关服务器的所有统计信息和信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> AUTH "password"
(error) WRONGPASS invalid username-password pair or user is disabled.
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> ECHO "Welcome to use redis!"
"Welcome to use redis!"
127.0.0.1:6379> INFO
# Server
redis_version:6.2.6
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:eac5b3c736e2a107
redis_mode:standalone
os:Linux 3.10.0-1160.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.8.5
process_id:17277
process_supervised:no
run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
tcp_port:6379
server_time_usec:1653053635898059
uptime_in_seconds:112803
uptime_in_days:1
hz:10
configured_hz:10
lru_clock:8886467
executable:/opt/software/redis-6.2.6/./src/redis-server
config_file:/opt/software/redis-6.2.6/./redis.conf
io_threads_active:0

# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:24
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0

# Memory
used_memory:879392
used_memory_human:858.78K
used_memory_rss:3112960
used_memory_rss_human:2.97M
used_memory_peak:977792
used_memory_peak_human:954.88K
used_memory_peak_perc:89.94%
used_memory_overhead:832376
used_memory_startup:810112
used_memory_dataset:47016
used_memory_dataset_perc:67.86%
allocator_allocated:924912
allocator_active:1191936
allocator_resident:3473408
total_system_memory:1019572224
total_system_memory_human:972.34M
used_memory_lua:43008
used_memory_lua_human:42.00K
used_memory_scripts:248
used_memory_scripts_human:248B
number_of_cached_scripts:2
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.29
allocator_frag_bytes:267024
allocator_rss_ratio:2.91
allocator_rss_bytes:2281472
rss_overhead_ratio:0.90
rss_overhead_bytes:-360448
mem_fragmentation_ratio:3.72
mem_fragmentation_bytes:2276328
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:20504
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0

# Persistence
loading:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:1
rdb_bgsave_in_progress:0
rdb_last_save_time:1653053235
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:462848
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0

# Stats
total_connections_received:86
total_commands_processed:874
instantaneous_ops_per_sec:0
total_net_input_bytes:34468
total_net_output_bytes:400133
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:6178
evicted_keys:0
keyspace_hits:194
keyspace_misses:13
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:955
total_forks:72
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:78
dump_payload_sanitizations:0
total_reads_processed:885
total_writes_processed:872
io_threaded_reads_processed:0
io_threaded_writes_processed:0

# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:207.781743
used_cpu_user:235.973647
used_cpu_sys_children:0.431789
used_cpu_user_children:0.070083
used_cpu_sys_main_thread:207.720070
used_cpu_user_main_thread:235.938962

# Modules

# Errorstats
errorstat_ERR:count=45
errorstat_NOAUTH:count=13
errorstat_NOTBUSY:count=3
errorstat_WRONGPASS:count=4
errorstat_WRONGTYPE:count=13

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=21,expires=0,avg_ttl=0
db1:keys=5,expires=0,avg_ttl=0
db2:keys=3,expires=0,avg_ttl=0
127.0.0.1:6379>

4.11.2 基本命令汇总

序号 命令 描述
1 BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作
2 BGSAVE 在后台异步保存当前数据库的数据到磁盘
3 CLIENT KILL 关闭客户端连接
4 CLIENT LIST 获取连接到服务器的客户端连接列表
5 CLIENT GETNAME 获取连接的名称
6 CLIENT PAUSE 在指定时间内终止运行来自客户端的命令
7 CLIENT STNAME 设置当前连接的名称
8 CLUSTER SLOTS 获取集群节点的映射数组
9 COMMAND 获取 Redis 命令总数
10 COMMAND COUNT 获取 Redis 命令总数
11 COMMAND GETKEYS 获取给定命令的所有键
12 TIME 返回当前服务器时间
13 COMMAND INFO 获取指定 Redis 命令描述的数组
14 CONFIG GET 获取指定配置参数的值
15 CONFIG REWRITE 修改 redis.conf 配置文件
16 CONFIG SET 修改 redis 配置参数,无需重启
17 CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据
18 DBSIZE 返回当前数据库的 key 的数量
19 DEBUG OBJECT 获取 key 的调试信息
20 DEBUG SEGFAULT 让 Redis 服务崩溃
21 FLUSHALL 删除所有数据库的所有 key
22 FLUSHDB 删除当前数据库的所有 key
23 INFO 获取 Redis 服务器的各种信息和统计数值
24 LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间
25 MONITOR 实时打印出 Redis 服务器接收到的命令,调试用
26 ROLE 返回主从实例所属的角色
27 SAVE 异步保存数据到硬盘
28 SHUTDOWN 异步保存数据到硬盘,并关闭服务器
29 SLAVEOF 将当前服务器转变从属服务器(slave server)
30 SLOWLOG 管理 redis 的慢日志
31 SYNC 用于复制功能 ( replication ) 的内部命令

4.12 HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 264个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

4.12.1 基本操作

  • 什么是基数?

    比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

  • 实例

    以下实例演示了 HyperLogLog 的工作过程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD rediscomcn "redis"
    (integer) 1
    127.0.0.1:6379> PFADD rediscomcn "mongodb"
    (integer) 1
    127.0.0.1:6379> PFADD rediscomcn "mysql"
    (integer) 1
    127.0.0.1:6379> PFCOUNT rediscomcn
    (integer) 3
    127.0.0.1:6379>

4.12.2 基本命令汇总

序号 命令 描述
1 PFADD 添加指定元素到 HyperLogLog 中。
2 PFCOUNT 返回给定 HyperLogLog 的基数估算值。
3 PFMERGE 将多个 HyperLogLog 合并为一个 HyperLogLog

4.13 地理信息

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。

Redis GEO 操作方法有:

  • geoadd:添加地理位置的坐标。
  • geopos:获取地理位置的坐标。
  • geodist:计算两个位置之间的距离。
  • georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
  • georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
  • geohash:返回一个或多个位置对象的 geohash 值。

4.13.1 geoadd

geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。

geoadd 语法格式如下:

1
127.0.0.1:6379> GEOADD key longitude latitude member [longitude latitude member ...]

以下实例中 key 为 Sicily、Catania 为位置名称 :

实例:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEORADIUS Sicily 15 37 100 km
1) "Catania"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
127.0.0.1:6379>

4.13.2 geopos

geopos 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。

geopos 语法格式如下:

1
127.0.0.1:6379> GEOPOS key member [member ...]

实例

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "15.08726745843887329"
2) "37.50266842333162032"
3) (nil)
127.0.0.1:6379>

4.13.3 geodist

geodist 用于返回两个给定位置之间的距离。

geodist 语法格式如下:

1
127.0.0.1:6379> GEODIST key member1 member2 [m|km|ft|mi]

member1 member2 为两个地理位置。

最后一个距离单位参数说明:

  • m :米,默认单位。
  • km :千米。
  • mi :英里。
  • ft :英尺。

实例: 计算 Palermo 与 Catania 之间的距离实例

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEODIST Sicily Palermo Catania km
"166.2742"
127.0.0.1:6379> GEODIST Sicily Palermo Catania mi
"103.3182"
127.0.0.1:6379> GEODIST Sicily Foo Bar
(nil)
127.0.0.1:6379>

4.13.4 georadius、georadiusbymember

georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

georadiusbymember 和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。

georadius 与 georadiusbymember 语法格式如下:

1
2
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

参数说明:

  • m :米,默认单位。
  • km :千米。
  • mi :英里。
  • ft :英尺。
  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
  • COUNT 限定返回的记录数。
  • ASC: 查找结果根据距离从近到远排序。
  • DESC: 查找结果根据从远到近排序。

    georadius实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
2) "190.4424"
2) 1) "Catania"
2) "56.4413"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
2) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) 1) "15.08726745843887329"
2) "37.50266842333162032"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
2) "190.4424"
3) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) "56.4413"
3) 1) "15.08726745843887329"
2) "37.50266842333162032"
127.0.0.1:6379>

georadiusbymember实例:

1
2
3
4
5
6
7
8
127.0.0.1:6379> GEOADD Sicily 13.583333 37.316667 "Agrigento"
(integer) 1
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"
127.0.0.1:6379>

4.13.5 geohash

Redis GEO 使用 geohash 来保存地理位置的坐标。

geohash 用于获取一个或多个位置元素的 geohash 值。

geohash 语法格式如下:

1
127.0.0.1:6379> GEOHASH key member [member ...]

geohash实例:

1
2
3
4
5
6
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"
127.0.0.1:6379>

4.14 Stream

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

每个 Stream 都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加消息时自动创建。

上图解析:

  • Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
  • lastdeliveredid :游标,每个消费组会有个游标 lastdeliveredid,任意一个消费者读取了消息都会使游标 lastdeliveredid 往前移动。
  • pendingids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pendingids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。

消息队列相关命令:

  • XADD - 添加消息到末尾
  • XTRIM - 对流进行修剪,限制长度
  • XDEL - 删除消息
  • XLEN - 获取流包含的元素数量,即消息长度
  • XRANGE - 获取消息列表,会自动过滤已经删除的消息
  • XREVRANGE - 反向获取消息列表,ID 从大到小
  • XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

  • XGROUP CREATE - 创建消费者组
  • XREADGROUP GROUP - 读取消费者组中的消息
  • XACK - 将消息标记为”已处理”
  • XGROUP SETID - 为消费者组设置新的最后递送消息ID
  • XGROUP DELCONSUMER - 删除消费者
  • XGROUP DESTROY - 删除消费者组
  • XPENDING - 显示待处理消息的相关信息
  • XCLAIM - 转移消息的归属权
  • XINFO - 查看流和消费者组的相关信息;
  • XINFO GROUPS - 打印消费者组的信息;
  • XINFO STREAM - 打印流信息

4.14.1 XADD

使用 XADD 向队列添加消息,如果指定的队列不存在,则创建一个队列,XADD 语法格式:

1
127.0.0.1:6379> XADD key ID field value [field value ...]
  • key :队列名称,如果不存在就创建
  • ID :消息 id,我们使用 * 表示由 redis 生成,可以自定义,但是要自己保证递增性。
  • field value : 记录。

XADD实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> XADD mystream * name Sara surname OConnor
"1653077968353-0"
127.0.0.1:6379> XADD mystream * field1 value1 field2 value2 field3 value3
"1653077976530-0"
127.0.0.1:6379> XLEN mystream
(integer) 2
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1653077968353-0"
2) 1) "name"
2) "Sara"
3) "surname"
4) "OConnor"
2) 1) "1653077976530-0"
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
5) "field3"
6) "value3"
127.0.0.1:6379>

4.14.2 XTRIM

使用 XTRIM对流进行修剪,限制长度, 语法格式:

1
XTRIM key MAXLEN [~] count
  • key :队列名称
  • MAXLEN :长度
  • count :数量

XTRIM实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> XADD mystream * field1 A field2 B field3 C field4 D
"1653078272108-0"
127.0.0.1:6379> XTRIM mystream MAXLEN 2
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1653078272108-0"
2) 1) "field1"
2) "A"
3) "field2"
4) "B"
5) "field3"
6) "C"
7) "field4"
8) "D"
127.0.0.1:6379>

4.14.3 XDEL

使用 XDEL 删除消息,语法格式:

1
127.0.0.1:6379> XDEL key ID [ID ...]
  • key:队列名称
  • ID :消息 ID

XDEL实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> XADD mystream * a 1
1538561698944-0
127.0.0.1:6379> XADD mystream * b 2
1538561700640-0
127.0.0.1:6379> XADD mystream * c 3
1538561701744-0
127.0.0.1:6379> XDEL mystream 1538561700640-0
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) 1538561698944-0
2) 1) "a"
2) "1"
2) 1) 1538561701744-0
2) 1) "c"
2) "3"

4.14.4 XLEN

使用 XLEN 获取流包含的元素数量,即消息长度,语法格式:

1
127.0.0.1:6379> XLEN key
  • key:队列名称

XLEN实例:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> XADD mystream * item 1
"1601372563177-0"
127.0.0.1:6379> XADD mystream * item 2
"1601372563178-0"
127.0.0.1:6379> XADD mystream * item 3
"1601372563178-1"
127.0.0.1:6379> XLEN mystream
(integer) 3
127.0.0.1:6379>

4.14.5 XRANGE

使用 XRANGE 获取消息列表,会自动过滤已经删除的消息 ,语法格式:

1
127.0.0.1:6379> XRANGE key start end [COUNT count]
  • key :队列名
  • start :开始值, - 表示最小值
  • end :结束值, + 表示最大值
  • count :数量

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
127.0.0.1:6379> XADD writers * name Virginia surname Woolf
"1601372577811-0"
127.0.0.1:6379> XADD writers * name Jane surname Austen
"1601372577811-1"
127.0.0.1:6379> XADD writers * name Toni surname Morrison
"1601372577811-2"
127.0.0.1:6379> XADD writers * name Agatha surname Christie
"1601372577812-0"
127.0.0.1:6379> XADD writers * name Ngozi surname Adichie
"1601372577812-1"
127.0.0.1:6379> XLEN writers
(integer) 5
127.0.0.1:6379> XRANGE writers - + COUNT 2
1) 1) "1601372577811-0"
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) "1601372577811-1"
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
127.0.0.1:6379>

4.14.6 XREVRANGE

使用 XREVRANGE 获取消息列表,会自动过滤已经删除的消息 ,语法格式:

1
127.0.0.1:6379> XREVRANGE key end start [COUNT count]
  • key :队列名
  • end :结束值, + 表示最大值
  • start :开始值, - 表示最小值
  • count :数量

XREVRANGE实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> XADD writers * name Virginia surname Woolf
"1601372731458-0"
127.0.0.1:6379> XADD writers * name Jane surname Austen
"1601372731459-0"
127.0.0.1:6379> XADD writers * name Toni surname Morrison
"1601372731459-1"
127.0.0.1:6379> XADD writers * name Agatha surname Christie
"1601372731459-2"
127.0.0.1:6379> XADD writers * name Ngozi surname Adichie
"1601372731459-3"
127.0.0.1:6379> XLEN writers
(integer) 5
127.0.0.1:6379> XREVRANGE writers + - COUNT 1
1) 1) "1601372731459-3"
2) 1) "name"
2) "Ngozi"
3) "surname"
4) "Adichie"
127.0.0.1:6379>

4.14.7 XREAD

使用 XREAD 以阻塞或非阻塞方式获取消息列表 ,语法格式:

1
127.0.0.1:6379> XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
  • count :数量
  • milliseconds :可选,阻塞毫秒数,没有设置就是非阻塞模式
  • key :队列名
  • id :消息 ID

实例: 从 Stream 头部读取两条消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
127.0.0.1:6379> XREAD COUNT 2 STREAMS mystream writers 0-0 0-0
1) 1) "mystream"
2) 1) 1) 1526984818136-0
2) 1) "duration"
2) "1532"
3) "event-id"
4) "5"
5) "user-id"
6) "7782813"
2) 1) 1526999352406-0
2) 1) "duration"
2) "812"
3) "event-id"
4) "9"
5) "user-id"
6) "388234"
2) 1) "writers"
2) 1) 1) 1526985676425-0
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) 1526985685298-0
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
127.0.0.1:6379>

4.14.8 XGROUP CREATE

使用 XGROUP CREATE 创建消费者组,语法格式:

1
127.0.0.1:6379> XGROUP [CREATE key groupname id-or-$] [SETID key groupname id-or-$] [DESTROY key groupname] [DELCONSUMER key groupname consumername]
  • key :队列名称,如果不存在就创建
  • groupname :组名。
  • $ : 表示从尾部开始消费,只接受新消息,当前 Stream 消息会全部忽略。

从头开始消费:

1
127.0.0.1:6379> XGROUP CREATE mystream consumer-group-name 0-0  

从尾部开始消费:

1
127.0.0.1:6379> XGROUP CREATE mystream consumer-group-name $

4.14.9 XREADGROUP GROUP

使用 XREADGROUP GROUP 读取消费组中的消息,语法格式:

1
127.0.0.1:6379> XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...]
  • group :消费组名
  • consumer :消费者名。
  • count : 读取数量。
  • milliseconds : 阻塞毫秒数。
  • key : 队列名。
  • ID : 消息 ID。
1
127.0.0.1:6379> XREADGROUP GROUP consumer-group-name consumer-name COUNT 1 STREAMS mystream >

5. Redis 高级功能

5.1 redis备份和恢复

SAVE 命令用于创建当前 Redis 数据库的备份。此命令将通过执行同步 SAVE 在 Redis 目录中创建 dump.rdb 文件。

  • 语法

    1
    127.0.0.1:6379> SAVE
  • 返回值:

    执行成功后,SAVE 命令返回 OK。

5.1.1 Redis备份示例

使用 SAVE 命令创建当前数据库的备份。

1
2
3
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379>

它将在 Redis 目录中创建 dump.rdb 文件。

可以看到 dump.rdb 文件已创建。

1
2
3
4
5
6
7
[root@192 redis-6.2.6]# ls
00-RELEASENOTES COPYING MANIFESTO runtest-moduleapi TLS.md
appendonly.aof deps README.md runtest-sentinel utils
BUGS dump.rdb redis.conf sentinel.conf
CONDUCT INSTALL runtest src
CONTRIBUTING Makefile runtest-cluster tests
[root@192 redis-6.2.6]#

5.1.2 还原Redis数据

将 Redis 备份文件(dump.rdb)移动到 Redis 目录中并启动服务器以恢复 Redis 数据。

查找 Redis 的安装目录,使用 Redis 的 CONFIG 命令,如下所示。

1
2
3
4
127.0.0.1:6379> CONFIG get dir
1) "dir"
2) "/opt/software/redis-6.2.6"
127.0.0.1:6379>

Redis 服务器安装在/opt/software/redis-6.2.6目录中。

5.1.3 BGSAVE命令

BGSAVE 是创建 Redis 备份的备用命令。

此命令将启动备份过程并在后台运行。

  • 语法:

    1
    127.0.0.1:6379> BGSAVE
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    [root@192 redis-6.2.6]# src/redis-cli -a yanpenggong
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> CONFIG get dir
    1) "dir"
    2) "/opt/software/redis-6.2.6"
    127.0.0.1:6379> BGSAVE
    Background saving started
    127.0.0.1:6379>

5.2 Redis 持久化

redis 提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。

RDB,简而言之,就是在不同的时间点,将 redis 存储的数据生成快照并存储到磁盘等介质上;

AOF,则是换了一个角度来实现持久化,那就是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

其实 RDB 和 AOF 两种方式也可以同时使用,在这种情况下,如果 redis 重启的话,则会优先采用 AOF 方式来进行数据恢复,这是因为 AOF 方式的数据恢复完整度更高。

如果你没有数据持久化的需求,也完全可以关闭 RDB 和 AOF 方式,这样的话,redis 将变成一个纯内存数据库,就像 memcache 一样。

5.2.1 redis持久化RDB

RDB 方式,是将 redis 某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

redis 在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。

对于 RDB 方式,redis 会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何 IO 操作的,这样就确保了 redis 极高的性能。

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。

虽然 RDB 有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么 RDB 方式就不太适合你,因为即使你每 5 分钟都持久化一次,当 redis 故障时,仍然会有近 5 分钟的数据丢失。所以,redis 还提供了另一种持久化方式,那就是 AOF。

5.2.2 redis持久化 AOF

AOF,英文是 Append Only File,即只允许追加不允许改写的文件。

如前面介绍的,AOF 方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。

我们通过配置 redis.conf 中的 appendonly yes 就可以打开 AOF 功能。如果有写操作(如 SET 等),redis 就会被追加到 AOF 文件的末尾。

默认的 AOF 持久化策略是每秒钟 fsync 一次(fsync 是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis 仍然可以保持很好的处理性能,即使 redis 故障,也只会丢失最近 1 秒钟的数据。

如果在追加日志时,恰好遇到磁盘空间满、inode 满或断电等情况导致日志写入不完整,也没有关系,redis 提供了 redis-check-aof 工具,可以用来进行日志修复。

因为采用了追加方式,如果不做任何处理的话,AOF 文件会变得越来越大,为此,redis 提供了 AOF 文件重写(rewrite)机制,即当 AOF 文件的大小超过所设定的阈值时,redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了 100 次 INCR 指令,在 AOF 文件中就要存储 100 条指令,但这明显是很低效的,完全可以把这 100 条指令合并成一条 SET 指令,这就是重写机制的原理。

在进行 AOF 重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响 AOF 文件的可用性,这点大家可以放心。

AOF 方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作 redis 时,不小心执行了 FLUSHALL,导致 redis 内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要 redis 配置了 AOF 持久化方式,且 AOF 文件还没有被重写(rewrite),我们就可以用最快的速度暂停 redis 并编辑 AOF 文件,将最后一行的 FLUSHALL 命令删除,然后重启 redis,就可以恢复 redis 的所有数据到 FLUSHALL 之前的状态了。是不是很神奇,这就是 AOF 持久化方式的好处之一。但是如果 AOF 文件已经被重写了,那就无法通过这种方法来恢复数据了。

虽然优点多多,但 AOF 方式也同样存在缺陷,比如在同样数据规模的情况下,AOF 文件要比 RDB 文件的体积大。而且,AOF 方式的恢复速度也要慢于 RDB 方式。

如果你直接执行 BGREWRITEAOF 命令,那么 redis 会生成一个全新的 AOF 文件,其中便包括了可以恢复现有数据的最少的命令集。

如果运气比较差,AOF 文件出现了被写坏的情况,也不必过分担忧,redis 并不会贸然加载这个有问题的 AOF 文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

  1. 备份被写坏的 AOF 文件
  2. 运行 redis-check-aof –fix 进行修复
  3. 用 diff -u 来看下两个文件的差异,确认问题点
  4. 重启 redis,加载修复后的 AOF 文件

5.2.3 redis持久化 – AOF重写

AOF 重写的内部运行原理,我们有必要了解一下。

在重写即将开始之际,redis 会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的 AOF 文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的 AOF 文件中,这样做是保证原有的 AOF 文件的可用性,避免在重写过程中出现意外。

当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新 AOF 文件中。

当追加结束后,redis 就会用新 AOF 文件来代替旧 AOF 文件,之后再有新的写指令,就都会追加到新的 AOF 文件中了。

5.2.4 redis持久化 – 如何选择RDB和AOF

对于我们应该选择 RDB 还是 AOF,官方的建议是两个同时使用。这样可以提供更可靠的持久化方案。

5.3 redis安全

对于数据库来说,安全性是非常必要的,以确保数据的安全性。它提供身份验证,因此如果客户端想要建立连接,则需要在执行命令之前进行身份验证。

需要在配置文件中设置密码以保护 Redis 数据库。

实例:

1
2
3
4
127.0.0.1:6379> CONFIG get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379>

可以看到上面的属性为空,表示没有此实例的任何密码。

可以通过执行以下命令来更改此属性并为此实例设置密码。

1
2
3
4
5
6
7
127.0.0.1:6379> CONFIG set requirepass "yanpenggong"
OK
127.0.0.1:6379> quit
[root@192 redis-6.2.6]# src/redis-cli
127.0.0.1:6379> CONFIG get requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6379>

设置此密码时,如果客户端在未经身份验证的情况下运行该命令,则会收到错误“NOAUTH Authentication required。”。因此,客户端需要使用 AUTH 命令来验证自己。

5.3.1 AUTH命令的用法

1
2
3
4
5
6
7
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> SET myset "Hello World"
OK
127.0.0.1:6379> GET myset
"Hello World"
127.0.0.1:6379>

5.4 Redis 基准

Redis 基准测试 redis-benchmark 是一种实用工具,用于通过同时使用 multiple(n) 命令来检查 Redis 的性能。

  • 语法:

    1
    redis-benchmark [option] [option value]
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    [root@192 redis-6.2.6]# src/redis-benchmark -n 100000 -a yanpenggong
    ====== PING_INLINE ======
    100000 requests completed in 15.49 seconds
    50 parallel clients
    3 bytes payload
    keep alive: 1
    host configuration "save": 900 1 300 10 60 10000
    host configuration "appendonly": no
    multi-thread: no

    Latency by percentile distribution:
    0.000% <= 2.807 milliseconds (cumulative count 1)
    50.000% <= 5.791 milliseconds (cumulative count 50175)
    75.000% <= 6.711 milliseconds (cumulative count 75143)
    87.500% <= 7.351 milliseconds (cumulative count 87511)
    93.750% <= 8.007 milliseconds (cumulative count 93796)
    96.875% <= 8.671 milliseconds (cumulative count 96890)
    98.438% <= 9.351 milliseconds (cumulative count 98442)
    99.219% <= 10.039 milliseconds (cumulative count 99219)
    99.609% <= 10.783 milliseconds (cumulative count 99613)
    99.805% <= 11.319 milliseconds (cumulative count 99807)
    99.902% <= 11.999 milliseconds (cumulative count 99903)
    99.951% <= 13.351 milliseconds (cumulative count 99952)
    99.976% <= 16.463 milliseconds (cumulative count 99976)
    99.988% <= 29.823 milliseconds (cumulative count 99988)
    99.994% <= 30.511 milliseconds (cumulative count 99994)
    99.997% <= 30.735 milliseconds (cumulative count 99997)
    99.998% <= 30.911 milliseconds (cumulative count 99999)
    99.999% <= 31.023 milliseconds (cumulative count 100000)
    100.000% <= 31.023 milliseconds (cumulative count 100000)

    Cumulative distribution of latencies:
    0.000% <= 0.103 milliseconds (cumulative count 0)
    0.007% <= 3.103 milliseconds (cumulative count 7)
    8.508% <= 4.103 milliseconds (cumulative count 8508)
    32.111% <= 5.103 milliseconds (cumulative count 32111)
    58.966% <= 6.103 milliseconds (cumulative count 58966)
    83.729% <= 7.103 milliseconds (cumulative count 83729)
    94.418% <= 8.103 milliseconds (cumulative count 94418)
    98.012% <= 9.103 milliseconds (cumulative count 98012)
    99.266% <= 10.103 milliseconds (cumulative count 99266)
    99.737% <= 11.103 milliseconds (cumulative count 99737)
    99.915% <= 12.103 milliseconds (cumulative count 99915)
    99.948% <= 13.103 milliseconds (cumulative count 99948)
    99.956% <= 14.103 milliseconds (cumulative count 99956)
    99.962% <= 15.103 milliseconds (cumulative count 99962)
    99.970% <= 16.103 milliseconds (cumulative count 99970)
    99.979% <= 17.103 milliseconds (cumulative count 99979)
    99.980% <= 29.103 milliseconds (cumulative count 99980)
    99.991% <= 30.111 milliseconds (cumulative count 99991)
    100.000% <= 31.103 milliseconds (cumulative count 100000)

    Summary:
    throughput summary: 6454.53 requests per second
    latency summary (msec):
    avg min p50 p95 p99 max
    5.870 2.800 5.791 8.207 9.807 31.023
    ====== PING_MBULK ======
    100000 requests completed in 15.45 seconds
    50 parallel clients
    3 bytes payload
    keep alive: 1
    host configuration "save": 900 1 300 10 60 10000
    host configuration "appendonly": no
    multi-thread: no

    Latency by percentile distribution:
    0.000% <= 2.351 milliseconds (cumulative count 1)
    50.000% <= 5.727 milliseconds (cumulative count 50067)
    75.000% <= 6.671 milliseconds (cumulative count 75131)
    87.500% <= 7.415 milliseconds (cumulative count 87505)
    93.750% <= 8.263 milliseconds (cumulative count 93781)
    96.875% <= 9.119 milliseconds (cumulative count 96886)
    98.438% <= 9.871 milliseconds (cumulative count 98438)
    99.219% <= 10.567 milliseconds (cumulative count 99221)
    99.609% <= 11.207 milliseconds (cumulative count 99611)
    99.805% <= 11.863 milliseconds (cumulative count 99805)
    99.902% <= 12.575 milliseconds (cumulative count 99904)
    99.951% <= 13.471 milliseconds (cumulative count 99952)
    99.976% <= 14.479 milliseconds (cumulative count 99976)
    99.988% <= 15.255 milliseconds (cumulative count 99988)
    99.994% <= 15.703 milliseconds (cumulative count 99994)
    99.997% <= 16.303 milliseconds (cumulative count 99997)
    99.998% <= 16.479 milliseconds (cumulative count 99999)
    99.999% <= 16.607 milliseconds (cumulative count 100000)
    100.000% <= 16.607 milliseconds (cumulative count 100000)

    Cumulative distribution of latencies:
    0.000% <= 0.103 milliseconds (cumulative count 0)
    0.014% <= 3.103 milliseconds (cumulative count 14)
    9.664% <= 4.103 milliseconds (cumulative count 9664)
    33.922% <= 5.103 milliseconds (cumulative count 33922)
    60.409% <= 6.103 milliseconds (cumulative count 60409)
    83.670% <= 7.103 milliseconds (cumulative count 83670)
    92.958% <= 8.103 milliseconds (cumulative count 92958)
    96.842% <= 9.103 milliseconds (cumulative count 96842)
    98.776% <= 10.103 milliseconds (cumulative count 98776)
    99.566% <= 11.103 milliseconds (cumulative count 99566)
    99.843% <= 12.103 milliseconds (cumulative count 99843)
    99.937% <= 13.103 milliseconds (cumulative count 99937)
    99.968% <= 14.103 milliseconds (cumulative count 99968)
    99.985% <= 15.103 milliseconds (cumulative count 99985)
    99.996% <= 16.103 milliseconds (cumulative count 99996)
    100.000% <= 17.103 milliseconds (cumulative count 100000)

    Summary:
    throughput summary: 6472.91 requests per second
    latency summary (msec):
    avg min p50 p95 p99 max
    5.858 2.344 5.727 8.551 10.319 16.607
    SET: rps=7171.3 (overall: 5609.2) avg_msec=5.378 (overall: 6.777)
  • redis 性能测试工具可选参数

    | 序号 | 选项 | 描述 | 默认值 |
    | —— | ——- | ————————————————————— | ————- |
    | 1 | -h | 指定服务器主机名 | 127.0.0.1 |
    | 2 | -p | 指定服务器端口 | 6379 |
    | 3 | -s | 指定服务器 socket | |
    | 4 | -c | 指定并发连接数 | 50 |
    | 5 | -n | 指定请求数 | 10000 |
    | 6 | -d | 以字节的形式指定 SET/GET 值的数据大小 | 2 |
    | 7 | -k | 1=keep alive 0=reconnect | 1 |
    | 8 | -r | SET/GET/INCR 使用随机 key, SADD 使用随机值 | |
    | 9 | -P | 通过管道传输 请求 | 1 |
    | 10 | -q | 强制退出 redis。仅显示 query/sec 值 | |
    | 11 | —csv | 以 CSV 格式输出 | |
    | 12 | -l | 生成循环,永久执行测试 | |
    | 13 | -t | 仅运行以逗号分隔的测试命令列表 | |
    | 14 | -I | Idle 模式。仅打开 N 个 idle 连接并等待 | |

    实例:

    以下实例使用了多个参数来测试 redis 性能:主机为 127.0.0.1,端口号为 6379,执行的命令为 set,lpush,请求数为 10000,通过 -q 参数让结果只显示每秒执行的请求数。

    1
    2
    3
    4
    5
    [root@192 redis-6.2.6]# src/redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 100000 -q -a yanpenggong
    SET: 6676.46 requests per second, p50=5.639 msec
    LPUSH: 6538.51 requests per second, p50=5.775 msec

    [root@192 redis-6.2.6]#

5.5 Redis客户端连接

Redis 可以在配置的监听 TCP 端口和 Unix 套接字上接受不同类型的客户端连接。

接受新客户端连接时,它将执行以下操作:

  • 由于 Redis 使用多路复用和非阻塞 I/O,因此客户端套接字处于非阻塞状态。
  • 设置 TCP_NODELAY 选项是为了确保我们的连接没有延迟。
  • 创建可读文件事件,以便一旦可以在套接字上读取新数据,Redis 就能够收集客户端查询。

5.5.1 最大客户端数

在 Redis config(redis.conf)中,有一个名为 maxclients 的属性,它指定可以连接到 Redis 的客户端数量。

1
2
3
4
5
6
[root@192 redis-6.2.6]# src/redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> CONFIG get maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379>

最大客户端数取决于 OS 的最大文件描述符数限制。它的默认值为 10000,但您可以更改此属性。

实例: 在启动服务器时将最大客户端数设置为 100000。

1
[root@192 redis-6.2.6]# src/redis-server --maxclients 100000

5.5.2 Redis 客户端命令

序号 命令 描述
1 CLIENT LIST 返回连接到 redis 服务的客户端列表
2 CLIENT SETNAME 设置当前连接的名称
3 CLIENT GETNAME 获取通过 CLIENT SETNAME 命令设置的服务名称
4 CLIENT PAUSE 挂起客户端连接,指定挂起的时间以毫秒计
5 CLIENT KILL 关闭客户端连接

5.6 Redis Pipelining 流水线

在了解流水线之前,首先要了解 Redis 的概念:

Redis 是一个支持请求/响应协议的 TCP 服务器。在 Redis 中,请求分两步完成:

  • 客户端通常以阻塞方式向服务器发送命令。
  • 服务器处理该命令并将响应发送回客户端。

5.6.1 什么是流水线

流水线操作有助于客户端向服务器发送多个请求,而无需等待回复,最后只需一步即可读取回复。

: 向 Redis 提交一次命令,Redis 将在一个步骤中提供所有命令的输出。

1
[root@192 redis-6.2.6]# (echo -en  “PING\r\n SET sssit javatraining\r\n GET sssit\r\n INCR visitor\r\n INCR visitor\r\n INCR visitor\r\n” ; sleep  10 ) | nc localhost 6379 

这里:

  • PING 命令用于检查 Redis 连接。
  • 设置名为“sssit”的字符串,其值为“javatraining”。
  • 获得了 key 值并将访问者数量增加了三倍。

每次增加值时都可以看到。

5.6.2 流水线的优势

Redis 流水线操作的主要优点是提高了 Redis 的性能。由于多个命令同时执行,它极大地提高了协议性能。

5.6.3 Pipelining vs Scripting

Redis Scripting 可在 Redis 2.6 或更高版本中使用。

脚本的主要优点是它可以以最小的延迟同时读取和写入数据。它使读取,计算,写入等操作变得非常快。

在流水线操作中,客户端在调用 write 命令之前需要 read 命令的回复。

5.7 redis分区

分区用于将 Redis 数据拆分为多个 Redis 实例,以便每个实例仅包含一部分 key。

它通常用于大型数据库。

5.7.1 分区类型

redis 中有两种类型的分区:

  • 范围分区
  • 哈希分区

5.7.2 范围分区

范围分区是执行分区的最简单方法之一。它通过将对象的范围映射到特定的 Redis 实例来完成。

例如:

假设您有 3000 个用户。因此,您可以说从 ID 0 到 ID 1000 的用户将进入实例 R0,而用户表单 ID 1001 到 ID 2000 将进入实例 R1,用户表单 ID 2001 到 ID 3000 将进入实例 R2,依此类推。

5.7.3 哈希分区

散列分区是 Range 分区的替代方法。在散列分区中,散列函数用于将 key 转换为数字,然后将数据存储在不同的 Redis 实例中。

5.7.4 Redis分区的优点

  • 分区有助于您使用多台计算机的集体内存。例如:对于较大的数据库,您需要大量内存,因此分区可以提供来自不同计算机的内存总和。如果不进行分区,则只能使用单台计算机可以支持的有限内存量。
  • 分区还用于将计算能力扩展到多个核心和多个计算机,以及网络带宽扩展到多个计算机和网络适配器。

5.7.5 Redis分区的缺点

分区存在一些缺点,因为 Redis 的某些功能受到分区的阻碍。

  • 分区通常不支持具有多个键的操作。例如,如果两个集合存储在映射到不同 Redis 实例的键中,则无法执行它们之间的交集。
  • 分区不支持具有多个 key 的事务。
  • 分区粒度是关键,因此不可能使用单个巨大的 key(如非常大的有序集)对数据集进行分片。
  • 使用分区时,数据处理更复杂,例如,您必须处理多个 RDB / AOF 文件,并且需要从多个实例和主机聚合持久性文件来备份数据。
  • 添加和删除容量可能很复杂。例如,Redis Cluster 支持大多数透明的数据重新平衡,能够在运行时添加和删除节点,但客户端分区和代理等其他系统不支持此功能。然而,一种称为预分片的技术在这方面有所帮助。

Redis命令手册

1. 命令集合

1.1 Key(键)

1.1.1 DEL key

Redis DEL 命令用于删除给定的一个或多个 key 。不存在的 key 会被忽略。

  • 语法:

    1
    127.0.0.1:6379> DEL KEY_NAME
  • 返回值:

    整数: 被删除 key 的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> set kungs1 "Hello"
    OK
    127.0.0.1:6379> set kungs2 "World"
    OK
    127.0.0.1:6379> set kungs3 "redis"
    OK
    127.0.0.1:6379> DEL kungs1 kungs2 kungs3 kungs4
    3
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of keys that will be removed. When a key to remove holds a value other than a string, the individual complexity for this key is O(M) where M is the number of elements in the list, set, sorted set or hash. Removing a single key that holds a string value is O(1).

1.1.2 DUMP key

Redis DUMP 用于序列化给定 key ,并返回被序列化的值,使用 restore 命令可以将DUMP 的结果反序列化回 Redis 。

序列化格式有以下几个特点:

  • 它带有 64 位的校验和,用于检测错误, restore 在进行反序列化之前会先检查校验和。.
  • 值的编码格式和 RDB 文件保持一致。
  • RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本造成 RDB 格式不兼容,那么 Redis 会拒绝对这个值进行反序列化操作。

序列化的值不包括任何过期(expire)信息。

如果想获得 key 的剩余过期时间,需要使用 PTTL 命令。

如果 key 不存在,那么返回 nil

  • 语法:

    1
    127.0.0.1:6379> DUMP KEY_NAME
  • 返回值:

    多行字符串: 如果 key 不存在,那么返回 nil 。 否则,返回序列化之后的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> set kungskey 10
    OK
    127.0.0.1:6379> DUMP kungskey
    "\x00\xc0\n\t\x00\xbem\x06\x89Z(\x00\n"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1) to access the key and additional O(NM) to serialize it, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1M) where M is small, so simply O(1).

1.1.3 EXISTS key [key …]

Redis EXISTS 命令用于检查给定 key 是否存在。

从 Redis 3.0.3 起可以一次检查多个 key 是否存在。这种情况下,返回待检查 key 中存在的 key 的个数。检查单个 key 返回 1 或 0 。

注意:如果相同的 key 在参数列表中出现了多次,它会被计算多次。所以,如果somekey存在, EXISTS somekey somekey 命令返回 2。

  • 语法:

    1
    127.0.0.1:6379> EXISTS KEY_NAME
  • 返回值:

    整数:

    • 1: key存在
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET key1 "Hello"
    OK
    127.0.0.1:6379> EXISTS key1
    (integer) 1
    127.0.0.1:6379> EXISTS nosuchkey
    (integer) 0
    127.0.0.1:6379> SET key2 "World"
    OK
    127.0.0.1:6379> EXISTS key1 key2 nosuchkey
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.4 EXPIRE key seconds

Redis Expire 命令设置 key 的过期时间(seconds)。 设置的时间过期后,key 会被自动删除。带有超时时间的 key 通常被称为易失的(volatile)

超时时间只能使用删除 key 或者覆盖 key 的命令清除,包括 DEL, SET, GETSET 和所有的 *STORE 命令。 对于修改 key 中存储的值,而不是用新值替换旧值的命令,不会修改超时时间。例如,自增 key 中存储的值的 INCR, 向list中新增一个值 LPUSH, 或者修改 hash 域的值 HSET ,这些都不会修改 key 的过期时间。

通过使用 PERSIST 命令把 key 改回持久的(persistent) key,这样 key 的过期时间也可以被清除。

key使用 RENAME 改名后,过期时间被转移到新 key 上。

已存在的旧 key 使用 RENAME 改名,那么新 key 会继承所有旧 key 的属性。例如,一个名为 Key_A 的 key 使用命令 RENAME Key_B Key_A 改名,新的 Key_A 会继承包括超时时间在内的所有 Key_B 的属性。

特别注意,使用负值调用 EXPIRE/PEXPIRE 或使用过去的时间调用 EXPIREAT/PEXPIREAT ,那么 key 会被删除 deleted 而不是过期。 (因为, 触发的key event 将是 del, 而不是 expired).

1.1.5 EXPIREAT key timestamp

EXPIREATEXPIRE 有相同的作用和语义, 不同的是 EXPIREAT 使用绝对 Unix 时间戳 (自1970年1月1日以来的秒数)代替表示过期时间的秒数。使用过去的时间戳将会立即删除该 key。

详细语义功能说明可以参考 EXPIRE

  • 语法:

    1
    127.0.0.1:6379> Expireat KEY_NAME TIME_IN_UNIX_TIMESTAMP
  • 背景:

    EXPIREAT 引入的目的是为了把 AOF 持久化模式的相对时间转换为绝对时间。当然,也可以直接指明某个 key 在未来某个时间过期。

  • 返回值:

    整数:

    • 1: 设置超时成功
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> EXISTS mykey
    (integer) 1
    127.0.0.1:6379> EXPIREAT mykey 1293840000
    (integer) 1
    127.0.0.1:6379> EXISTS mykey
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.1.6 PEXPIRE key milliseconds

PEXPIREEXPIRE 基本一样,只是过期时间单位是毫秒。

  • 语法:

    1
    127.0.0.1:6379> PEXPIRE key milliseconds
  • 返回值:

    整数:

    • 1: 过期设置成功
    • 0: key不存在 或设置失败
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> PEXPIRE mykey 15000
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) 11
    127.0.0.1:6379> PTTL mykey
    (integer) 7039
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.7 PEXPIREAT key milliseconds-timestamp

Redis PEXPIREAT 命令用于设置 key 的过期时间,时间的格式是uinx时间戳并精确到毫秒。

  • 语法:

    1
    127.0.0.1:6379> PEXPIREAT KEY_NAME TIME_IN_MILLISECONDS_IN_UNIX_TIMESTAMP
  • 返回值:

    整数:

    • 1: 设置成功返回
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> PEXPIREAT mykey 150000000000
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) -2
    127.0.0.1:6379> PTTL mykey
    (integer) -2
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.8 KEYS pattern

Redis KEYS 命令用于查找所有匹配给定模式 pattern 的 key 。

尽管这个操作的时间复杂度是 O(N),但是常量时间相当小。

例如,在一个普通笔记本上跑 Redis,扫描 100 万个 key 只要40毫秒。

Warning: 生产环境使用 KEYS 命令需要非常小心。在大的数据库上执行命令会影响性能。

这个命令适合用来调试和特殊操作,像改变键空间布局。

不要在你的代码中使用 KEYS 。如果你需要一个寻找键空间中的key子集,考虑使用 SCANSets

匹配模式:

  • h?llo 匹配 hello, hallohxllo
  • h*llo 匹配 hlloheeeello
  • h[ae]llo 匹配 hello and hallo, 不匹配 hillo
  • h[^e]llo 匹配 hallo, hbllo, … 不匹配 hello
  • h[a-b]llo 匹配 hallohbllo

使用 \ 转义你想匹配的特殊字符。

1.1.9 MOVE key db

Redis MOVE 命令用于将当前数据库的 key 移动到选定的数据库 db 当中。

如果 key 在目标数据库中已存在,或者 key 在源数据库中不存,则key 不会被移动。

  • 语法:

    1
    127.0.0.1:6379> MOVE KEY_NAME DESTINATION_DATABASE
  • 返回值:

    整数:

    • 1: key 被移动
    • 0: key 没有被移动
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    # key 存在于当前数据库
    # redis默认使用数据库 0,为了清晰起见,这里再显式指定一次。
    127.0.0.1:6379> select 0
    OK
    127.0.0.1:6379> set kungs "yanpenggong base -Zone"
    OK
    # 将 kungs 移动到数据库 1
    127.0.0.1:6379> move kungs 1
    (integer) 1
    # kungs 已经被移走
    127.0.0.1:6379> exists kungs
    (integer) 0
    # 使用数据库 1
    127.0.0.1:6379> select 1
    OK
    # 证实 kungs 被移到了数据库 1
    # (注意命令提示符变成了"127.0.0.1:6379[1]",表明正在使用数据库 1)
    127.0.0.1:6379[1]> exists kungs
    (integer) 1
    # 当 key 不存在的时候
    127.0.0.1:6379[1]> exists fake_key
    (integer) 0
    # 试图从数据库 1 移动一个不存在的 key 到数据库 0,失败
    127.0.0.1:6379[1]> move fake_key 0
    (integer) 0
    # 使用数据库0
    127.0.0.1:6379[1]> select 0
    OK
    # 证实 fake_key 不存在
    127.0.0.1:6379> exists fake_key
    (integer) 0

    # 当源数据库和目标数据库有相同的 key 时
    # 使用数据库0
    127.0.0.1:6379> select 0
    OK
    127.0.0.1:6379> set fruit "apple"
    OK
    # 使用数据库1
    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]> set fruit "pineappleC"
    OK
    # 使用数据库0,并试图将 fruit 移动到数据库 1
    127.0.0.1:6379[1]> select 0
    OK
    # 因为两个数据库有相同的 key,MOVE 失败
    127.0.0.1:6379> move fruit 1
    (integer) 0
    # 数据库 0 的 fruit 没变
    127.0.0.1:6379> get fruit
    "apple"
    # 数据库 1 的 fruit 也是
    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]> get fruit
    "pineappleC"
    127.0.0.1:6379[1]>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.10 PERSIST key

Redis PERSIST 命令用于删除给定 key 的过期时间,使得 key 永不过期。

  • 语法:

    1
    127.0.0.1:6379> PERSIST KEY_NAME
  • 返回值:

    整数:

    • 1: 当过期时间移除成功时
    • 0: key不存在或 key 没有设置过期时间
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SET mykey "Hello"
    OK
    # 为 key 设置生存时间
    127.0.0.1:6379> EXPIRE mykey 10
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) 8
    # 移除 key 的生存时间
    127.0.0.1:6379> PERSIST mykey
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) -1
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.1.11 PTTL key

Redis PTTL 命令以毫秒为单位返回 key 的剩余过期时间。

  • 语法:

    1
    127.0.0.1:6379> PTTL KEY_NAME
  • 返回值:

    Redis 2.6 之前的版本如果 key 不存在或者 key 没有关联超时时间则返回 -1

    Redis 2.8 起:

    • key 不存在返回 -2
    • key 存在但是没有关联超时时间返回 -1

    整数:

    • -1: key 存在但没有设置剩余生存时间
    • -2: key 不存在
    • 其它: 以毫秒为单位,返回 key 的剩余生存时间
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> set mykey "Hello"
    OK
    # key 存在,但没有设置剩余生存时间
    127.0.0.1:6379> PTTL mykey
    (integer) -1
    127.0.0.1:6379> EXPIRE mykey 1000
    (integer) 1
    # 有剩余生存时间的 key
    127.0.0.1:6379> PTTL mykey
    (integer) 998591
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.12 TTL key

Redis TTL 命令以秒为单位返回 key 的剩余过期时间。用户客户端检查 key 还可以存在多久。

  • Redis 2.6 之前的版本如果 key 不存在或者 key 没有关联超时时间则返回 -1 。
  • Redis 2.8 起:
    • key 不存在返回 -2
    • key 存在但是没有关联超时时间返回 -1
    • PTTL 返回以毫秒为单位的剩余超时时间。
  • 返回值:

    整数: 剩余超时秒数,失败返回负数如上。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> set mykey "Hello"
    OK
    # key 存在,但没有设置剩余生存时间
    127.0.0.1:6379> TTL mykey
    (integer) -1
    127.0.0.1:6379> EXPIRE mykey 1000
    (integer) 1
    # 有剩余生存时间的 key
    127.0.0.1:6379> TTL mykey
    (integer) 998
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.13 RANDOMKEY

Redis RANDOMKEY 命令从当前数据库中随机返回一个 key 。

  • 语法:

    1
    127.0.0.1:6379> RANDOMKEY 
  • 返回值:

    多行字符串: 当数据库不为空时,返回一个 key 。 当数据库为空时,返回 nil 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> MSET fruit "apple" drink "beer" food "cookies"
    OK
    127.0.0.1:6379> KEYS *
    1) "food"
    2) "drink"
    3) "fruit"
    127.0.0.1:6379> RANDOMKEY
    "food"
    127.0.0.1:6379> RANDOMKEY
    "fruit"
    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> RANDOMKEY
    (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.14 RENAME key newkey

Redis RENAME 命令用于修改 key 的名字为 newkey 。若key 不存在返回错误。

在集群模式下,key 和newkey 需要在同一个 hash slot。key 和newkey有相同的 hash tag 才能重命名。

如果 newkey 存在则会被覆盖,此种情况隐式执行了 DEL 操作,所以如果要删除的key的值很大会有一定的延时,即使RENAME 本身是常量时间复杂度的操作。

在集群模式下,key 和newkey 需要在同一个 hash slot。key 和newkey有相同的 hash tag 才能重命名。

  • 历史:

    <= 3.2.0: 源 key 和目的 key 相同返回错误。

  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # key 存在且 newkey 不存在
    127.0.0.1:6379> set mykey "Hello"
    OK
    127.0.0.1:6379> RENAME mykey mykey1
    OK
    127.0.0.1:6379> get mykey1
    "Hello"
    # 当 key 不存在时,返回错误
    127.0.0.1:6379> RENAME mykey2 mykey22
    (error) ERR no such key
    # newkey 已存在时, RENAME 会覆盖旧 newkey
    127.0.0.1:6379> set pc "macpro"
    OK
    127.0.0.1:6379> set personal_computer "thinkpad"
    OK
    127.0.0.1:6379> RENAME pc personal_computer
    OK
    127.0.0.1:6379> get pc
    (nil)
    # 原来的值 thinkpad 被覆盖了
    127.0.0.1:6379> get personal_computer
    "macpro"
    127.0.0.1:6379>

    可用版本>= 1.0.0.

    时间复杂度: O(1)

1.1.15 RENAMENX key newkey

Redis Renamenx 命令用于在新的 key 不存在时修改 key 的名称 。若 key 不存在返回错误。

在集群模式下,keynewkey 需要在同一个 hash slotkeynewkey有相同的 hash tag 才能重命名。

  • 语法:

    1
    127.0.0.1:6379> RENAMENX OLD_KEY_NAME NEW_KEY_NAME
  • 历史:

  • 返回值:

    整数:

    • 1: rename 成功
    • 0: newkey 已经存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # newkey 不存在,改名成功
    127.0.0.1:6379> set mykey "Hello"
    OK
    127.0.0.1:6379> RENAMENX mykey myotherkey
    (integer) 1
    127.0.0.1:6379> GET myotherkey
    "Hello"
    # newkey存在时,失败
    127.0.0.1:6379> SET animal "bear"
    OK
    127.0.0.1:6379> SET favorite_animal "butterfly"
    OK
    127.0.0.1:6379> RENAMENX animal favorite_animal
    (integer) 0
    127.0.0.1:6379> get animal
    "bear"
    127.0.0.1:6379> get favorite_animal
    "butterfly"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.16 SCAN cursor [MATCH pattern] [COUNT count]

Redis SCAN 命令及其相关命令 SSCAN, HSCAN, ZSCAN 命令都是用于增量遍历集合中的元素。

  • SCAN: 命令用于迭代当前数据库中的数据库键
  • SSCAN: 命令用于迭代集合键中的元素。
  • HSCAN: 命令用于迭代哈希键中的键值对。
  • ZSCAN: 命令用于迭代有序集合中的元素(包括元素成员和元素分值)。

以上列出的四个命令都支持增量式迭代, 它们每次执行都只会返回少量元素, 所以这些命令可以用于生产环境, 而不会出现像 KEYS 命令、 SMEMBERS 命令带来的问题 —— 当 KEYS 命令被用于处理一个大的数据库时, 又或者 SMEMBERS 命令被用于处理一个大的集合键时, 它们可能会阻塞服务器达数秒之久。

不过, 增量式迭代命令也不是没有缺点的: 举个例子, 使用 SMEMBERS 命令可以返回集合键某一时刻包含的所有元素, 但是对于 SCAN 这类增量式迭代命令来说, 因为在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令不能完全保证返回所有元素。

因为 SCAN 、 SSCAN 、 HSCAN 和 ZSCAN 四个命令的工作方式都非常相似, 所以这个文档会一并介绍这四个命令, 但是要记住:SSCAN 命令、 HSCAN 命令和 ZSCAN 命令的第一个参数总是一个存储集合的键名。而 SCAN 命令则不需要在第一个参数提供任何数据库键 —— 因为它迭代的是当前数据库中的所包含的键。

  1. SCAN 命令的基本用法

    SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。

    SCAN 返回一个包含两个元素的数组, 第一个元素是用于进行下一次迭代的新游标, 而第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代,而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    127.0.0.1:6379> scan 0
    1) "17"
    2) 1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
    10) "key:7"
    11) "key:1"
    127.0.0.1:6379> scan 17
    1) "0"
    2) 1) "key:5"
    2) "key:18"
    3) "key:0"
    4) "key:2"
    5) "key:19"
    6) "key:13"
    7) "key:6"
    8) "key:9"
    9) "key:11"

    在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。第二次迭代使用的是第一次迭代时返回的游标, 也就是命令回复第一个元素的值 —— 17

  1. SCAN 命令的保证

    • 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。
    • 如果有一个元素, 它从遍历开始就已经被删除,且直到遍历结束也没有被添加回来, 那么 SCAN 命令确保不会返回这个元素。

    然而因为 SCAN 命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点:

    • 同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
    • 如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。
  1. SCAN 命令每次执行返回的元素数量

    SCAN 命令族并不保证每次执行都返回某个给定数量的元素。增量式命令甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。

    不过命令返回的元素数量总是符合一定规则的, 在实际中:对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;而对于一个足够小的数据集来说, 小集合键、小哈希键和小有序集合键, 那么增量迭代命令将在一次调用中返回数据集中的所有元素。

    最后, 用户可以通过增量式迭代命令提供的 COUNT 选项来指定每次迭代返回元素的最大值。

  1. COUNT 选项

    虽然 SCAN 命令不保证每次迭代所返回的元素数量, 但我们可以使用 COUNT选项, 对命令的行为进行一定程度上的调整。 COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。虽然这个选项只是对增量式迭代命令的一种提示(hint), 但是在大多数情况下, 这种提示都是有效的。

    • COUNT 参数的默认值为 10
    • 在迭代一个足够大的、由哈希表实现的数据库、集合键、哈希键或者有序集合键时, 如果用户没有使用 MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
    • 在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。

    Important: 并非每次迭代都要使用相同的 COUNT **值。用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。

  1. MATCH 选项

    和 KEYS 命令一样, SCAN命令族也可以通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素, 这一点可以通过在执行增量式迭代命令时, 通过给定 MATCH <pattern> 参数来实现。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood
    (integer) 6
    127.0.0.1:6379> sscan myset 0 match f*
    1) "0"
    2) 1) "foo"
    2) "feelsgood"
    3) "foobar"
    127.0.0.1:6379>

    对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    127.0.0.1:6379> scan 0 MATCH *11*
    1) "288"
    2) 1) "key:911"
    127.0.0.1:6379> scan 288 MATCH *11*
    1) "224"
    2) (empty list or set)
    127.0.0.1:6379> scan 224 MATCH *11*
    1) "80"
    2) (empty list or set)
    127.0.0.1:6379> scan 80 MATCH *11*
    1) "176"
    2) (empty list or set)
    127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
    1) "0"
    2) 1) "key:611"
    2) "key:711"
    3) "key:118"
    4) "key:117"
    5) "key:311"
    6) "key:112"
    7) "key:111"
    8) "key:110"
    9) "key:113"
    10) "key:211"
    11) "key:411"
    12) "key:115"
    13) "key:116"
    14) "key:114"
    15) "key:119"
    16) "key:811"
    17) "key:511"
    18) "key:11"
    127.0.0.1:6379>

    我们可以看到, 以上的大部分迭代都不返回任何元素。

    在最后一次迭代, 我们通过将 COUNT 选项的参数设置为 1000 , 强制命令为本次迭代扫描

更多元素, 从而使得命令返回的元素也变多了

  • 语法:

    1
    SCAN cursor [MATCH pattern] [COUNT count]

    参数说明:

    • cursor - 游标。
    • pattern - 匹配的模式。
    • count - 指定从数据集里返回多少元素,默认值为 10 。
  • 返回值:

    数组列表

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 使用 0 作为游标,开始新的迭代
    127.0.0.1:6379> scan 0
    1) "0"
    2) 1) "favorite_animal"
    2) "personal_computer"
    3) "myotherkey"
    4) "mykey1"
    5) "animal"
    # 使用的是第一次迭代时返回的游标 12 开始新的迭代
    127.0.0.1:6379> scan 12
    1) "0"
    2) 1) "favorite_animal"
    2) "personal_computer"
    3) "myotherkey"
    4) "mykey1"
    5) "animal"
    # 使用的是第一次迭代时返回的游标 3 开始新的迭代
    127.0.0.1:6379> scan 3
    1) "0"
    2) 1) "myotherkey"
    2) "mykey1"
    3) "animal"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.

1.1.17 TYPE key

Redis Type 命令用于返回 key 所储存的值的类型。

  • 语法:

    1
    127.0.0.1:6379> TYPE KEY_NAME 
  • 返回值:

    返回 key 的数据类型,数据类型有:

    • none (key不存在)
    • string (字符串)
    • list (列表)
    • set (集合)
    • zset (有序集)
    • hash (哈希表)
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SET key1 "value"
    OK
    127.0.0.1:6379> LPUSH key2 "value"
    (integer) 1
    127.0.0.1:6379> SADD key3 "value"
    (integer) 1
    127.0.0.1:6379> TYPE key1
    string
    127.0.0.1:6379> TYPE key2
    list
    127.0.0.1:6379> TYPE key3
    set
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.18 MIGRATE host port key|\”\” destination-db timeout [COPY] [REPLACE] [AUTH password] [AUTH2 username password] [KEYS key [key …]]

将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 会出现在目标实例上,而当前实例上的 key 会被删除。

MIGRATE 命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等待超时。

  • 一次迁移多个 key:

    Redis 3.0.6 起MIGRATE 支持批量迁移。需要使用 KEYS 选项,使用空字符串替换 key,要迁移的 key 列在 KEYS 命令之后:

    1
    MIGRATE 192.168.1.34 6379 "" 0 5000 KEYS key1 key2 key3

    当所有 key 都不存在时返回 NOKEY ,即使只有一个key存在也执行成功。

  • Options:

    • COPY — 复制,不删除源实例中的 key。
    • REPLACE — 替换,替换目标实例中的存在的 key。
    • KEYS — 如果 key 参数是一个空字符串,会迁移 KEYS 命令后所有的 key 。
    • AUTH — 使用密码访问目标数据库。
    • AUTH2 — 使用用户名和密码对访问数据库。 (Redis 6 以上 ACL auth )。
  • 返回值:

    字符串: 迁移成功时返回 OK ,如果在源实例中找不到 key 返回 NOKEY 。

可用版本>= 2.6.0.

时间复杂度: This command actually executes a DUMP+DEL in the source instance, and a RESTORE in the target instance. See the pages of these commands for time complexity. Also an O(N) data transfer between the two instances is performed.

1.2 String(字符串)

1.2.1 SET key value [EX seconds|PX milliseconds|KEEPTTL] [NX|XX] [GET]

Redis SET 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。

  • 语法:

    1
    127.0.0.1:6379> SET KEY_NAME VALUE
  • 返回值:

    • 字符串: 如果SET命令正常执行那么回返回OK

    • 多行字符串: 使用 GET 选项,返回 key 存储的值

    • : key 不存在,否则如果加了NX 或者 XX选项,SET 没执行,那么会返回nil。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379> SET anotherkey "will expire in a minute" EX 60
    OK
    127.0.0.1:6379> get anotherkey
    "will expire in a minute"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.2 GET key

返回与键 key 相关联的字符串值,用于获取指定 key 的值。

如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。

如果键 key 的值不是字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。

  • 返回值:

    多行字符串: 返回key中存储的值,key 不存在是返回nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 对不存在的 key 进行 GET
    127.0.0.1:6379> GET nonexisting
    (nil)
    127.0.0.1:6379> SET mykey "Hello"
    "OK"
    # 对字符串类型 key 进行 GET
    127.0.0.1:6379> GET mykey
    "Hello"
    # 对不是字符串类型的 key 进行 GET
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> GET myhash
    ERR WRONGTYPE Operation against a key holding the wrong kind of value
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.3 GETRANGE key start end

GETRANGE 命令返回存储在 key 中的字符串的子串,由 start 和 end 偏移决定(都包括在内)。负数偏移提供相对字符串结尾的偏移。所以, -1 表示最后一个字符, -2 表示倒数第二个字符,以此类推。
GETRANGE 通过将结果范围限制为字符串的实际长度来处理超出范围的请求。
Warning: GETRANGE 是改名而来,在 Redis2.0 以前版本叫做 SUBSTR 。

  • 语法:

    1
    127.0.0.1:6379> GETRANGE KEY_NAME start end
  • 返回值:

    多行字符串:截取得到的子字符串。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET mykey "This is a string yanpenggong"
    OK
    127.0.0.1:6379> GETRANGE mykey 0 3
    "This"
    127.0.0.1:6379> GETRANGE mykey -3 -1
    "ong"
    127.0.0.1:6379> GETRANGE mykey 0 -1
    "This is a string yanpenggong"
    127.0.0.1:6379> GETRANGE mykey 10 100
    "string yanpenggong"
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered O(1) for small strings.

1.2.4 GETSET key value

将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。

返回给定键 key 的旧值。

如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil

当键 key 存在但不是字符串类型时, 命令返回一个错误。

  • 语法:

    1
    127.0.0.1:6379> GETSET KEY_NAME VALUE
  • 返回值:

    返回给定 key 的旧值。 当 key 没有旧值时,即 key 不存在时,返回 nil 。

    当 key 存在但不是字符串类型时,返回一个错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 没有旧值,返回 nil
    127.0.0.1:6379> GETSET db redis
    (nil)
    127.0.0.1:6379> GET db
    "redis"
    # 返回旧值 redis
    127.0.0.1:6379> GETSET db mongodb
    "redis"
    127.0.0.1:6379> GET db
    "mongodb"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.5 GETBIT key offset

key 所储存的字符串值,获取指定偏移量上的位(bit)。

offset 比字符串值的长度大,或者 key 不存在时,返回 0

1.2.6 MGET key [key …]

Redis MGET 命令返回所有(一个或多个)给定 key 的值,值的类型是字符串。 如果给定的 key 里面,有某个 key 不存在或者值不是字符串,那么这个 key 返回特殊值 nil

  • 语法:

    1
    127.0.0.1:6379> MGET KEY1 KEY2 .. KEYN
  • 返回值:

    数组: MGET 命令将返回一个列表, 列表中包含了所有给定键的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET key1 "Hello"
    OK
    127.0.0.1:6379> SET key2 "World"
    OK
    127.0.0.1:6379> MGET key1 key2 nonexisting
    1) "Hello"
    2) "World"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of keys to retrieve.

1.2.7 SETBIT key offset value

Redis Setbit 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。

根据值 value 是 1 或 0 来决定设置或清除位 bit。当 key 不存在时会创建一个新的字符串。

当字符串不够长时,字符串的长度将增大,以确保它可以在offset位置存储值。

offset 参数需要大于等于0,并且小于 $2^{32}$ (bitmaps 最大 512MB)。

当值字符串变长时,添加的 bit 会被设置为 0。

注意: 当设置的是最后一位 bit (offset 等于 $2^{32} -1$),并且存储在 key 中的字符串还没有存储一个字符串值,或者存储的是一个短的字符串值时,Redis 需要分配所有的中间内存,这会阻塞 Redis 服务器一段时间。

在 2010 年的 MacBook Pro上:

  • 设置 $2^{32} -1$ 位 (分配512MB内存) 需花费 300ms,
  • 设置 $2^{30} -1$ 位 (分配 128MB 内存) 需花费 80m,
  • 设置 $2^{28} -1$ 位 (分配 32MB 内存) 需花费 30ms,
  • 设置 $2^{26} -1$ 位 (分配 8MB 内存) 需花费 8ms。

需要注意的是,一旦上面第一步内存分配被完成,对于同一个 key 接下来调用 SETBIT 将不会有分配内存开销。

  • 语法:

    1
    127.0.0.1:6379> SETBIT key offset value
  • 返回值:

    整数: 存储在 offset 偏移位的原始值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SETBIT bit 10086 1
    (integer) 0
    127.0.0.1:6379> GETBIT bit 10086
    (integer) 1
    # bit 默认被初始化为 0
    127.0.0.1:6379> GETBIT bit 100
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.2.8 SETEX key seconds value

SETEX 命令将键 key 的值设置为 value , 并将键 key 的生存时间设置为 seconds 秒钟。

如果键 key 已经存在, 那么 SETEX 命令将覆盖已有的值。

SETEX 命令的效果和以下两个命令的效果类似:

1
2
127.0.0.1:6379> SET mykey value
127.0.0.1:6379> EXPIRE mykey seconds

SETEX 和这两个命令的不同之处在于 SETEX 是一个原子(atomic)操作, 它可以在同一时间内完成设置值和设置过期时间这两个操作, 因此 SETEX 命令在Redis用做缓存的时候非常实用。

  • 语法:

    1
    127.0.0.1:6379> SETEX KEY_NAME TIMEOUT VALUE
  • 返回值:

    字符串:命令在设置成功时返回 OK 。 当 seconds 参数不合法时, 命令将返回ERR ERR value is not an integer or out of range错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SETEX mykey 10 "Hello"
    OK
    127.0.0.1:6379> TTL mykey
    (integer) 9
    127.0.0.1:6379> GET mykey
    "Hello"
    # 等几秒再看看输出
    127.0.0.1:6379> TTL mykey
    (integer) -2
    127.0.0.1:6379> GET mykey
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.2.9 SETNX key value

Redis Setnx( SET if Not exists )命令在指定的 key 不存在时,为 key 设置指定的值,这种情况下等同 SET 命令。当 key存在时,什么也不做。

  • 语法:

    1
    127.0.0.1:6379> SETNX KEY_NAME VALUE
  • 返回值:

    整数:

    • 1: 如果key被设置了
    • 0: 如果key没有被设置
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # mykey 不存在
    127.0.0.1:6379> EXISTS mykey
    (integer) 0
    # mykey 设置成功
    127.0.0.1:6379> SETNX mykey "Hello"
    (integer) 1
    # 尝试覆盖,但是失败
    127.0.0.1:6379> SETNX mykey "World"
    (integer) 0
    # 没有被覆盖
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.10 SETRANGE key offset value

SETRANGE 命令从偏移量 offset 开始, 用 value 参数覆盖键 key 储存的字符串值。

不存在的键 key 当作空白字符串处理。

SETRANGE命令会确保字符串足够长以便将 value 设置到指定的偏移量上, 如果键 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset10 ), 那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )进行填充。

因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 $2^{29}-1$(536870911) , 如果你需要使用比这更大的空间, 请使用多个 key

Warning: 当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: SETRANGE命令会返回被修改之后, 字符串值的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET key1 "Hello world"
    OK
    127.0.0.1:6379> SETRANGE key1 6 "Redis"
    (integer) 11
    127.0.0.1:6379> GET key1
    "Hello Redis"
    127.0.0.1:6379> SETRANGE key2 6 "Redis"
    (integer) 11
    127.0.0.1:6379> GET key2
    "\x00\x00\x00\x00\x00\x00Redis"
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.

1.2.11 STRLEN key

Redis Strlen 命令用于获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串类型时,返回错误。

  • 语法:

    1
    127.0.0.1:6379> STRLEN KEY_NAME
  • 返回值

    整数: 字符串的长度,key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 获取字符串的长度
    127.0.0.1:6379> SET mykey "Hello World"
    OK
    127.0.0.1:6379> STRLEN mykey
    (integer) 11
    # 不存在的 key 长度为 0
    127.0.0.1:6379> STRLEN nonexisting
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.2.12 MSET key value [key value …]

Redis MSET 命令设置多个 key 的值为各自对应的 value。

MSETSET 一样,会用新值替换旧值。如果你不想覆盖旧值,可以使用 MSETNX

MSET 是原子操作,所有 key 的值同时设置。客户端不会看到有些 key 值被修改,而另一些 key 值没变。

  • 语法:

    1
    127.0.0.1:6379> MSET key1 value1 key2 value2 .. keyN valueN
  • 返回值:

    字符串: 总是返回”OK”,因为 MSET不会失败。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> MSET key1 "Hello" key2 "World"
    OK
    127.0.0.1:6379> GET key1
    "Hello"
    127.0.0.1:6379> GET key2
    "World"
    127.0.0.1:6379>

可用版本>= 1.0.1.

时间复杂度: O(N) where N is the number of keys to set.

1.2.13 MSETNX key value [key value …]

当且仅当所有给定键都不存在时, 为所有给定键设置值。

即使只有一个给定键已经存在, MSETNX 命令也会拒绝执行对所有键的设置操作。

MSETNX 是一个原子性(atomic)操作, 所有给定键要么就全部都被设置, 要么就全部都不设置。

MSETNX 可以用来设置逻辑对象的属性,来确保要么都设置,要么都不设置。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数:

    • 1: 当所有给定键都设置成功时
    • 0: 某个给定键已经存在而导致设置未能成功
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> MSETNX key1 "Hello" key2 "there"
    (integer) 1
    127.0.0.1:6379> MSETNX key2 "new" key3 "world"
    (integer) 0
    127.0.0.1:6379> MGET key1 key2 key3
    1) "Hello"
    2) "there"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 1.0.1.

时间复杂度: O(N) where N is the number of keys to set.

1.2.14 PSETEX key milliseconds value

PSETEX 命令和 SETEX 命令相似, 但它以毫秒为单位设置 key 的生存时间, 而不是像 SETEX 命令那样以秒为单位进行设置。

  • 语法:

    1
    127.0.0.1:6379> PSETEX key milliseconds value
  • 返回值:

    设置成功时返回”OK”

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> PSETEX mykey 10000 "Hello"
    OK
    127.0.0.1:6379> PTTL mykey
    (integer) 8171
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.2.15 INCR key

Redis INCR命令将 key 中储存的数字值增一。

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。

如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。

本操作的值限制在 64 位(bit)有符号数字表示之内。

Note: 本质上这是一个字符串操作,因为Redis没有专门的整数类型。存储在 key 中的字符串被转换为十进制有符号整数,在此基础上加1。

  • 语法:

    1
    127.0.0.1:6379> INCR KEY_NAME
  • 返回值:

    整数: 执行 INCR 命令之后 key 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> INCR mykey
    (integer) 11
    127.0.0.1:6379> GET mykey
    "11"
    # 数字值在 Redis 中以字符串的形式保存
    127.0.0.1:6379> SET mykey 20
    OK
    127.0.0.1:6379> INCR mykey
    (integer) 21
    127.0.0.1:6379> GET mykey
    "21"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.16 INCRBY key increment

Redis INCRBY 命令将 key 中储存的数字加上指定的增量值。

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。

如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。

本操作的值限制在 64 位(bit)有符号数字表示之内。

关于递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。

  • 语法:

    1
    127.0.0.1:6379> INCRBY key increment
  • 返回值:

    整数: 命令执行之后 key 中 存储的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> INCRBY mykey 5
    (integer) 15
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.17 INCRBYFLOAT key increment

为键 key 中储存的值加上浮点数增量 increment ,key 中的浮点数是以字符串形式存储的。

如果键 key 不存在, 那么 INCRBYFLOAT 会先将键 key 的值设为 0 , 然后再执行加法操作。

如果命令执行成功, 那么键 key 的值会被更新为执行加法计算之后的新值, 并且新值会以字符串的形式返回给调用者。

无论是键 key 的值还是增量 increment , 都可以使用像 2.0e73e590e-2 那样的指数符号(exponential notation)来表示, 但是, 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存, 也即是, 它们总是由一个数字, 一个(可选的)小数点和一个任意长度的小数部分组成(比如 3.1469.768 ,诸如此类), 小数部分尾随的 0 会被移除, 如果可能的话, 命令还会将浮点数转换为整数(比如 3.0 会被保存成 3 )。

此外, 无论加法计算所得的浮点数的实际精度有多长, INCRBYFLOAT命令的计算结果最多只保留小数点的后十七位。

当以下任意一个条件发生时, 命令返回一个错误:

  • key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型);
  • key 当前的值或者给定的增量 increment 不能被解释(parse)为双精度浮点数。

  • 语法:

    1
    127.0.0.1:6379> INCRBYFLOAT key increment
  • 返回值:

    多行字符串: 在加上增量 increment 之后, 键 key 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET mykey 10.50
    OK
    127.0.0.1:6379> INCRBYFLOAT mykey 0.1
    "10.6"
    127.0.0.1:6379> INCRBYFLOAT mykey -5
    "5.6"
    127.0.0.1:6379> SET mykey 5.0e3
    OK
    127.0.0.1:6379> INCRBYFLOAT mykey 2.0e2
    "5200"
    127.0.0.1:6379>
  • 实现细节

    INCR 命令族主要用在复制和 AOF 文件中,用来当做 SET,减少源 SET 命令个数,浮点的实现差异不会是不一致的来源。

可用版本>= 2.6.0.

时间复杂度: O(1)

1.2.18 DECR key

为键 key 储存的数字值减去一。

如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。

如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。

本操作的值限制在 64 位(bit)有符号数字表示之内。

  • 语法:

    1
    127.0.0.1:6379> DECR key
  • 返回值:

    整数: 执行操作之后key中的值

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> DECR mykey
    (integer) 9
    127.0.0.1:6379> SET mykey "13621873621786345326"
    OK
    127.0.0.1:6379> DECR mykey
    (error) ERR value is not an integer or out of range
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.19 DECRBY key decrement

将键 key 储存的整数值减去减量 decrement 。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: DECRBY 命令会返回键在执行减法操作之后的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> DECRBY mykey 3
    (integer) 7
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.20 APPEND key value

Redis APPEND 命令用于为指定的 key 追加值。
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。

  • 语法:

    1
    127.0.0.1:6379> APPEND KEY_NAME NEW_VALUE
  • 返回值:

    整数: 追加指定值之后, key 中字符串的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 确保 myphone 不存在
    127.0.0.1:6379> EXISTS myphone
    (integer) 0
    # 对不存在的key 进行APPEND,等同于 SET myphone "nokia"
    127.0.0.1:6379> APPEND myphone "nokia"
    (integer) 5
    # 对已存在的字符串进行 APPEND。长度从5个字符串增加到11个字符串
    127.0.0.1:6379> APPEND myphone " - 222"
    (integer) 11
    127.0.0.1:6379> GET myphone
    "nokia - 222"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by Redis will double the free space available on every reallocation.

1.3 Hash(哈希表)

1.3.1 HDEL key field [field …]

Redis HDEL 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。 如果 key 粗存在,会被当作空哈希表处理并返回 0

  • 语法:

    1
    127.0.0.1:6379> HDEL KEY_NAME FIELD1.. FIELDN 
  • 返回值:

    整数: 被成功删除字段的数量,不包括被忽略的字段。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    127.0.0.1:6379> HDEL myhash field1
    (integer) 1
    127.0.0.1:6379> HDEL myhash field2
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields to be removed.

1.3.2 HEXISTS key field

Redis Hexists 命令用于查看哈希表的指定字段field 是否存在。

  • 语法:

    1
    127.0.0.1:6379> HEXISTS KEY_NAME FIELD_NAME 
  • 返回值:

    整数, specifically:

    • 1 哈希表含有给定字段field
    • 0 哈希表不含有给定字段,或 key 不存在。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    127.0.0.1:6379> HEXISTS myhash field1
    (integer) 1
    127.0.0.1:6379> HEXISTS myhash field2
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.3 HGET key field

Redis HGET 命令用于返回哈希表中指定字段 field 的值。

  • 语法:

    1
    127.0.0.1:6379> HGET KEY_NAME FIELD_NAME
  • 返回值:

    多行字符串: 返回给定字段的值。如果给定的字段或 key 不存在时,返回 nil 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    # 字段存在
    127.0.0.1:6379> HGET myhash field1
    "foo"
    # 字段不存在
    127.0.0.1:6379> HGET myhash field2
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.4 HGETALL key

Redis HGETALL 命令用于返回存储在 key 中的哈希表中所有的域和值。

在返回值里,紧跟每个域(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。

  • 语法:

    1
    127.0.0.1:6379> HGETALL KEY_NAME
  • 返回值:

    数组: 以列表形式返回哈希表的字段及字段值。 若 key 不存在,返回空列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HGETALL myhash
    1) "field1"
    2) "Hello"
    3) "field2"
    4) "World"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.5 HINCRBY key field increment

为哈希表 key 中的域 field 的值加上增量 increment

增量也可以为负数,相当于对给定域进行减法操作。

如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。

如果域 field 不存在,那么在执行命令前,域的值被初始化为 0

对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误 ERR ERR hash value is not an integer。

本操作的值被限制在 64 位(bit)有符号数字表示之内。

  • 语法:

    1
    127.0.0.1:6379> HINCRBY KEY_NAME FIELD_NAME INCR_BY_NUMBER 
  • 返回值:

    整数: 执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field 5
    (integer) 1
    127.0.0.1:6379> HINCRBY myhash field 1
    (integer) 6
    127.0.0.1:6379> HINCRBY myhash field -1
    (integer) 5
    127.0.0.1:6379> HINCRBY myhash field -10
    (integer) -5
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.6 HINCRBYFLOAT key field increment

为哈希表 key 中的域 field 加上浮点数增量 increment

如果哈希表中没有域 field ,那么 INCRBYFLOAT 会先将域 field 的值设为 0 ,然后再执行加法操作。

如果键 key 不存在,那么 INCRBYFLOAT 会先创建一个哈希表,再创建域 field ,最后再执行加法操作。

当以下任意一个条件发生时,返回一个错误:

  • field 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
  • field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)

命令的详细功能和 INCRBYFLOAT命令类似,请查看 INCRBYFLOAT命令获取更多相关信息。

  • 语法:

    1
    127.0.0.1:6379> HINCRBYFLOAT key field increment
  • 返回值:

    多行字符串: 执行加法操作之后 field 域的值

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> HSET myhash field 10.50
    (integer) 1
    127.0.0.1:6379> HINCRBYFLOAT myhash field 0.1
    "10.6"
    127.0.0.1:6379> HINCRBYFLOAT myhash field -5
    "5.6"
    127.0.0.1:6379> HSET myhash field 5.0e3
    (integer) 0
    127.0.0.1:6379> HINCRBYFLOAT myhash field 2.0e2
    "5200"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.3.7 HKEYS key

HKEYS 返回存储在 key 中哈希表的所有域。

  • 语法:

    1
    127.0.0.1:6379> HKEYS key
  • 返回值:

    数组: 包含哈希表中所有域的表。当 key 不存在时,返回空表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HKEYS myhash
    1) "field1"
    2) "field2"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.8 HLEN key

Redis HLEN 命令用于获取哈希表中字段(fields)的数量。

  • 语法:

    1
    127.0.0.1:6379> HLEN key
  • 返回值:

    整数: 哈希表中字段的数量。 当 key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HLEN myhash
    (integer) 2
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.9 HMGET key field [field …]

Redis HMGET 命令用于返回哈希表中,一个或多个给定字段(field)的值。

如果指定的字段(field)不存在于哈希表或者 key 不存在,那么返回一个 nil 值。

  • 语法:

    1
    127.0.0.1:6379> HMGET key field [field ...]
  • 返回值:

    数组: 返回要查询的field对应值的列表,值的顺序field在命令中出现的顺序排列。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HMGET myhash field1 field2 nofield
    1) "Hello"
    2) "World"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields being requested.

1.3.10 HMSET key field value [field value …]

Redis HMSET 命令用于同时将多个 field-value (字段-值)对设置到哈希表中。

此命令会覆盖哈希表中已存在的字段。

如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作。

Redis 4.0.0起,HMSET 被废弃,请使用 HSET 代替。

  • 语法:

    1
    127.0.0.1:6379> HMSET key field value [field value ...]
  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
    OK
    127.0.0.1:6379> HGET myhash field1
    "Hello"
    127.0.0.1:6379> HGET myhash field2
    "World"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields being set.

1.3.11 HSET key field value [field value …]

  • 语法:

    1
    127.0.0.1:6379> HSET key field value [field value ...]
  • 返回值:

    整数: 被修改或增加的 field 个数。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HGET myhash field1
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1) for each field/value pair added, so O(N) to add N field/value pairs when the command is called with multiple field/value pairs.

1.3.12 HSETNX key field value

Redis HSETNX 命令用于为哈希表中不存在的字段赋值 。

如果字段已经存在于哈希表中,操作无效。

如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。

  • 语法:

    1
    127.0.0.1:6379> HSETNX key field value
  • 返回值:

    整数:

    • 1 field 设置成功。
    • 0 field 已存在,设置失败。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSETNX myhash field "Hello"
    (integer) 1
    127.0.0.1:6379> HSETNX myhash field "World"
    (integer) 0
    127.0.0.1:6379> HGET myhash field
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.13 HVALS key

Redis HVALS 命令返回哈希表所有域(field)的值。

  • 语法:

    1
    127.0.0.1:6379> HVALS key
  • 返回值:

    数组: 返回哈希表中所有域(field)值的列表。 当 key 不存在时,返回空表。 not exist.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HVALS myhash
    1) "Hello"
    2) "World"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.14 HSCAN key cursor [MATCH pattern] [COUNT count]

Redis HSCAN 命令用于遍历哈希表中的键值对。

  • 语法:

    1
    127.0.0.1:6379> HSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明

    • cursor: 游标。
    • pattern: 匹配的模式。
    • count: 指定从数据集里返回多少元素,默认值为 10 。
  • 返回值:

    返回的每个元素都是一个元组,每一个元组元素由一个字段(field) 和值(value)组成。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HMSET sites google "google.com" kungs "yanpenggong" weibo "weibo.com" 8 "alibaba.com"
    OK
    127.0.0.1:6379> HSCAN sites 0 match "goog*"
    1) "0"
    2) 1) "google"
    2) "google.com"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.3.15 HSTRLEN key field

Redis HSTRLEN 命令返回存储在 key 中的哈希表里, 与给定域 field 相关联的值的字符串长度(string length)。

如果给定的键或者域不存在, 那么命令返回 0

  • 语法:

    1
    127.0.0.1:6379> HSTRLEN key field
  • 返回值:

    整数: 值的字符串长度,key 或 field 不存在时返回 0。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HMSET myhash f1 HelloWorld f2 88 f3 -516
    OK
    127.0.0.1:6379> HSTRLEN myhash f1
    (integer) 10
    127.0.0.1:6379> HSTRLEN myhash f2
    (integer) 2
    127.0.0.1:6379> HSTRLEN myhash f3
    (integer) 4
    127.0.0.1:6379>

可用版本>= 3.2.0.

时间复杂度: O(1)

1.4 List(列表)

1.4.1 BLPOP key [key …] timeout

Redis BLPOP 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。它是 LPOP 的阻塞版本。
当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。

  • 语法:

    1
    127.0.0.1:6379> BLPOP LIST1 LIST2 .. LISTN TIMEOUT
  • 返回值:

    数组:

    • 如果列表为空或超时,返回一个 nil
    • 返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    127.0.0.1:6379> DEL list1 list2
    (integer) 1
    127.0.0.1:6379> RPUSH list1 a b c
    (integer) 3
    127.0.0.1:6379> BLPOP list1 list2 0
    1) "list1"
    2) "a"
    127.0.0.1:6379> BLPOP list1 10
    1) "list1"
    2) "b"
    127.0.0.1:6379> BLPOP list1 10
    1) "list1"
    2) "c"
    127.0.0.1:6379> BLPOP list1 10
    (nil)
    (10.08s)
    127.0.0.1:6379> BLPOP list2 10
    (nil)
    (10.07s)
    127.0.0.1:6379>

    在实例中,操作会被阻塞,如果指定的列表 key list2 存在数据则会返回第一个元素,否则在等待10秒后会返回 nil 。

可用版本>= 2.0.0.

时间复杂度: O(1)

1.4.2 BRPOP key [key …] timeout

BRPOP 是阻塞列表的移除原语。从给的列表参数中按顺序检查第一个不空的列表,然后从该列表的尾部移除元素。 BRPOP 是 RPOP 的阻塞版本,因为当没有元素从给定的列表中移除的时候,BRPOP 阻塞连接。

参考 BLPOP documentation 了解更多信息,因为 BRPOP 和 BLPOP 的功能是相同的,除了他们一个是从列表头部(左边),另一个是从列表尾部(右边)移除元素。

  • 语法:

    1
    127.0.0.1:6379> BRPOP LIST1 LIST2 .. LISTN TIMEOUT 
  • 返回值:

    数组:

    • 所有列表为空并且超时时,返回 nil
    • 一个两个成员的数组,第一个元素是被移除元素的key的名字,第二个元素是被移除元素的值。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> DEL list1 list2
    Error: Broken pipe
    127.0.0.1:6379> RPUSH list1 a b c
    (integer) 3
    127.0.0.1:6379> BRPOP list1 list2 0
    1) "list1"
    2) "c"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.4.3 BRPOPLPUSH source destination timeout

Redis BRPOPLPUSH 命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOPLPUSH 是 RPOPLPUSH的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH的表现和 RPOPLPUSH 一样。
超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。
从 Redis 6.2.0 起,建议使用 BLMOVE 替代 BRPOPLPUSH

  • 语法:

    1
    127.0.0.1:6379> BRPOPLPUSH LIST1 ANOTHER_LIST TIMEOUT
  • 返回值:

    多行字符串: 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> RPUSH msg "hello yanpenggong"
    (integer) 1
    127.0.0.1:6379> BRPOPLPUSH msg reciver 10
    "hello yanpenggong"
    127.0.0.1:6379> LLEN reciver
    (integer) 1
    127.0.0.1:6379> LRANGE reciver 0 0
    1) "hello yanpenggong"
    # 空列表
    127.0.0.1:6379> RPOP msg
    (nil)
    127.0.0.1:6379> BRPOPLPUSH msg reciver 10
    (nil)
    (10.05s)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.4.4 LINDEX key index

LINDEX 返回列表 key 里索引 index 位置存储的元素。

index 下标是从 0 开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。

负数索引用于指定从列表尾部开始索引的元素,在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。
当 key 值不是列表的时候,会返回错误。

  • 语法:

    1
    127.0.0.1:6379> LINDEX key index
  • 返回值:

    多行字符串: 查询的元素,index 超出索引范围时返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> LPUSH mylist "World"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LINDEX mylist 0
    "Hello"
    127.0.0.1:6379> LINDEX mylist -1
    "World"
    127.0.0.1:6379> LINDEX mylist 3
    (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of elements to traverse to get to the element at index. This makes asking for the first or the last element of the list O(1).

1.4.5 LINSERT key BEFORE|AFTER pivot element

Redis LINSERT 用于把 element 插入到列表 key 中,参考值 pivot 的前面或后面。

key 不存在时,这个list会被看作是空list,什么都不执行。

key 存在,值不是列表类型时,返回错误。

  • 语法:

    1
    127.0.0.1:6379> LINSERT key BEFORE|AFTER pivot element
  • 返回值:

    整数: 执行操作后的列表长度,列表中pivot参考值不存在的时候返回 -1

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> LINSERT mylist BEFORE "World" "There"
    (integer) 3
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "There"
    3) "World"
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(N) where N is the number of elements to traverse before seeing the value pivot. This means that inserting somewhere on the left end on the list (head) can be considered O(1) and inserting somewhere on the right end (tail) is O(N).

1.4.6 LLEN key

Redis LLEN 用于返回存储在 key 中的列表长度。 如果 key 不存在,则 key被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误。

  • 语法:

    1
    127.0.0.1:6379> LLEN KEY_NAME
  • 返回值:

    整数: 列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> LRANGE mylist 0 -1
    (empty array)
    127.0.0.1:6379> LPUSH mylist "World"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LPUSH mylist "yanpenggong"
    (integer) 3
    127.0.0.1:6379> LLEN mylist
    (integer) 3
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.7 LPOP key

Redis LPOP 命令用于删除并返回存储在 key 中的列表的第一个元素。

  • 语法:

    1
    127.0.0.1:6379> LPOP key
  • 返回值:

    多行字符串: 列表的首元素,key 不存在的时候返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LPOP mylist
    "one"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.8 LPUSH key element [element …]

redis LPUSH 用于将一个或多个值插入到列表key 的头部。

如果 key 不存在,那么在进行 push 操作前会创建一个空列表。

如果 key 对应的值不是 list 类型,那么会返回一个错误。

可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。

元素按在参数中出现的顺序,从左到右依次插入到 list 的头部。

所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。

  • 语法:

    1
    127.0.0.1:6379> LPUSH KEY_NAME VALUE1.. VALUEN
  • 返回值:

    整数: 执行push操作后列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> LPUSH mylist "world"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "world"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.9 LPUSHX key element [element …]

Redis LPUSHX 在当 key 存在并且存储着一个 list 类型值的时候,向值 list 的头部插入 value。 与 LPUSH 相反,当 key 不存在的时候不会进行任何操作。

  • 语法:

    1
    127.0.0.1:6379> LPUSHX KEY_NAME VALUE1.. VALUEN
  • 返回值:

    整数: 执行push操作后列表list的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> LPUSH mylist "world" "Hello"
    (integer) 2
    127.0.0.1:6379> LPUSHX mylist "kungs"
    (integer) 3
    127.0.0.1:6379> LPUSHX mylist1 "kungs"
    (integer) 0
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "kungs"
    2) "Hello"
    3) "world"
    127.0.0.1:6379> LRANGE mylist1 0 -1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.10 LRANGE key start stop

Redis LRANGE 用于返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。

其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

  • 语法:

    1
    127.0.0.1:6379> LRANGE KEY_NAME START END
  • 返回值:

    数组: 一个列表,包含指定区间内的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LRANGE mylist 0 0
    1) "one"
    127.0.0.1:6379> LRANGE mylist -3 2
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> LRANGE mylist -100 100
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> LRANGE mylist 5 10
    (empty array)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.

1.4.11 LREM key count element

Redis LREM 用于从列表 key 中删除前 count 个值等于 element 的元素。 这个 count 参数通过下面几种方式影响这个操作:

1
2
3
count > 0: 从头到尾删除值为 value 的元素。
count < 0: 从尾到头删除值为 value 的元素。
count = 0: 移除所有值为 value 的元素。

比如, LREM list -2 "hello" 会从列表key中删除最后两个出现的 “hello”。

需要注意的是,不存在key会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。

  • 语法:

    1
    127.0.0.1:6379> LREM key count VALUE
  • 返回值:

    整数: 删除元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 3
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 4
    127.0.0.1:6379> LREM mylist -2 "Hello"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N+M) where N is the length of the list and M is the number of elements removed.

1.4.12 LSET key index element

Redis LSET 用于设置列表 key 中 index 位置的元素值为 element。 更多关于 index 参数的信息,详见 LINDEX

当 index 超出列表索引范围时会返回错误ERR ERR index out of range

  • 语法:

    1
    127.0.0.1:6379> LSET KEY_NAME INDEX VALUE
  • 返回值:

    字符串: 操作成功返回 ok ,否则返回错误信息。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LSET mylist 0 "four"
    OK
    127.0.0.1:6379> LSET mylist -2 "five"
    OK
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "four"
    2) "five"
    3) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1).

1.4.13 LTRIM key start stop

Redis Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

start 和 stop 都是由0开始计数的, 这里的 0 是列表里的第一个元素(表头),1 是第二个元素,以此类推。

start 和 end 也可以用负数来表示与表尾的偏移量,比如 -1 表示列表里的最后一个元素, -2 表示倒数第二个,等等。

超过范围的下标并不会产生错误:如果 start 超过列表尾部,或者 start > end,结果会是列表变成空表(即该 key 会被移除)。 如果 end 超过列表尾部,Redis 会将其当作列表的最后一个元素。

  • 语法:

    1
    127.0.0.1:6379> LTRIM KEY_NAME START STOP
  • 返回值:

    字符串: 命令执行成功时,返回 ok 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LTRIM mylist 1 -1
    OK
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of elements to be removed by the operation.

1.4.14 RPOP key

Redis RPOP 用于移除并返回列表 key 的最后一个元素。

  • 语法:

    1
    127.0.0.1:6379> RPOP KEY_NAME 
  • 返回值:

    多行字符串: 最后一个元素的值,key 不存在时返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> RPOP mylist
    "three"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "one"
    2) "two"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.15 RPOPLPUSH source destination

用于原子地从列表 source 中移除并返回最后一个元素,然后把这个元素插入为列表destination 的第一个元素。

例如: 假设 source 列表成员为 a,b,c,列表 destination 成员为 x,y,z

执行 RPOPLPUSH source destination 的结果是列表 source 成员为a,b ,列表 destination 成员为c,x,y,z

如果列表 source 不存在,返回 nil ,什么也不执行。

如果列表 sourcedestination 相同,相当于从列表的一端删除元素,在放入列表的另一端,所以可以当做一个列表循环命令。

LMOVE 用来替换废弃的指令 RPOPLPUSH,相当于执行LMOVE RIGHT LEFT

从 Redis 6.2.0起, RPOPLPUSH 被废弃,使用 LMOVE替代。

  • 语法:

    1
    127.0.0.1:6379> RPOPLPUSH SOURCE_KEY_NAME DESTINATION_KEY_NAME
  • 返回值:

    多行字符串: 移除并又插入的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> RPOPLPUSH mylist myotherlist
    "three"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "one"
    2) "two"
    127.0.0.1:6379> LRANGE myotherlist 0 -1
    1) "three"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.4.16 RPUSH key element [element …]

RPUSH 向存存储在 key 中的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是列表,那么会返回一个错误。

可以使用RPUSH命令把多个元素插入队列,只需要在命令后面指定多个参数。元素是从左到右按序从列表尾部插入。 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。

  • 语法:

    1
    127.0.0.1:6379> RPUSH KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: 执行 push 操作后的列表长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.17 RPUSHX key element [element …]

RPUSHX将值 value 插入到列表 key 的表尾, 当且仅当 key 存在并且是一个列表。 和 RPUSH命令相反, 当 key 不存在时,RPUSHX 命令什么也不做。

  • 语法:

    1
    127.0.0.1:6379> RPUSHX KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: RPUSHX 命令执行之后列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> RPUSHX myotherlist "World"
    (integer) 0
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379> LRANGE myotherlist 0 -1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.5 Sets(集合)

1.5.1 SADD key member [member …]

Redis Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。

假如集合 key 不存在,则创建一个只包含被添加的元素作为成员的集合。

当集合 key 不是集合类型时,返回一个错误。

注意:在 Redis2.4 版本以前, SADD 只接受单个成员值。

  • 语法:

    1
    127.0.0.1:6379> SADD KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SADD myset "Hello"
    (integer) 1
    127.0.0.1:6379> SADD myset "World"
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset
    1) "World"
    2) "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.5.2 SCARD key

Redis SCARD 命令返回集合中元素的数量。

  • 语法:

    1
    127.0.0.1:6379> SCARD KEY_NAME
  • 返回值:

    整数: 集合中成员的数量。 当集合 key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SADD myset "Hello"
    (integer) 1
    127.0.0.1:6379> SADD myset "World"
    (integer) 1
    127.0.0.1:6379> SCARD myset
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.3 SDIFF key [key …]

Redis SDIFF 命令返回第一个集合与其他集合之间的差异,也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。

  • 语法:

    1
    127.0.0.1:6379> SDIFF FIRST_KEY OTHER_KEY1..OTHER_KEYN 
  • 返回值:

    数组: 包含差集成员的列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c
    (integer) 1
    127.0.0.1:6379> SADD key3 a c e
    (integer) 3
    127.0.0.1:6379> SDIFF key1 key2 key3
    1) "b"
    2) "d"
    127.0.0.1:6379> SDIFF key1 key2
    1) "a"
    2) "b"
    3) "d"
    127.0.0.1:6379>
    可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.4 SDIFFSTORE destination key [key …]

SDIFFSTORE 命令的作用和SDIFF类似,不同的是它将结果保存到 destination 集合,而把结果集返回给客户端。

如果 destination 集合已经存在,则将其覆盖。

  • 语法:

    1
    127.0.0.1:6379> SDIFFSTORE DESTINATION_KEY KEY1..KEYN
  • 返回值:

    整数: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SDIFFSTORE key key1 key2
    (integer) 2
    127.0.0.1:6379> SMEMBERS key
    1) "a"
    2) "b"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.5 SINTER key [key …]

对于不存在的 key 可以认为是空集合。

如果给定的key中有一个空集合,那么结果集一定是空集合。

  • 语法:

    1
    127.0.0.1:6379> SINTER KEY KEY1..KEYN 
  • 返回值:

    数组: 结果集成员个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SINTER key1 key2
    1) "d"
    2) "c"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.

1.5.6 SINTERSTORE destination key [key …]

SINTERSTORE 命令与 SINTER 命令类似,不同的是它并不是直接返回结果集,而是将结果保存在 destination 集合中。
如果 destination 集合存在, 则会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> SINTERSTORE DESTINATION_KEY KEY KEY1..KEYN
  • 返回值:

    整数: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> DEL key key1key2 key3
    (integer) 1
    127.0.0.1:6379> DEL key key1 key2 key3
    (integer) 2
    127.0.0.1:6379> SADD key1 a b c
    (integer) 3
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SINTERSTORE key key1 key2
    (integer) 1
    127.0.0.1:6379> SMEMBERS key
    1) "c"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.

1.5.7 SISMEMBER key member

Redis SISMEMBER 用于判断元素 member 是否集合 key 的成员。

  • 语法:

    1
    127.0.0.1:6379> SISMEMBER KEY MEMBER
  • 返回值:

    整数:

    • 1: 如果成员元素是集合的成员,返回 1 。
    • 0: 如果成员元素不是集合的成员,或 key 不存在,返回 0 。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SADD myset "one"
    (integer) 1
    127.0.0.1:6379> SISMEMBER myset "one"
    (integer) 1
    127.0.0.1:6379> SISMEMBER myset "two"
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.8 SMEMBERS key

Redis SISMEMBER 命令返回存储在 key 中的集合的所有的成员。 不存在的集合被视为空集合。
SISMEMBER 与运行带有一个参数 key 的 SINTER 有同样的效果。

  • 语法:

    1
    127.0.0.1:6379> SMEMBERS key
  • 返回值:

    数组: 集合中的所有成员。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SADD myset "Hello" "World"
    (integer) 2
    127.0.0.1:6379> SMEMBERS myset
    1) "World"
    2) "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the set cardinality.

1.5.9 SMOVE source destination member

Redis SMOVE 命令用于从集合source 中移动成员member 到集合 destination。 这个操作是原子操作。 在任何时刻,member 只会存在于sourcedestination 其中之一。

如果集合source 不存在,或者要移动的成员不是集合source 的成员,什么也不执行并返回 0

否则,其它情况下,从集合source 中删除成员并添加到集合 destination

如果要移动的元素在集合 destination中已经存在,那么只是从集合source中删除该成员。

如果 sourcedestination 不是集合类型则返回错误。

  • 语法:

    1
    127.0.0.1:6379> SMOVE SOURCE DESTINATION MEMBER
  • 返回值:

    整数:

    • 1: 移动元素成功。
    • 0: 如果要移动的 element 不是source 的成员,什么也不执行。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SADD myset "one" "two"
    (integer) 2
    127.0.0.1:6379> SADD myotherset "three"
    (integer) 1
    127.0.0.1:6379> SMOVE myset myotherset "two"
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset
    1) "one"
    127.0.0.1:6379> SMEMBERS myotherset
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.10 SPOP key [count]

Redis SPOP 命令用于从集合 key中删除并返回一个或多个随机元素。

这个命令和 SRANDMEMBER 相似, SRANDMEMBER 只返回随机成员但是不删除这些返回的成员。

参数 count 从 Redis 3.2 起可用

  • 语法:

    1
    127.0.0.1:6379> SPOP key [count]
  • 返回值:

    多行字符串: 被删除的元素,当key不存在时返回nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> SADD myset "one" "two" "three"
    (integer) 3
    127.0.0.1:6379> SPOP myset
    "one"
    127.0.0.1:6379> SMEMBERS myset
    1) "two"
    2) "three"
    127.0.0.1:6379> SADD myset "four" "five"
    (integer) 2
    127.0.0.1:6379> SPOP myset 3
    1) "four"
    2) "three"
    3) "two"
    127.0.0.1:6379> SMEMBERS myset
    1) "five"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.11 SRANDMEMBER key [count]

Redis SRANDMEMBER 命令仅使用key 参数,那么随机返回集合key 中的一个随机元素。

Redis 2.6开始,可以接受 count 参数,如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,如果count是个整数且大于集合中元素的个数时,返回整个集合的所有元素,当count是负数,则会返回一个包含count的绝对值的个数元素的数组,如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.

仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER 仅仅是返回该随记元素,而不对原集合做任何操作。

传递count参数时的行为规范

当传递了一个值为正数的count参数,返回的元素就好像从集合中移除了每个选中的元素一样(就像在宾果游戏中提取数字一样)。但是元素不会从集合中移除。所以基本上:

  • 不会返回重复的元素。
  • 如果count参数的值大于集合内的元素数量,此命令将会仅返回整个集合,没有额外的元素。

相反,当count参数的值为负数时,此命令的行为将发生改变,并且提取操作就像在每次提取后,重新将取出的元素放回包里一样,因此,可能返回重复的元素,以及总是会返回我们请求的数量的元素,因为我们可以一次又一次地重复相同的元素,除了当集合为空(或者不存在key)的时候,将总是会返回一个空数组。

返回元素的分布

当集合中的元素数量很少时,返回元素分布远不够完美,这是因为我们使用了一个近似随机元素函数,它并不能保证良好的分布。

所使用的算法(在dict.c中实现)对哈希表桶进行采样以找到非空桶。一旦找到非空桶,由于我们在哈希表的实现中使用了链接法,因此会检查桶中的元素数量,并且选出一个随机元素。

这意味着,如果你在整个哈希表中有两个非空桶,其中一个有三个元素,另一个只有一个元素,那么其桶中单独存在的元素将以更高的概率返回。

  • 语法:

    1
    127.0.0.1:6379> SRANDMEMBER KEY [count]
  • 返回值:

    多行字符串: 不使用count 参数的情况下该命令返回随机的元素,如果key不存在则返回nil。

    数组: 使用count参数,则返回一个随机的元素数组,如果key不存在则返回一个空的数组。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> SADD myset one two three
    (integer) 3
    127.0.0.1:6379> SRANDMEMBER myset
    "three"
    127.0.0.1:6379> SRANDMEMBER myset 2
    1) "one"
    2) "two"
    127.0.0.1:6379> SRANDMEMBER myset -5
    1) "three"
    2) "one"
    3) "two"
    4) "three"
    5) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.

1.5.12 SREM key member [member …]

SREM 用于在集合中删除指定的元素。如果指定的元素不是集合成员则被忽略。

如果集合 key 不存在则被视为一个空的集合,该命令返回0。

如果key的类型不是一个集合,则返回 ERR WRONGTYPE Operation against a key holding the wrong kind of value 错误

  • 语法:

    1
    127.0.0.1:6379> SREM KEY MEMBER1..MEMBERN
  • 返回值:

    整数: 被删除元素个数,不含不存在的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> SADD myset "one" "two" "three"
    (integer) 3
    127.0.0.1:6379> SREM myset "one"
    (integer) 1
    127.0.0.1:6379> SREM myset "four"
    (integer) 0
    127.0.0.1:6379> SMEMBERS myset
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of members to be removed.

1.5.13 SUNION key [key …]

SUNION 命令用于返回所有给定集合的并集。例如:

对于不存在 key 被当做空集合处理。

  • 语法:

    1
    127.0.0.1:6379> SUNION KEY KEY1..KEYN
  • 返回值:

    数组: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SADD key1 "a" "b" "c"
    (integer) 3
    127.0.0.1:6379> SADD key2 "c" "d" "e"
    (integer) 3
    127.0.0.1:6379> SUNION key1 key2
    1) "e"
    2) "b"
    3) "c"
    4) "a"
    5) "d"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.14 SUNIONSTORE destination key [key …]

SUNIONSTORE 命令的功能类似于 SUNION,不同的是不反回结果集,而是存储在 destination 中。

如果 destination 已经存在,则被覆盖。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: 结果集中的成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SADD key1 "a" "b" "c"
    (integer) 3
    127.0.0.1:6379> SADD key2 "c" "d" "e"
    (integer) 3
    127.0.0.1:6379> SUNIONSTORE key key1 key2
    (integer) 5
    127.0.0.1:6379> SMEMBERS key
    1) "e"
    2) "b"
    3) "c"
    4) "a"
    5) "d"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.15 SSCAN key cursor [MATCH pattern] [COUNT count]

Redis SSCAN 命令用于遍历集合中键的元素,SSCAN 继承自SCAN。

  • 语法:

    1
    127.0.0.1:6379> SSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明

    • cursor - 游标。
    • pattern - 匹配的模式。
    • count - 指定从数据集里返回多少元素,默认值为 10
  • 返回值:

    数组列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> SADD myset "Mongodb" "Redis" "hive"
    (integer) 3
    127.0.0.1:6379> SSCAN myset 0 match "R*"
    1) "0"
    2) 1) "Redis"
    127.0.0.1:6379> SSCAN myset 2 match "R*"
    1) "0"
    2) (empty array)
    127.0.0.1:6379> SSCAN myset -4 match R*
    1) "0"
    2) 1) "Redis"
    127.0.0.1:6379> SSCAN myset 2 match *o*
    1) "0"
    2) 1) "Mongodb"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.6 Sorted Sets(有序集合)

1.6.1 ZADD key [NX|XX] [GT|LT] [CH] [INCR]score member [score member …]

Redis ZADD 命令用于将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

如果某个 member 已经是有序集的成员,那么更新这个 memberscore值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。

如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。

key 存在但不是有序集类型时,返回一个错误。

score 值可以是整数值或双精度浮点数,score 可为正也可以为负。

注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素。

  • 语法:

    1
    127.0.0.1:6379> ZADD key [NX|XX] [GT|LT] [CH] [INCR]score member [score member ...]
    1. 参数说明

      • XX: 仅更新存在的成员,不添加新成员。
      • NX: 不更新存在的成员。只添加新成员。

      • LT: 更新新的分值比当前分值小的成员,不存在则新增。

      • GT: 更新新的分值比当前分值大的成员,不存在则新增。

      • CH: 返回变更成员的数量。变更的成员是指 新增成员score值更新的成员,命令指明的和之前score值相同的成员不计在内。 注意: 在通常情况下,ZADD返回值只计算新添加成员的数量。

      • INCR: ZADD 使用该参数与 ZINCRBY 功能一样。一次只能操作一个score-element对。

      注意: GT, LTNX 三者互斥不能同时使用。

    2. scores 有效值范围

      Redis 有序集合的分数使用双精度64位浮点数表示。在Redis所支持的平台上,称为IEEE 754 floating point number,它能包括的整数范围是-(2^53)+(2^53)。或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。

    3. Sorted sets 101

      有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。

      获取一个成员当前的分数可以使用 ZSCORE 命令,也可以用它来验证成员是否存在。

    4. 相同分数的成员

      有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。当多个成员有相同的分数时,他们将是按字典排序(ordered lexicographically)(仍由分数作为第一排序条件,然后,相同分数的成员按照字典序排序)。

      字典顺序排序用的是二进制,它比较的是字符串的字节数组。

      如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用 ZRANGEBYLEX 命令(注:范围查询分数可以使用 ZRANGEBYSCORE 命令)。

  • 返回值:

    整数:

    • 被成功添加的新成员的数量,不包括那些被更新分数的、已经存在的成员。

    如果使用 INCR 选项,则返回 多行字符串:

    • 以字符串形式表示的 member 的 score 值(双精度浮点数)。(双精度浮点数) , 执行失败返回 nil (当使用 XXNX 选项)。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    # 添加单个元素
    127.0.0.1:6379> ZADD page_rank 10 google.com
    (integer) 1
    # 添加多个元素
    127.0.0.1:6379> ZADD page_rank 9 baidu.com 8 github.com
    (integer) 2
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    # 添加已存在元素,且 score 值不变,发现没有改变
    127.0.0.1:6379> ZADD page_rank 10 google.com
    (integer) 0
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    # 添加已存在元素,但是改变 score 值
    127.0.0.1:6379> ZADD page_rank 6 github.com
    (integer) 0
    # "github.com"的值被改变
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "6"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)) for each item added, where N is the number of elements in the sorted set.

1.6.2 ZCARD key

Redis ZCARD 命令用于返回有序集的成员个数。

  • 语法:

    1
    127.0.0.1:6379> ZCARD KEY_NAME
  • 返回值:

    整数: 返回有序集的成员个数,当 key 不存在时,返回 0

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZCARD myset
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.6.3 ZCOUNT key min max

ZCOUNT 返回有序集 key 中, score 值在 minmax 之间(默认包括 score 值等于 minmax )的成员的数量。

关于参数 minmax 的详细使用方法,请参考ZRANGEBYSCORE.

注意: ZCOUNT 命令的时间复杂度是 O(log(N)),因为 ZCOUNT 使用有序成员来实现范围查询,不需要遍历整个集合。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: score 值在 min 和 max 之间的成员的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZADD myset 3 "three"
    (integer) 1
    127.0.0.1:6379> ZCOUNT myset -inf +inf
    (integer) 3
    127.0.0.1:6379> ZCOUNT myset (1 3
    (integer) 2
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N)) with N being the number of elements in the sorted set.

1.6.4 ZINCRBY key increment member

ZINCRBY 为有序集 key 的成员 memberscore 值加上增量 increment

key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member

key 不是有序集类型时,返回”ERR WRONGTYPE Operation against a key holding the wrong kind of value”。

score 值可以是字符串形式表示的整数值或双精度浮点数。

可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -2 member ,就是让 memberscore 值减去 2

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    多行字符串: 以字符串形式表示的 member 成员的新 score 值(双精度浮点数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZINCRBY myset 2 "one"
    "3"
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "two"
    2) "2"
    3) "one"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)) where N is the number of elements in the sorted set.

1.6.5 ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

计算 numkeys 个有序集合的交集,并且把结果放到 destination 中。 在给定要计算的 key 和其它参数之前,必须先给定 key 个数(numberkeys)。

默认情况下,结果集中元素的分数是各有序集合中该元素分数之和。

对于WEIGHTS和AGGREGATE参数的描述,参见命令 ZUNIONSTORE。

如果destination存在,会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> INTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • 返回值:

    整数:结果集 destination 中元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> ZADD zset1 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZADD zset2 1 "one" 2 "two" 3 "three"
    (integer) 3
    # zset1 * 2 + zset2 * 3
    127.0.0.1:6379> ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
    (integer) 2
    127.0.0.1:6379> ZRANGE out 0 -1 WITHSCORES
    1) "one"
    2) "5"
    3) "two"
    4) "10"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(NK)+O(Mlog(M)) worst case with N being the smallest input sorted set, K being the number of input sorted sets and M being the number of elements in the resulting sorted set.

1.6.6 ZLEXCOUNT key min max

当有序集中的所有成员都有相同的score, ZLEXCOUNT 命令返回有序集中值在 minmax之间的成员个数。

minmax 详见ZRANGEBYLEX。时间复 O(log(N))。

  • 语法:

    1
    127.0.0.1:6379> ZLEXCOUNT key min max
  • 返回值:

    整数: 返回特定分值元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> ZADD myset 0 a 0 b 0 c 0 d 0 e
    (integer) 5
    127.0.0.1:6379> ZADD myset 0 f 0 g
    (integer) 2
    127.0.0.1:6379> ZLEXCOUNT myset - +
    (integer) 7
    127.0.0.1:6379> ZLEXCOUNT myset [b [f
    (integer) 5
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)) with N being the number of elements in the sorted set.

1.6.7 ZRANGE key start stop [WITHSCORES]

Redis ZRANGE 命令返回有序集中,指定区间内的成员,其中成员的按分数值递增(从小到大)来排序,具有相同分数值的成员按字典序(lexicographical order )来排列。

如果你需要成员按值递减(从大到小)来排列,请使用 ZREVRANGE命令。

下标参数 startstop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。

你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。

startstop 都是包含在内的区间,因此例如 ZRANGE myzset 0 1 将会返回有序集合的第一个和第二个元素。

超出范围的索引不会产生错误。 如果 start 参数的值大于有序集合中的最大索引,或者 start > stop ,将会返回一个空列表。 如果 stop 的值大于有序集合的末尾,Redis 会将其视为有序集合的最后一个元素。

可以传递 WITHSCORES 选项,以便将元素的分数与元素一起返回。这样返回的列表将包含 value1,score1,...,valueN,scoreN ,而不是 value1,...,valueN 。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或元组)。

  • 语法:

    1
    127.0.0.1:6379> ZRANGE key start stop [WITHSCORES]
  • 返回值:

    数组: 给定范围内的元素列表(如果指定了WITHSCORES选项,将同时返回它们的得分)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> ZRANGE myset 2 3
    1) "three"
    127.0.0.1:6379> ZRANGE myset -2 -1
    1) "two"
    2) "three"
    127.0.0.1:6379> ZRANGE myset 0 1 WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.

1.6.8 ZRANGEBYLEX key min max [LIMIT offset count]

Redis Zrangebylex 通过字典区间返回有序集合的成员。

  • 语法:

    1
    127.0.0.1:6379> ZRANGEBYLEX key min max [LIMIT offset count]
  • 返回值:

    数组: 指定区间内的元素列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> ZADD myset 0 a 0 b 0 c 0 d 0 e 0 f 0 g
    (integer) 7
    127.0.0.1:6379> ZRANGEBYLEX myset - [c
    1) "a"
    2) "b"
    3) "c"
    127.0.0.1:6379> ZRANGEBYLEX myset - (c
    1) "a"
    2) "b"
    127.0.0.1:6379> ZRANGEBYLEX myset [aaa (g
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "f"
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.9 ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

Redis ZRANGEBYSCORE 返回有序集 key 中,所有 score 值介于 minmax 之间(包括等于 minmax )的成员。有序集成员按 score 值递增(从小到大)次序排列。

具有相同 score 值的成员按字典序(lexicographical order)来排列(该属性是有序集提供的,不需要额外的计算)。

可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count ),注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。

可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score 值一起返回。 该选项自 Redis 2.0 版本起可用。

互斥区间与无穷大:

minmax 可以是 -inf+inf ,这样一来,你就可以在不知道有序集的最低和最高 score 值的情况下,获取所有成员。

默认情况下,区间的取值使用闭区间 (小于等于或大于等于),你也可以通过给参数前增加 ( 符号来使用可选的开区间 (小于或大于)。

举个例子:

1
ZRANGEBYSCORE zset (1 5

返回所有符合条件 1 < score <= 5 的成员:

1
ZRANGEBYSCORE zset (5 (10

则返回所有符合条件 5 < score < 10 的成员。

  • 语法:

    1
    127.0.0.1:6379> ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
  • 返回值:

    数组: 指定区间内的有序集成员的列表(带有 score 值(可选))。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    # 显示整个有序集
    127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf
    1) "one"
    2) "two"
    3) "three"
    # 显示整个有序集及成员的 score 值
    127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    # 显示大于等于 1 小于等于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset 1 2
    1) "one"
    2) "two"
    # 显示大于 1 小于等于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset (1 2
    1) "two"
    # 显示大于 1 小于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset (1 (2
    (empty array)
    127.0.0.1:6379>

可用版本>= 1.0.5.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.10 ZRANK key member

RedisZRANK 命令返回有序集key中成员member的排名,其中有序集成员按score值从低到高排列。

排名从0开始,也就是说,score值最低的成员排名为0

使用ZREVRANK命令可以获得成员按score值递增(从高到低)排列的排名。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    • 如果member是有序集key的成员,整数: member 的排名。
    • 如果member不是有序集key的成员, 或 key 不存在,多行字符串: nil
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZRANK myset "three"
    (integer) 2
    127.0.0.1:6379> ZRANK myset "four"
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N))

1.6.11 ZREM key member [member …]

Redis ZREM 命令用于从有序集合key中删除指定的成员member

如果member不存在则被忽略。

当key存在,但是不是有序集合类型时,返回类型错误。

  • 语法:

    1
    127.0.0.1:6379> ZREM key member [member ...]
  • 返回值:

    整数: 返回的是从有序集合中删除的成员个数,不包括不存在的成员。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREM myset "two"
    (integer) 1
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "three"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.

1.6.12 ZREMRANGEBYLEX key min max

Reids ZREMRANGEBYLEX 命令用于删除成员名称按字典由低到高排序介于minmax 之间的所有成员(集合中所有成员的分数相同)。 不要在成员分数不同的有序集合中使用此命令,因为它是基于分数一致的有序集合设计的,如果使用,会导致删除的结果不正确。

命令中 minmax 的含义与 ZRANGEBYLEX 命令相同。该命令会与使用相同minmax参数的 ZRANGEBYLEX 返回相同的结果。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYLEX key min max
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    127.0.0.1:6379> ZADD myset 0 aaa 0 b 0 c 0 d 0 e 0 f 0 zap 0 zip 0 ALPHA 0 alpha

    (integer) 10
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "ALPHA"
    2) "aaa"
    3) "alpha"
    4) "b"
    5) "c"
    6) "d"
    7) "e"
    8) "f"
    9) "zap"
    10) "zip"
    127.0.0.1:6379> ZREMRANGEBYLEX myset [alpha [omega
    (integer) 6
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "ALPHA"
    2) "aaa"
    3) "zap"
    4) "zip"
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.13 ZREMRANGEBYRANK key start stop

Redis ZREMRANGEBYRANK 移除有序集key中,指定排名(rank)区间 startstop 内的所有成员。下标参数start和stop都是从0开始计数,0是分数最小的那个元素。索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYRANK key start stop
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREMRANGEBYRANK myset 0 1
    (integer) 2
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "three"
    2) "3"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.14 ZREMRANGEBYSCORE key min max

Redis ZREMRANGEBYSCORE 命令移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。

自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYSCORE key min max
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREMRANGEBYSCORE myset -inf (2
    (integer) 1
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "two"
    2) "2"
    3) "three"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.15 ZREVRANGE key start stop [WITHSCORES]

Redis ZREVRANGE 命令返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从高到低)来排列。

具有相同score值的成员按字典序的反序排列。 除了成员排序相反外,ZREVRANGE命令的其他方面和ZRANGE命令一样。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANGE key start stop [WITHSCORES]
  • 返回值:

    数组: 指定范围的元素列表(可选是否含有分数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANGE myset 0 -1
    1) "three"
    2) "two"
    3) "one"
    127.0.0.1:6379> ZREVRANGE myset 2 3
    1) "one"
    127.0.0.1:6379> ZREVRANGE myset -2 -1
    1) "two"
    2) "one"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.

1.6.16 ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

Redis Zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列。

具有相同分数值的成员按字典序来排列(该属性是有序集提供的,不需要额外的计算)。

默认情况下,区间的取值使用闭区间 (小于等于或大于等于),你也可以通过给参数前增加 ( 符号来使用可选的开区间 (小于或大于)。

可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。

可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。

##区间及无限

min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。

默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
  • 返回值:

    数组: 指定分数范围的元素列表(也可以返回他们的分数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANGEBYSCORE myset +inf -inf
    1) "three"
    2) "two"
    3) "one"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset 2 1
    1) "two"
    2) "one"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset 2 (1
    1) "two"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset (2 (1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.17 ZREVRANK key member

Redis ZREVRANK 命令返回有序集key中成员member的排名,其中有序集成员按score值从高到低排列。

排名从0开始,也就是说,score值最大的成员排名为0

使用ZRANK命令可以获得成员按score值递增(从低到高)排列的排名。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANK key member
  • 返回值:

    • 如果member是有序集key的成员,整数: member的排名。
    • 如果member不是有序集key的成员, 或 key 不存在,多行字符串: nil
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANK myset "one"
    (integer) 2
    127.0.0.1:6379> ZREVRANK myset "two"
    (integer) 1
    127.0.0.1:6379> ZREVRANK myset "four"
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N))

1.6.18 ZSCORE key member

Redis zscore 命令用于返回有序集 key.中成员 member 的分数。

如果有续集中 不存在 member ,或者 key 不存在,返回 nil

  • 语法:

    1
    127.0.0.1:6379> ZSCORE key member
  • 返回值:

    多行字符串: 成员的分数。(双精度浮点数,字符串格式)

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZSCORE myset "two"
    "2"
    127.0.0.1:6379> ZSCORE myset "one"
    "1"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.6.19 ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

Redis ZUNIONSTORE 用于计算给定的numkeys个有序集合的并集,并且把结果放到destination中。

在给定要计算的key和其它参数之前,必须先给定key个数(numkeys)。

默认情况下,结果集中某个成员的score值是所有给定集中该成员score值之和。

使用WEIGHTS选项,你可以为每个给定的有序集指定一个乘法因子,意思就是,每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。如果WEIGHTS没有给定,默认是 1

使用AGGREGATE选项,你可以指定并集的结果集的聚合方式。默认使用的参数SUM,可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。如果使用参数MIN或者MAX,结果集就是所有集合中该元素最小或最大score。

如果destination存在,会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • 返回值:

    整数: 结果集destination中成员的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> ZADD myset1 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZADD myset2 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZUNIONSTORE out 2 myset1 myset2 WEIGHTS 2 3
    (integer) 3
    127.0.0.1:6379> ZRANGE out 0 -1 WITHSCORES
    1) "one"
    2) "5"
    3) "three"
    4) "9"
    5) "two"
    6) "10"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N)+O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set.

1.6.20 ZSCAN key cursor [MATCH pattern] [COUNT count]

查看 SCAN 获取关于 ZSCAN 命令的信息。

  • 语法:

    1
    127.0.0.1:6379> ZSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明:

    • cursor: 游标。
    • pattern: 匹配的模式。
    • count: 指定从数据集里返回多少元素,默认值为 10
  • 返回值:

    返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZSCAN myset 0 match *w*
    1) "0"
    2) 1) "two"
    2) "2"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.7 Redis 发布订阅

1.7.1 PSUBSCRIBE pattern [pattern …]

Redis PSUBSCRIBE 命令用于订阅一个或多个符合给定模式的频道。

模式支持 glob 风格的正则表达式。每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.newsit.blogit.tweets 等等), news.* 匹配所有以 news. 开头的频道( news.itnews.global.today 等等),诸如此类。

特殊字符使用 \ 转义。

  • 语法:

    1
    127.0.0.1:6379> PSUBSCRIBE pattern [pattern ...]
  • 返回值:

    接收到的信息。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Redis PUBLISH test"
    1) "message"
    2) "rediscomcnChat"
    3) "Learn redis with python"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of patterns the client is already subscribed to.

1.7.2 PUBSUB subcommand [argument [argument …]]

Redis Pubsub 命令用于查看订阅与发布系统状态,它由数个不同格式的子命令组成。

  1. PUBSUB CHANNELS [pattern]

    列出当前的活跃频道。

    活跃频道指的是那些至少有一个订阅者的频道, 订阅模式的客户端不计算在内。

    pattern 参数是可选的:

    • 如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
    • 如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。

    返回值:

    数组: 一个由活跃频道组成的列表。

  2. PUBSUB NUMSUB [channel-1 ... channel-N]

    返回给定频道的订阅者数量, 订阅模式的客户端不计算在内。

    返回值:

    数组: 一个多条批量回复(Multi-bulk reply),回复中包含给定的频道,以及频道的订阅者数量。

    格式为:频道 channel-1channel-1 的订阅者数量,频道 channel-2channel-2 的订阅者数量,诸如此类。

    回复中频道的排列顺序和执行命令时给定频道的排列顺序一致。

    不给定任何频道而直接调用这个命令也是可以的, 在这种情况下, 命令只返回一个空列表。

  3. PUBSUB NUMPAT

    返回订阅模式的数量。

    注意, 这个命令返回的不是订阅模式的客户端的数量, 而是客户端订阅的所有模式的数量总和。

    返回值:

    整数: 所有客户端订阅的所有模式的数量总和。

  • 语法:

    1
    127.0.0.1:6379> PUBSUB subcommand [argument [argument ...]]
  • 返回值:

    数组: 一个由活跃频道组成的列表。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> PUBSUB CHANNELS
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(N) for the CHANNELS subcommand, where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns). O(N) for the NUMSUB subcommand, where N is the number of requested channels. O(1) for the NUMPAT subcommand.

1.7.3 PUBLISH channel message

Redis PUBLISH 命令用于将信息 message 发送到指定的频道 channel

  • 语法:

    1
    127.0.0.1:6379> PUBLISH channel message
  • 返回值:

    整数: 接收到信息 message 的订阅者数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 对没有订阅者的频道发送信息
    127.0.0.1:6379> PUBLISH bad_channel "can any body hear me?"
    (integer) 0
    # 向有一个订阅者的频道发送信息
    127.0.0.1:6379> PUBLISH rediscomcnChat "Hello World"
    (integer) 1
    # # 向有多个订阅者的频道发送信息(前提是,启动了多个订阅者)
    127.0.0.1:6379> PUBLISH rediscomcnChat1 "two channel infos"
    (integer) 2
    127.0.0.1:6379>

    在订阅者频道可以接收到最新消息:

    l lsh l
    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Hello World"

可用版本>= 2.0.0.

时间复杂度: O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).

1.7.4 PUNSUBSCRIBE [pattern [pattern …]]

Redis PUNSUBSCRIBE 命令用于客户端退订所有给定模式。

如果没有模式被指定,也即是,一个无参数的 PUNSUBSCRIBE 调用被执行,那么客户端使用PSUBSCRIBE 命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式。

  • 语法:

    1
    127.0.0.1:6379> PUNSUBSCRIBE [pattern [pattern ...]]
  • 返回值:

    这个命令在不同的客户端中有不同的表现。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PUNSUBSCRIBE rediscomcnChat1
    1) "punsubscribe"
    2) "rediscomcnChat1"
    3) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N+M) where N is the number of patterns the client is already subscribed and M is the number of total patterns subscribed in the system (by any client).

1.7.5 SUBSCRIBE channel [channel …]

Redis SUBSCRIBE 命令用于订阅给定的一个或多个频道的信息。

进入订阅模式后只能执行如下命令: SUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, PUNSUBSCRIBE, PING 和QUIT 。

  • 语法:

    1
    127.0.0.1:6379> SUBSCRIBE channel [channel ...]
  • 返回值:

    接收到的信息

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Hello World"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of channels to subscribe to.

1.7.6 UNSUBSCRIBE [channel [channel …]]

Redis UNSUBSCRIBE 命令用于指示客户端退订给定的频道。

如果没有频道被指定,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。

  • 语法:

    1
    127.0.0.1:6379> UNSUBSCRIBE [channel [channel ...]]
  • 返回值:

    这个命令在不同的客户端中有不同的表现。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> UNSUBSCRIBE rediscomcnChat1
    1) "unsubscribe"
    2) "rediscomcnChat1"
    3) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of clients already subscribed to a channel.

1.8 Redis 事务

1.8.1 DISCARD

DISCARD 命令取消事务,放弃执行事务队列内的所有命令,恢复连接为非 (transaction) 模式。

如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH 。

  • 语法:

    1
    127.0.0.1:6379> DISCARD
  • 返回值:

    字符串: OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> ping
    QUEUED
    127.0.0.1:6379(TX)> SET myset "kungs"
    QUEUED
    127.0.0.1:6379(TX)> DISCARD
    OK
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.8.2 EXEC

Redis EXEC 命令用于执行事务 (transaction )队列内的所有命令。

假如某个(或某些) key 正处于 WATCH 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么EXEC 命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。 check-and-set mechanism.

  • 语法:

    1
    127.0.0.1:6379> EXEC
  • 返回值:

    事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    # 事务被成功执行
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> PING
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    # 监视 key ,且事务成功执行
    127.0.0.1:6379> WATCH lock lock_times
    OK
    127.0.0.1:6379>
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> SET lock "huangz"
    QUEUED
    127.0.0.1:6379(TX)> INCR lock_times
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) OK
    2) (integer) 1
    # 监视 key ,且事务被打断
    127.0.0.1:6379> WATCH lock lock_times
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> SET lock "joe" # 就在这时,另一个客户端修改了 lock_times 的值
    QUEUED
    127.0.0.1:6379(TX)> INCR lock_times
    QUEUED
    127.0.0.1:6379(TX)> EXEC # 因为 lock_times 被修改, joe 的事务执行失败
    (nil)
    127.0.0.1:6379>

可用版本>= 1.2.0.

1.8.3 MULTI

Redis MULTI 命令用于标记一个事务块的开始。

事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。

  • 语法:

    1
    127.0.0.1:6379> MULTI
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> PING
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    127.0.0.1:6379>

可用版本>= 1.2.0.

1.8.4 UNWATCH

Redis UNWATCH命令用于取消 WATCH 命令对所有 key 的监视。
详细参考 transaction.
如果执行过 EXEC 或DISCARD,无需再执行 UNWATCH。
因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH了。

  • 语法:

    1
    127.0.0.1:6379> UNWATCH
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379>  WATCH lock lock_times
    OK
    127.0.0.1:6379> UNWATCH
    OK
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.8.5 WATCH key [key …]

Redis WATCH 命令用于标记要监视的key,以便有条件地执行事务(更多参考transaction)。

WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。

监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)

  • 语法:

    1
    127.0.0.1:6379> WATCH key [key ...]
  • 返回值:

    字符串: 总是返回OK

  • 实例:

    1
    2
    3
    127.0.0.1:6379>  WATCH lock lock_times
    OK
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for every key.

1.9 Script(脚本)

1.9.1 EVAL script numkeys key [key ...] arg [arg ...]

Redis Eval 命令使用 Lua 解释器执行脚本。

  • 语法:

    1
    127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]

    参数说明

    • script: 参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。
    • numkeys: 用于指定键名参数的个数。
    • key [key …]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    • arg [arg …]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
  • 返回值:

    返回需要执行的输出内容。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.2 EVALSHA sha1 numkeys key [key ...] arg [arg ...]

Redis Evalsha 命令根据给定的 sha1 校验码,执行缓存在服务器中的脚本。

将脚本缓存到服务器的操作可以通过 SCRIPT LOAD 命令进行。

这个命令的其他地方,比如参数的传入方式,都和 EVAL 命令一样。

  • 语法:

    1
    127.0.0.1:6379> EVALSHA sha1 numkeys key [key ...] arg [arg ...]

    参数说明:

    • sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
    • numkeys: 用于指定键名参数的个数。
    • key [key …]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    • arg [arg …]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
  • 返回值:

    输出缓存的数据内容。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
    "hello moto"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.3 SCRIPT EXISTS sha1 [sha1 ...]

Redis Script Exists 命令用于校验指定的脚本是否已经被保存在缓存当中。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT EXISTS sha1 [sha1 ...]
  • 返回值:

    一个列表,包含 0 和 1 ,前者表示脚本不存在于缓存,后者表示脚本已经在缓存里面了。

    列表中的元素和给定的 SHA1 校验和保持对应关系,比如列表的第三个元素的值就表示第三个 SHA1 校验和所指定的脚本在缓存中的状态。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 载入一个脚本
    127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    127.0.0.1:6379> SCRIPT EXISTS "232fd51614574cf0867b83d384a5e898cfd24e5a"
    1) (integer) 1
    # 清空缓存
    127.0.0.1:6379> SCRIPT FLUSH
    OK
    127.0.0.1:6379> SCRIPT EXISTS "232fd51614574cf0867b83d384a5e898cfd24e5a"
    1) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.4 SCRIPT FLUSH

Redis Script Flush 命令用于清除所有 Lua 脚本缓存。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT FLUSH
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT FLUSH
    OK
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.5 SCRIPT KILL

Redis Script kill 命令用于杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效。

这个命令主要用于终止运行时间过长的脚本,比如一个因为 BUG 而发生无限循环的脚本。

SCRIPT KILL 执行之后,当前正在运行的脚本会被杀死,执行这个脚本的客户端会从 EVAL 命令的阻塞当中退出,并收到一个错误作为返回值。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT KILL
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT KILL
    OK
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.6 SCRIPT LOAD script

Redis Script Load 命令用于将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

EVAL 命令也会将脚本添加到脚本缓存中,但是它会立即对输入的脚本进行求值。

如果给定的脚本已经在缓存里面了,那么不执行任何操作。

在脚本被加入到缓存之后,通过 EVALSHA 命令,可以使用脚本的 SHA1 校验和来调用这个脚本。

脚本可以在缓存中保留无限长的时间,直到执行 SCRIPT FLUSH 为止。

关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 EVAL 命令。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT LOAD script
  • 返回值:

    给定脚本的 SHA1 校验和

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT LOAD "return 1"
    "e0e1f9fabfc9d4800c877a703b823ac0578ff8db"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.10 Connection(连接)

1.10.1 AUTH [username] password

Redis AUTH 命令用来设置如下两种方式对访问Redis进行权限控制:

  1. 通过 requirepass 设置访问密码。If the Redis server is password protected via the requirepass option.
  2. Redis 6.0 起,支持ACL权限控制,具体参考 Redis ACL system

对应于配置文件中的 requirepass 命令。通过配置 requirepass ,可以使 Redis 拒绝未使用 AUTH 验证访问权限的客户端链接。

如果 AUTH 命令验证的密码与配置文件requirepass 配置的相同,则密码验证通过,服务器返回OK,并开始接受客户端的命令。

密码验证失败,则返回提示信息重新输入密码。

安全注意

因为redis的高性能能在短时间接受非常多的尝试性密码,所以请务必设置一个足够复杂的密码以防止可能的攻击。推荐使用 ACL GENPASS 命令生成密码。

  • 语法:

    当使用 Redis ACLs 权限控制时,AUTH 验证格式如下:

    1
    127.0.0.1:6379> AUTH [username] password

    通过验证用户名密码的方式验证访问权限,详细参考 ACL guide

    在 ACLs 模式下,如果传递一个密码参数给 AUTH,那么会隐式设置用户名 “default”。

  • 返回值:

    字符串: 验证失败时返回错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> AUTH PASSWORD
    (error) ERR Client sent AUTH, but no password is set
    127.0.0.1:6379> CONFIG SET requirepass "yanpenggong"
    OK
    127.0.0.1:6379> AUTH mypass
    Ok

可用版本>= 1.0.0.

1.10.2 ECHO message

Redis ECHO 命令用于打印一个给定的信息 message ,测试时使用。

  • 语法:

    1
    127.0.0.1:6379> ECHO message
  • 返回值:

    多行字符串:返回字符串message本身。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> ECHO "Hello World"
    "Hello World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.10.3 PING

Redis PING 命令用于客户端向 Redis 服务器发送一个 PING ,如果服务器运作正常的话,会返回一个 PONG 。PING 命令不带参数返回 PONG 。带参数则返回参数 message

PING 通常用来测试连接是否存活,或者测试延迟。

如果客户端订阅某个频道或某个模式,不带参数执行命令会返回一个数组第一个元素是 “pong” ,第二个元素是空,带参数执行同样返回参数 message

  • 语法:

    1
    127.0.0.1:6379> PING
  • 返回值:

    字符串:如果连接正常就返回一个 PONG ,否则返回一个连接错误。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PING
    PONG
    127.0.0.1:6379> PING "Hello World"
    "Hello World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.10.4 QUIT

Redis QUIT 命令用于请求服务器关闭连接。在当前连接上的待处理请求完成后,立刻断开连接。

  • 语法:

    1
    127.0.0.1:6379> QUIT
  • 返回值:

    字符串: 总是返回 OK。

  • 实例:

    1
    2
    127.0.0.1:6379> QUIT
    [root@localhost redis-6.2.6]#

可用版本>= 1.0.0.

1.10.5 SELECT index

Redis SELECT 命令用于切换到指定的数据库,index 是从 0 开始的整数。默认使用数据库 0 。
Redis 可选择的数据库是一种逻辑命名空间格式:物理上所有的数据库还是持久化在一起的,在同一个RDB/AOF文件中。不同的数据库中可以有同名的 key, FLUSHDB, SWAPDB或 RANDOMKEY 这些命令都是针对选定的数据库有效。
从实际应用角度出发,Redis databases 主要用来表示不同的 key 属于同一个应用,而不是一个 Redis 实例对应多个不同的应用。
Reids 分片(Cluster)不能使用 SELECT 。因为 Redis 分片只支持数据库 0 。Redis 分片的情况下,有多个数据库是没有用的。
当前选定的数据库是连接的一个属性,客户端应该记录当前连接的数据库并在重连的时候重新选择对应的数据库。
没有查询当前连接所选择的数据库的命令,可以使用 CLIENT LIST 输出所有用户当前选择的数据库。

  • 语法:

    1
    127.0.0.1:6379> SELECT index
  • 返回值:

    字符串:总是返回 OK 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 默认使用 0 号数据库
    127.0.0.1:6379> SET dn_number 0
    OK
    # 使用 1 号数据库
    127.0.0.1:6379> SELECT 1
    OK
    # 已经切换到 1 号数据库,注意 Redis 现在的命令提示符多了个 [1]
    127.0.0.1:6379[1]> GET db_number
    (nil)
    127.0.0.1:6379[1]> SET db_number 1
    OK
    127.0.0.1:6379[1]> GET db_number
    "1"
    # 再切换到 3 号数据库
    127.0.0.1:6379[1]> SELECT 3
    OK
    # 提示符从 [1] 改变成了 [3]
    127.0.0.1:6379[3]>

可用版本>= 1.0.0.

1.11 SERVER(服务器)

1.11.1 BGREWRITEAOF

Redis BGREWRITEAOF 命令用于异步执行一个 AOF(Append Only File ) 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。

即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

只有当后台没有正在运行的持久化进程的时候,重写才会被 Redis 触发。

具体来说:

  • 如果一个 redis 的子进程在创建磁盘快照,AOF 重写被列入执行计划但是不会执行直到生成 RDB 的子程序退出。在这种情况下 BGREWRITEAOF 将仍然返回OK状态码, 不过使用一个合适的提示信息。你可以检查一个 AOF 重写是否被例入执行计划通过查询 INFO 命令。
  • 如果一个 AOF rewrite 已经在运行,那么这个命令将会返回错误并且不会有 AOF rewrite 命令被列入后续的执行计划中。
  • 如果 AOF 重启可以启动,但是在运行开始的时候失败(例如创建子进程失败),会返回错误信息给调用者。

从 Redis 2.4 起 AOF rewrite 是被自动触发的,当然 BGREWRITEAOF 命令可以用来在任何时间触发重写。

请参考 Redis持久化文档 获取更多信息。

  • 语法:

    1
    127.0.0.1:6379> BGREWRITEAOF
  • 返回值:

    字符串: 启动重写的提示信息或者执行错误信息。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> BGREWRITEAOF
    Background append only file rewriting started
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.2 BGSAVE

后台保存DB。一般立即返回 OK 状态码。 Redis forks, 父进程继续提供服务以供客户端调用,子进程将DB数据保存到磁盘然后退出。

如果有运行中的SAVE或AOF返回错误。

如果使用 BGSAVE SCHEDULE 那么立即返回 OK ,如果后台正好有运行中的AOF,SAVE操作会在下次运行。

客户端可以通过 LASTSAVE 命令查看相关信息,判断 BGSAVE 命令是否执行成功。

请移步 持久化文档 查看更多相关细节。

  • 语法:

    1
    127.0.0.1:6379> BGSAVE [SCHEDULE]
  • 返回值:

    字符串: Background saving startedBackground saving scheduled 使用 SCHEDULE 时。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> BGSAVE
    Background saving started
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.3 CLIENT KILL

Redis CLIENT KILL 命令用于关闭地址为 ip:port 的客户端连接。

  • 语法:

    1
    127.0.0.1:6379> CLIENT KILL [ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [USER username] [ADDR ip:port] [SKIPME yes/no]

    ip:port 应该和 CLIENT LIST 命令返回的结果中 addr 列其中一行匹配。

    因为 Redis 使用单线程设计,所以当 Redis 正在执行命令的时候,不会有客户端被断开连接。

    如果要被断开连接的客户端正在执行命令,那么当这个命令执行之后,在发送下一个命令的时候,它就会收到一个网络错误,告知它自身的连接已被关闭。

    可以根据不同属性杀死客户端而不是只按地址杀死。他们有以下选项:

    • CLIENT KILL ADDR ip:port 和旧版的三个参数时的行为完全一样。
    • CLIENT KILL ID client-id 可以通过唯一ID字段杀死一个客户端,唯一ID可以通过Redis2.8.12的CLIENT LIST命令查询。
    • CLIENT KILL TYPE type 这里的 type 可以是 normal, slave, pubsub。 这将关闭给定烈性的所有客户端。请注意MONITOR命令阻塞的客户端是 normal 类型。
    • CLIENT KILL USER username 关闭使用 ACL username 连接的客户端。如果不存在 ACL user 则返回错误。
    • CLIENT KILL SKIPME yes/no 默认情况下是 yes, 调用该命令的客户端自身不被删掉,如果为 no 也会删除自身。
  • 返回值:

    三参数格式执行命令:字符串: 连接存在并被关闭返回 OK

    新格式:整数: 被杀死的客户端个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 列出所有已连接客户端
    127.0.0.1:6379> CLIENT list
    id=90 addr=127.0.0.1:34566 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    # 杀死当前客户端的连接
    127.0.0.1:6379> CLIENT KILL 127.0.0.1:34566
    OK
    # 之前的连接已经被关闭,CLI 客户端又重新建立了连接
    # 之前的端口是 34566 ,现在是 34568
    127.0.0.1:6379> CLIENT list
    id=91 addr=127.0.0.1:34568 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the number of client connections

1.11.4 CLIENT LIST

Redis CLIENT LIST 命令用于返回所有连接到服务器的客户端信息和统计数据。

从 v5.0 起,TYPE type 子命令可以用来过滤客户端类型,type 可以是 normal, master, replicapubsub

注意,被 MONITOR 阻塞的客户端被归类为 normal 类型。

  • 语法:

    1
    127.0.0.1:6379> CLIENT LIST [TYPE normal|master|replica|pubsub]
  • 返回值:

    命令返回多行字符串,这些字符串按以下形式被格式化:

    • 每个已连接客户端对应一行(以 LF 分割)
    • 每行字符串由一系列 属性=值 形式的域组成,每个域之间以空格分开

    以下是域的含义:

    • addr : 客户端的地址和端口
    • fd : 套接字所使用的文件描述符
    • age : 以秒计算的已连接时长
    • idle : 以秒计算的空闲时长
    • flags : 客户端 flag
    • db : 该客户端正在使用的数据库 ID
    • sub : 已订阅频道的数量
    • psub : 已订阅模式的数量
    • multi : 在事务中被执行的命令数量
    • qbuf : 查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
    • qbuf-free : 查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
    • obl : 输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
    • oll : 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
    • omem : 输出缓冲区和输出列表占用的内存总量
    • events : 文件描述符事件
    • cmd : 最近一次执行的命令

    客户端 flag 可以由以下部分组成:

    • O : 客户端是 MONITOR 模式下的附属节点(slave)
    • S : 客户端是一般模式下(normal)的附属节点
    • M : 客户端是主节点(master)
    • x : 客户端正在执行事务
    • b : 客户端正在等待阻塞事件
    • i : 客户端正在等待 VM I/O 操作(已废弃)
    • d : 一个受监视(watched)的键已被修改, EXEC 命令将失败
    • c : 在将回复完整地写出之后,关闭链接
    • u : 客户端未被阻塞(unblocked)
    • A : 尽可能快地关闭连接
    • N : 未设置任何 flag

    文件描述符事件可以是:

    • r : 客户端套接字(在事件 loop 中)是可读的(readable)
    • w : 客户端套接字(在事件 loop 中)是可写的(writeable)
  • 实例:

    1
    2
    3
    127.0.0.1:6379> CLIENT LIST
    id=92 addr=127.0.0.1:34570 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the number of client connections

1.11.5 CLIENT GETNAME

Redis CLIENT GETNAME 命令用于返回 CLIENT SETNAME命令为当前连接设置的名字。 因为新创建的连接默认是没有名字的, 对于没有名字的连接, CLIENT GETNAME 返回空白回复。

  • 语法:

    1
    127.0.0.1:6379> CLIENT GETNAME
  • 返回值:

    多行字符串: 如果连接没有设置名字,那么返回空白回复; 如果有设置名字,那么返回名字。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 新连接默认没有名字
    127.0.0.1:6379> CLIENT GETNAME
    (nil)
    # 设置名字
    127.0.0.1:6379> CLIENT SETNAME hello-world-connection
    OK
    # 返回名字
    127.0.0.1:6379> CLIENT GETNAME
    "hello-world-connection"
    127.0.0.1:6379>

可用版本>= 2.6.9.

时间复杂度: O(1)

1.11.6 CLIENT PAUSE

CLIENT PAUSE 是连接控制命令,它可以将所有客户端的访问暂停给定的毫秒数。

该命令执行如下:

  • 它会停止处理所有来自一般客户端或者pub/sub客户端的命令。但是和slaves的复制命令不受影响。
  • 因为它会立刻返回OK给调用者,所以CLIENT PAUSE 不会被自己暂停。
  • 当给定的时间结束,所有的客户端都被解除阻塞:这时所有客户端的查询缓存里积累的所有命令都会被处理。

CLIENT PAUSE 命令可以可控的将客户端从一个Redis实例切换至另一个实例。

比如,当需要升级一个实例时,管理员可以作如下操作:

  • 使用CLIENT PAUSE 暂停所有客户端
  • 等待数秒,让slaves 节点处理完所有来自master的复制命令
  • 将一个salve节点切换为 master
  • 重配客户端以来接新的 master 节点

可以在MULTI/EXEC中一起使用CLIENT PAUSE 和INFO replication以在阻塞的同时获取当前master的偏移量。用这种方法,可以检查slaves处理至给定的复制偏移节点,确保复制完整。

从 3.2.10 / 4.0.0 起,该命令也会停止过期和淘汰在暂停时期,保持数据处于静止不变的状态。

  • 语法:

    1
    127.0.0.1:6379> CLIENT PAUSE timeout 
  • 返回值:

    字符串: OK 或者 error timeout is invalid。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> CLIENT PAUSE 10
    OK
    127.0.0.1:6379>

可用版本>= 2.9.50.

时间复杂度: O(1)

1.11.7 CLIENT SETNAME

Redis CLIENT SETNAME 命令为当前连接设置一个名字。

这个名字会显示在CLIENT LIST命令的结果中, 用于客户端识别当前与服务器之间的连接。

例如, 在使用 Redis 构建队列(queue)时, 可以根据连接负责的任务(role), 为信息生产者(producer)和信息消费者(consumer)分别设置不同的名字。

名字使用 Redis 的字符串类型来保存, 最大可以占用 512 MB 。 另外, 为了避免和CLIENT LIST 命令的输出格式发生冲突, 名字里不允许使用空格。

要移除一个连接的名字, 可以将连接的名字设为空字符串 “” 。

使用 CLIENT GETNAME 命令可以取出连接的名字。

新创建的连接默认是没有名字的。

提示:在 Redis 应用程序发生连接泄漏时,为连接设置名字是一种很好的 debug 手段。

  • 语法:

    1
    127.0.0.1:6379> CLIENT SETNAME connection-name
  • 返回值:

    字符串: OK 设置成功。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 新连接默认没有名字
    127.0.0.1:6379> CLIENT GETNAME
    (nil)
    # 设置名字
    127.0.0.1:6379> CLIENT SETNAME link1-connection
    OK
    # 返回名字
    127.0.0.1:6379> CLIENT GETNAME
    "link1-connection"
    # 在客户端列表中查看
    127.0.0.1:6379> CLIENT LIST
    id=94 addr=127.0.0.1:34574 laddr=127.0.0.1:6379 fd=7 name=link1-connection age=49 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    # 清除名字
    127.0.0.1:6379> CLIENT SETNAME # 只用空格是不行的!
    (error) ERR Unknown subcommand or wrong number of arguments for 'SETNAME'. Try CLIENT HELP.
    127.0.0.1:6379> CLIENT SETNAME "" # 必须双引号显示包围
    OK
    127.0.0.1:6379> CLIENT GETNAME # 清除完毕
    (nil)
    127.0.0.1:6379>

可用版本>= 2.6.9.

时间复杂度: O(1)

1.11.8 CLUSTER SLOTS

Redis Client Slots 命令用于当前的集群状态,以数组形式展示。

  • 语法:

    1
    127.0.0.1:6379> CLUSTER SLOT
  • 返回值:

    IP/端口嵌套的列表数组。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    127.0.0.1:6379> cluster slots
    1) 1) (integer) 0
    2) (integer) 4095
    3) 1) "127.0.0.1"
    2) (integer) 7000
    4) 1) "127.0.0.1"
    2) (integer) 7004
    2) 1) (integer) 12288
    2) (integer) 16383
    3) 1) "127.0.0.1"
    2) (integer) 7003
    4) 1) "127.0.0.1"
    2) (integer) 7007
    3) 1) (integer) 4096
    2) (integer) 8191
    3) 1) "127.0.0.1"
    2) (integer) 7001
    4) 1) "127.0.0.1"
    2) (integer) 7005
    4) 1) (integer) 8192
    2) (integer) 12287
    3) 1) "127.0.0.1"
    2) (integer) 7002
    4) 1) "127.0.0.1"
    2) (integer) 7006

可用版本>= 3.0.0.

时间复杂度: O(N) where N is the total number of Cluster nodes

1.11.9 COMMAND

Redis COMMAND 命令以数组的形式返回有关所有 Redis 命令的详细信息。

如果集群客户端必须知道命令中 key 的位置,以便命令可以转到匹配的实例, 但是 Redis 命令在接收一个 key,多个 key 甚至由其他数据分隔开的多个 key 之间会有所不同。

你可以使用 COMMAND 来为每一个命令缓存命令和 key 位置之间的映射关系,以实现命令到集群的精确路由。

  1. 嵌套结果数组:

    每一个顶级结果包含了六个嵌套的结果。每一个嵌套结果是:

    • 命令名称

    • 命令参数个数

    • 嵌套的命令选项

    • 参数列表中第一个 key 的位置

    • 参数列表中最后一个 key 的位置

    • 用于定位重复 key 的步数

  2. 命令名称

    命令名称是以小写字符串形式返回的命令。

  1. 命令参数个数

    | | |
    | —————————————————————————————— | —————————————————————————————— |
    | 1) 1) “get”
    2) (integer) 2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1 | 1) 1) “mget”
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1 |

    命令参数个数遵循一个简单的模式

    • 正数:命令拥有固定数量的必需参数。
    • 负数:命令拥有最小数量的必需参数,可以有更多的参数。

    命令参数个数包含计算命令名称本身。

    例如:

    • GET 参数个数是 2,因为该命令仅接收一个参数,并且命令格式始终是 GET _key_
    • MGET 的参数个数是 -2,因为该命令接收至少一个参数,但最多可以接收无限数量:MGET _key1_ [key2] [key3] ...

    MGET 中同样需要注意,『最后一个key的位置』的值是 -1,这表示 key 列表可以具有无限长度。

  2. 选项

    命令标志是包含一个或多个状态回复的数组:

    • write - 命令可能会导致修改
    • readonly - 命令永远不会修改键
    • denyoom - 如果当前发生OOM,则拒绝该命令
    • admin - 服务器管理命令
    • pubsub - 发布订阅相关的命令
    • noscript - 在脚本中将会拒绝此命令
    • random - 命令具有随机结果,在脚本中使用很危险
    • sort\for*script* - 如果从脚本调用,则排序输出
    • loading - 允许在数据库加载时使用此命令
    • stale - 允许在从节点具有陈旧数据时使用此命令
    • skip_monitor - 在MONITOR中不会显示此命令
    • asking - 集群相关的 - 即使正在导入数据也接受此命令
    • fast - 命令以常量或log(N)时间运行。用于延迟监控。
    • movablekeys - key在命令中没有预先确定的位置。你必须自己发现key
  3. 可变位置的 Key

    1
    2
    3
    4
    5
    6
    7
    8
    1) 1) "sort"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1

    某些 Redis 命令没有预先确定 key 的位置。对于那些命令,标志 movablekeys会被添加到命令的选项中。 Redis 集群客户端需要解析标记为 movabkeleys 的命令,以便定位所有相关的 key 的位置。

    目前需要解析 key 位置的完整命令列表:

    • SORT - 可选的 STORE key,可选的 BY 权重,可选的 GET keys
    • ZUNIONSTORE - keys 参数列表在 WEIGHT或者 AGGREGATE之前
    • ZINTERSTORE - keys 参数列表在 WEIGHT或者AGGREGATE之前
    • EVAL - keys 列表是在参数 numkeys 之后的 numkeys个参数
    • EVALSHA - keys 列表是在参数 numkeys之后的 numkeys 个参数

    另请参阅 COMMAND GETKEYS 来让 Redis 服务器告诉你任意给定完整命令中的 keys 在哪里。

  4. 参数列表中的第一个Key

    对大部分命令来说,第一个 key 的位置是 1。位置 0 始终是命令名称本身。

  5. 参数列表中的最后一个 Key

    Redis 命令通常可以接收一个 key,两个 key 或者无限数量的 key 。

    如果命令只接收一个 key,那么第一个 key 和最后一个 key 的位置都是1。

    如果命令接收两个 key(例如:BRPOPLPUSHSMOVERENAME等),那么最后一个 key 的位置是最后一个 key 在参数列表中的位置。

    如果命令接收无限数量的 key,那么最后一个 key 的位置是 -1。

  6. 步数

1) 1) “mset”
2) (integer) -3
3) 1) write
2) denyoom
4) (integer) 1
5) (integer) -1
6) (integer) 2
1) 1) “mget”
2) (integer) -2
3) 1) readonly
4) (integer) 1
5) (integer) -1
6) (integer) 1

Key 的步数允许我们在命令中查找 key 的位置,比如 MSET,其格式是 MSET _key1_ _val1_ [key2] [val2] [key3] [val3]...

MSET 的用例中,key 是每隔一个位置出现,所以步数的值是 2。对比上面的 MGET,其步数是 1。

  • 语法:

    1
    127.0.0.1:6379> COMMAND
  • 返回值:

    数组: 嵌套的命令详细信息列表。命令以随机的顺序返回。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
    757
    758
    759
    760
    761
    762
    763
    764
    765
    766
    767
    768
    769
    770
    771
    772
    773
    774
    775
    776
    777
    778
    779
    780
    781
    782
    783
    784
    785
    786
    787
    788
    789
    790
    791
    792
    793
    794
    795
    796
    797
    798
    799
    800
    801
    802
    803
    804
    805
    806
    807
    808
    809
    810
    811
    812
    813
    814
    815
    816
    817
    818
    819
    820
    821
    822
    823
    824
    825
    826
    827
    828
    829
    830
    831
    832
    833
    834
    835
    836
    837
    838
    839
    840
    841
    842
    843
    844
    845
    846
    847
    848
    849
    850
    851
    852
    853
    854
    855
    856
    857
    858
    859
    860
    861
    862
    863
    864
    865
    866
    867
    868
    869
    870
    871
    872
    873
    874
    875
    876
    877
    878
    879
    880
    881
    882
    883
    884
    885
    886
    887
    888
    889
    890
    891
    892
    893
    894
    895
    896
    897
    898
    899
    900
    901
    902
    903
    904
    905
    906
    907
    908
    909
    910
    911
    912
    913
    914
    915
    916
    917
    918
    919
    920
    921
    922
    923
    924
    925
    926
    927
    928
    929
    930
    931
    932
    933
    934
    935
    936
    937
    938
    939
    940
    941
    942
    943
    944
    945
    946
    947
    948
    949
    950
    951
    952
    953
    954
    955
    956
    957
    958
    959
    960
    961
    962
    963
    964
    965
    966
    967
    968
    969
    970
    971
    972
    973
    974
    975
    976
    977
    978
    979
    980
    981
    982
    983
    984
    985
    986
    987
    988
    989
    990
    991
    992
    993
    994
    995
    996
    997
    998
    999
    1000
    1001
    1002
    1003
    1004
    1005
    1006
    1007
    1008
    1009
    1010
    1011
    1012
    1013
    1014
    1015
    1016
    1017
    1018
    1019
    1020
    1021
    1022
    1023
    1024
    1025
    1026
    1027
    1028
    1029
    1030
    1031
    1032
    1033
    1034
    1035
    1036
    1037
    1038
    1039
    1040
    1041
    1042
    1043
    1044
    1045
    1046
    1047
    1048
    1049
    1050
    1051
    1052
    1053
    1054
    1055
    1056
    1057
    1058
    1059
    1060
    1061
    1062
    1063
    1064
    1065
    1066
    1067
    1068
    1069
    1070
    1071
    1072
    1073
    1074
    1075
    1076
    1077
    1078
    1079
    1080
    1081
    1082
    1083
    1084
    1085
    1086
    1087
    1088
    1089
    1090
    1091
    1092
    1093
    1094
    1095
    1096
    1097
    1098
    1099
    1100
    1101
    1102
    1103
    1104
    1105
    1106
    1107
    1108
    1109
    1110
    1111
    1112
    1113
    1114
    1115
    1116
    1117
    1118
    1119
    1120
    1121
    1122
    1123
    1124
    1125
    1126
    1127
    1128
    1129
    1130
    1131
    1132
    1133
    1134
    1135
    1136
    1137
    1138
    1139
    1140
    1141
    1142
    1143
    1144
    1145
    1146
    1147
    1148
    1149
    1150
    1151
    1152
    1153
    1154
    1155
    1156
    1157
    1158
    1159
    1160
    1161
    1162
    1163
    1164
    1165
    1166
    1167
    1168
    1169
    1170
    1171
    1172
    1173
    1174
    1175
    1176
    1177
    1178
    1179
    1180
    1181
    1182
    1183
    1184
    1185
    1186
    1187
    1188
    1189
    1190
    1191
    1192
    1193
    1194
    1195
    1196
    1197
    1198
    1199
    1200
    1201
    1202
    1203
    1204
    1205
    1206
    1207
    1208
    1209
    1210
    1211
    1212
    1213
    1214
    1215
    1216
    1217
    1218
    1219
    1220
    1221
    1222
    1223
    1224
    1225
    1226
    1227
    1228
    1229
    1230
    1231
    1232
    1233
    1234
    1235
    1236
    1237
    1238
    1239
    1240
    1241
    1242
    1243
    1244
    1245
    1246
    1247
    1248
    1249
    1250
    1251
    1252
    1253
    1254
    1255
    1256
    1257
    1258
    1259
    1260
    1261
    1262
    1263
    1264
    1265
    1266
    1267
    1268
    1269
    1270
    1271
    1272
    1273
    1274
    1275
    1276
    1277
    1278
    1279
    1280
    1281
    1282
    1283
    1284
    1285
    1286
    1287
    1288
    1289
    1290
    1291
    1292
    1293
    1294
    1295
    1296
    1297
    1298
    1299
    1300
    1301
    1302
    1303
    1304
    1305
    1306
    1307
    1308
    1309
    1310
    1311
    1312
    1313
    1314
    1315
    1316
    1317
    1318
    1319
    1320
    1321
    1322
    1323
    1324
    1325
    1326
    1327
    1328
    1329
    1330
    1331
    1332
    1333
    1334
    1335
    1336
    1337
    1338
    1339
    1340
    1341
    1342
    1343
    1344
    1345
    1346
    1347
    1348
    1349
    1350
    1351
    1352
    1353
    1354
    1355
    1356
    1357
    1358
    1359
    1360
    1361
    1362
    1363
    1364
    1365
    1366
    1367
    1368
    1369
    1370
    1371
    1372
    1373
    1374
    1375
    1376
    1377
    1378
    1379
    1380
    1381
    1382
    1383
    1384
    1385
    1386
    1387
    1388
    1389
    1390
    1391
    1392
    1393
    1394
    1395
    1396
    1397
    1398
    1399
    1400
    1401
    1402
    1403
    1404
    1405
    1406
    1407
    1408
    1409
    1410
    1411
    1412
    1413
    1414
    1415
    1416
    1417
    1418
    1419
    1420
    1421
    1422
    1423
    1424
    1425
    1426
    1427
    1428
    1429
    1430
    1431
    1432
    1433
    1434
    1435
    1436
    1437
    1438
    1439
    1440
    1441
    1442
    1443
    1444
    1445
    1446
    1447
    1448
    1449
    1450
    1451
    1452
    1453
    1454
    1455
    1456
    1457
    1458
    1459
    1460
    1461
    1462
    1463
    1464
    1465
    1466
    1467
    1468
    1469
    1470
    1471
    1472
    1473
    1474
    1475
    1476
    1477
    1478
    1479
    1480
    1481
    1482
    1483
    1484
    1485
    1486
    1487
    1488
    1489
    1490
    1491
    1492
    1493
    1494
    1495
    1496
    1497
    1498
    1499
    1500
    1501
    1502
    1503
    1504
    1505
    1506
    1507
    1508
    1509
    1510
    1511
    1512
    1513
    1514
    1515
    1516
    1517
    1518
    1519
    1520
    1521
    1522
    1523
    1524
    1525
    1526
    1527
    1528
    1529
    1530
    1531
    1532
    1533
    1534
    1535
    1536
    1537
    1538
    1539
    1540
    1541
    1542
    1543
    1544
    1545
    1546
    1547
    1548
    1549
    1550
    1551
    1552
    1553
    1554
    1555
    1556
    1557
    1558
    1559
    1560
    1561
    1562
    1563
    1564
    1565
    1566
    1567
    1568
    1569
    1570
    1571
    1572
    1573
    1574
    1575
    1576
    1577
    1578
    1579
    1580
    1581
    1582
    1583
    1584
    1585
    1586
    1587
    1588
    1589
    1590
    1591
    1592
    1593
    1594
    1595
    1596
    1597
    1598
    1599
    1600
    1601
    1602
    1603
    1604
    1605
    1606
    1607
    1608
    1609
    1610
    1611
    1612
    1613
    1614
    1615
    1616
    1617
    1618
    1619
    1620
    1621
    1622
    1623
    1624
    1625
    1626
    1627
    1628
    1629
    1630
    1631
    1632
    1633
    1634
    1635
    1636
    1637
    1638
    1639
    1640
    1641
    1642
    1643
    1644
    1645
    1646
    1647
    1648
    1649
    1650
    1651
    1652
    1653
    1654
    1655
    1656
    1657
    1658
    1659
    1660
    1661
    1662
    1663
    1664
    1665
    1666
    1667
    1668
    1669
    1670
    1671
    1672
    1673
    1674
    1675
    1676
    1677
    1678
    1679
    1680
    1681
    1682
    1683
    1684
    1685
    1686
    1687
    1688
    1689
    1690
    1691
    1692
    1693
    1694
    1695
    1696
    1697
    1698
    1699
    1700
    1701
    1702
    1703
    1704
    1705
    1706
    1707
    1708
    1709
    1710
    1711
    1712
    1713
    1714
    1715
    1716
    1717
    1718
    1719
    1720
    1721
    1722
    1723
    1724
    1725
    1726
    1727
    1728
    1729
    1730
    1731
    1732
    1733
    1734
    1735
    1736
    1737
    1738
    1739
    1740
    1741
    1742
    1743
    1744
    1745
    1746
    1747
    1748
    1749
    1750
    1751
    1752
    1753
    1754
    1755
    1756
    1757
    1758
    1759
    1760
    1761
    1762
    1763
    1764
    1765
    1766
    1767
    1768
    1769
    1770
    1771
    1772
    1773
    1774
    1775
    1776
    1777
    1778
    1779
    1780
    1781
    1782
    1783
    1784
    1785
    1786
    1787
    1788
    1789
    1790
    1791
    1792
    1793
    1794
    1795
    1796
    1797
    1798
    1799
    1800
    1801
    1802
    1803
    1804
    1805
    1806
    1807
    1808
    1809
    1810
    1811
    1812
    1813
    1814
    1815
    1816
    1817
    1818
    1819
    1820
    1821
    1822
    1823
    1824
    1825
    1826
    1827
    1828
    1829
    1830
    1831
    1832
    1833
    1834
    1835
    1836
    1837
    1838
    1839
    1840
    1841
    1842
    1843
    1844
    1845
    1846
    1847
    1848
    1849
    1850
    1851
    1852
    1853
    1854
    1855
    1856
    1857
    1858
    1859
    1860
    1861
    1862
    1863
    1864
    1865
    1866
    1867
    1868
    1869
    1870
    1871
    1872
    1873
    1874
    1875
    1876
    1877
    1878
    1879
    1880
    1881
    1882
    1883
    1884
    1885
    1886
    1887
    1888
    1889
    1890
    1891
    1892
    1893
    1894
    1895
    1896
    1897
    1898
    1899
    1900
    1901
    1902
    1903
    1904
    1905
    1906
    1907
    1908
    1909
    1910
    1911
    1912
    1913
    1914
    1915
    1916
    1917
    1918
    1919
    1920
    1921
    1922
    1923
    1924
    1925
    1926
    1927
    1928
    1929
    1930
    1931
    1932
    1933
    1934
    1935
    1936
    1937
    1938
    1939
    1940
    1941
    1942
    1943
    1944
    1945
    1946
    1947
    1948
    1949
    1950
    1951
    1952
    1953
    1954
    1955
    1956
    1957
    1958
    1959
    1960
    1961
    1962
    1963
    1964
    1965
    1966
    1967
    1968
    1969
    1970
    1971
    1972
    1973
    1974
    1975
    1976
    1977
    1978
    1979
    1980
    1981
    1982
    1983
    1984
    1985
    1986
    1987
    1988
    1989
    1990
    1991
    1992
    1993
    1994
    1995
    1996
    1997
    1998
    1999
    2000
    2001
    2002
    2003
    2004
    2005
    2006
    2007
    2008
    2009
    2010
    2011
    2012
    2013
    2014
    2015
    2016
    2017
    2018
    2019
    2020
    2021
    2022
    2023
    2024
    2025
    2026
    2027
    2028
    2029
    2030
    2031
    2032
    2033
    2034
    2035
    2036
    2037
    2038
    2039
    2040
    2041
    2042
    2043
    2044
    2045
    2046
    2047
    2048
    2049
    2050
    2051
    2052
    2053
    2054
    2055
    2056
    2057
    2058
    2059
    2060
    2061
    2062
    2063
    2064
    2065
    2066
    2067
    2068
    2069
    2070
    2071
    2072
    2073
    2074
    2075
    2076
    2077
    2078
    2079
    2080
    2081
    2082
    2083
    2084
    2085
    2086
    2087
    2088
    2089
    2090
    2091
    2092
    2093
    2094
    2095
    2096
    2097
    2098
    2099
    2100
    2101
    2102
    2103
    2104
    2105
    2106
    2107
    2108
    2109
    2110
    2111
    2112
    2113
    2114
    2115
    2116
    2117
    2118
    2119
    2120
    2121
    2122
    2123
    2124
    2125
    2126
    2127
    2128
    2129
    2130
    2131
    2132
    2133
    2134
    2135
    2136
    2137
    2138
    2139
    2140
    2141
    2142
    2143
    2144
    2145
    2146
    2147
    2148
    2149
    2150
    2151
    2152
    2153
    2154
    2155
    2156
    2157
    2158
    2159
    2160
    2161
    2162
    2163
    2164
    2165
    2166
    2167
    2168
    2169
    2170
    2171
    2172
    2173
    2174
    2175
    2176
    2177
    2178
    2179
    2180
    2181
    2182
    2183
    2184
    2185
    2186
    2187
    2188
    2189
    2190
    2191
    2192
    2193
    2194
    2195
    2196
    2197
    2198
    2199
    2200
    2201
    2202
    2203
    2204
    2205
    2206
    2207
    2208
    2209
    2210
    2211
    2212
    2213
    2214
    2215
    2216
    2217
    2218
    2219
    2220
    2221
    2222
    2223
    2224
    2225
    2226
    2227
    2228
    2229
    2230
    2231
    2232
    2233
    2234
    2235
    2236
    2237
    2238
    2239
    2240
    2241
    2242
    2243
    2244
    2245
    2246
    2247
    2248
    2249
    2250
    2251
    2252
    2253
    2254
    2255
    2256
    2257
    2258
    2259
    2260
    2261
    2262
    2263
    2264
    2265
    2266
    2267
    2268
    2269
    2270
    2271
    2272
    2273
    2274
    2275
    2276
    2277
    2278
    2279
    2280
    2281
    2282
    2283
    2284
    2285
    2286
    2287
    2288
    2289
    2290
    2291
    2292
    2293
    2294
    2295
    2296
    2297
    2298
    2299
    2300
    2301
    2302
    2303
    2304
    2305
    2306
    2307
    127.0.0.1:6379> COMMAND
    1) 1) "xsetid"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    2) 1) "lpop"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    3) 1) "xautoclaim"
    2) (integer) -6
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    4) 1) "discard"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    5) 1) "copy"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    6) 1) "type"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    7) 1) "failover"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    8) 1) "setnx"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    9) 1) "bgrewriteaof"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    10) 1) "psync"
    2) (integer) -3
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    11) 1) "smove"
    2) (integer) 4
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    12) 1) "zrevrangebylex"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    13) 1) "zinter"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    14) 1) "geopos"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    15) 1) "readwrite"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    16) 1) "hincrby"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    17) 1) "keys"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    4) @dangerous
    18) 1) "lpos"
    2) (integer) -3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    19) 1) "exec"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) skip_slowlog
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @transaction
    20) 1) "zcount"
    2) (integer) 4
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    21) 1) "zdiffstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    22) 1) "replconf"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    23) 1) "rpush"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    24) 1) "getdel"
    2) (integer) 2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    25) 1) "brpop"
    2) (integer) -3
    3) 1) write
    2) noscript
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    26) 1) "georadius"
    2) (integer) -6
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    27) 1) "persist"
    2) (integer) 2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    28) 1) "blpop"
    2) (integer) -3
    3) 1) write
    2) noscript
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    29) 1) "zrangebylex"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    30) 1) "sadd"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    31) 1) "unlink"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    32) 1) "hello"
    2) (integer) -1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    5) no_auth
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    33) 1) "smismember"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    34) 1) "msetnx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 2
    7) 1) @write
    2) @string
    3) @slow
    35) 1) "zrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    36) 1) "zscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    37) 1) "ltrim"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    38) 1) "save"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    39) 1) "replicaof"
    2) (integer) 3
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    40) 1) "sscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    41) 1) "decr"
    2) (integer) 2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    42) 1) "flushdb"
    2) (integer) -1
    3) 1) write
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    43) 1) "object"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @slow
    44) 1) "zmscore"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    45) 1) "geosearchstore"
    2) (integer) -8
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    46) 1) "srem"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    47) 1) "rpoplpush"
    2) (integer) 3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    48) 1) "zunion"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    49) 1) "pfselftest"
    2) (integer) 1
    3) 1) admin
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @hyperloglog
    2) @admin
    3) @slow
    4) @dangerous
    50) 1) "shutdown"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    51) 1) "pfdebug"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) admin
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @admin
    4) @slow
    5) @dangerous
    52) 1) "pexpireat"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    53) 1) "lset"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    54) 1) "zrem"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    55) 1) "sync"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    56) 1) "geodist"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    57) 1) "setrange"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    58) 1) "lmove"
    2) (integer) 5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    59) 1) "expireat"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    60) 1) "slaveof"
    2) (integer) 3
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    61) 1) "ttl"
    2) (integer) 2
    3) 1) readonly
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    62) 1) "incrby"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    63) 1) "move"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    64) 1) "monitor"
    2) (integer) 1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    65) 1) "lastsave"
    2) (integer) 1
    3) 1) random
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @fast
    3) @dangerous
    66) 1) "del"
    2) (integer) -2
    3) 1) write
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    67) 1) "flushall"
    2) (integer) -1
    3) 1) write
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    68) 1) "debug"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    69) 1) "zincrby"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    70) 1) "pttl"
    2) (integer) 2
    3) 1) readonly
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    71) 1) "restore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    72) 1) "xreadgroup"
    2) (integer) -7
    3) 1) write
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @write
    2) @stream
    3) @slow
    4) @blocking
    73) 1) "restore-asking"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) asking
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    74) 1) "dbsize"
    2) (integer) 1
    3) 1) readonly
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @fast
    75) 1) "geoadd"
    2) (integer) -5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    76) 1) "reset"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    77) 1) "zremrangebyscore"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    78) 1) "zscore"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    79) 1) "hscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    80) 1) "sunion"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    81) 1) "migrate"
    2) (integer) -6
    3) 1) write
    2) random
    3) movablekeys
    4) (integer) 3
    5) (integer) 3
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    82) 1) "zunionstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    83) 1) "xack"
    2) (integer) -4
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    84) 1) "rpushx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    85) 1) "role"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @dangerous
    86) 1) "pexpire"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    87) 1) "rename"
    2) (integer) 3
    3) 1) write
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    88) 1) "blmove"
    2) (integer) 6
    3) 1) write
    2) denyoom
    3) noscript
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    89) 1) "zremrangebylex"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    90) 1) "zrevrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    91) 1) "hkeys"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    92) 1) "mget"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    93) 1) "dump"
    2) (integer) 2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @slow
    94) 1) "srandmember"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    95) 1) "randomkey"
    2) (integer) 1
    3) 1) readonly
    2) random
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    96) 1) "georadiusbymember"
    2) (integer) -5
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    97) 1) "zrangestore"
    2) (integer) -5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    98) 1) "incrbyfloat"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    99) 1) "zrandmember"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    100) 1) "substr"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @slow
    101) 1) "incr"
    2) (integer) 2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    102) 1) "post"
    2) (integer) -1
    3) 1) readonly
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    103) 1) "zrank"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    104) 1) "hrandfield"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    105) 1) "zdiff"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    106) 1) "zrevrangebyscore"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    107) 1) "zadd"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    108) 1) "append"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    109) 1) "sdiffstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    110) 1) "hstrlen"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    111) 1) "linsert"
    2) (integer) 5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    112) 1) "zrevrank"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    113) 1) "watch"
    2) (integer) -2
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @fast
    2) @transaction
    114) 1) "hdel"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    115) 1) "script"
    2) (integer) -2
    3) 1) noscript
    2) may_replicate
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    116) 1) "punsubscribe"
    2) (integer) -1
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    117) 1) "lolwut"
    2) (integer) -1
    3) 1) readonly
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @fast
    118) 1) "xinfo"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    119) 1) "hgetall"
    2) (integer) 2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    120) 1) "hexists"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    121) 1) "multi"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    122) 1) "lindex"
    2) (integer) 3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    123) 1) "strlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    124) 1) "zlexcount"
    2) (integer) 4
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    125) 1) "xclaim"
    2) (integer) -6
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    126) 1) "zcard"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    127) 1) "stralgo"
    2) (integer) -2
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @string
    3) @slow
    128) 1) "host:"
    2) (integer) -1
    3) 1) readonly
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    129) 1) "scard"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    130) 1) "xgroup"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @slow
    131) 1) "rpop"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    132) 1) "unwatch"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    133) 1) "spop"
    2) (integer) -2
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    134) 1) "hget"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    135) 1) "pubsub"
    2) (integer) -2
    3) 1) pubsub
    2) random
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    136) 1) "lrange"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    137) 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
    138) 1) "renamenx"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    139) 1) "hvals"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    140) 1) "bgsave"
    2) (integer) -1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    141) 1) "georadiusbymember_ro"
    2) (integer) -5
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    142) 1) "setbit"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    143) 1) "exists"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    144) 1) "readonly"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    145) 1) "zrangebyscore"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    146) 1) "info"
    2) (integer) -1
    3) 1) random
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @dangerous
    147) 1) "xpending"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    148) 1) "lpush"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    149) 1) "scan"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    150) 1) "getbit"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @fast
    151) 1) "geosearch"
    2) (integer) -7
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    152) 1) "unsubscribe"
    2) (integer) -1
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    153) 1) "zinterstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    154) 1) "geohash"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    155) 1) "bitfield"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    156) 1) "bitop"
    2) (integer) -4
    3) 1) write
    2) denyoom
    4) (integer) 2
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    157) 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
    158) 1) "xread"
    2) (integer) -4
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @stream
    3) @slow
    4) @blocking
    159) 1) "bitfield_ro"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @fast
    160) 1) "sunionstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    161) 1) "decrby"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    162) 1) "sort"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @sortedset
    4) @list
    5) @slow
    6) @dangerous
    163) 1) "hmget"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    164) 1) "sdiff"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    165) 1) "evalsha"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    166) 1) "psetex"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    167) 1) "client"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) random
    4) loading
    5) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    4) @connection
    168) 1) "sinter"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    169) 1) "zpopmax"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    170) 1) "publish"
    2) (integer) 3
    3) 1) pubsub
    2) loading
    3) stale
    4) fast
    5) may_replicate
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @fast
    171) 1) "subscribe"
    2) (integer) -2
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    172) 1) "xadd"
    2) (integer) -5
    3) 1) write
    2) denyoom
    3) random
    4) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    173) 1) "swapdb"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @fast
    4) @dangerous
    174) 1) "lrem"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    175) 1) "llen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @fast
    176) 1) "select"
    2) (integer) 2
    3) 1) loading
    2) stale
    3) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    177) 1) "wait"
    2) (integer) 3
    3) 1) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @slow
    178) 1) "time"
    2) (integer) 1
    3) 1) random
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    179) 1) "brpoplpush"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) noscript
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    180) 1) "setex"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    181) 1) "touch"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    182) 1) "hlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    183) 1) "echo"
    2) (integer) 2
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    184) 1) "sismember"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    185) 1) "command"
    2) (integer) -1
    3) 1) random
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @connection
    186) 1) "xlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @fast
    187) 1) "xdel"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    188) 1) "slowlog"
    2) (integer) -2
    3) 1) admin
    2) random
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    189) 1) "bzpopmax"
    2) (integer) -3
    3) 1) write
    2) noscript
    3) fast
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    4) @blocking
    190) 1) "hsetnx"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    191) 1) "expire"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    192) 1) "ping"
    2) (integer) -1
    3) 1) stale
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    193) 1) "bzpopmin"
    2) (integer) -3
    3) 1) write
    2) noscript
    3) fast
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    4) @blocking
    194) 1) "memory"
    2) (integer) -2
    3) 1) readonly
    2) random
    3) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    195) 1) "xrevrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    196) 1) "pfadd"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @fast
    197) 1) "config"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    198) 1) "hmset"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    199) 1) "acl"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    200) 1) "xrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    201) 1) "zpopmin"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    202) 1) "lpushx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    203) 1) "auth"
    2) (integer) -2
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    5) no_auth
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    204) 1) "pfmerge"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @slow
    205) 1) "getrange"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @slow
    206) 1) "bitcount"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @slow
    207) 1) "getex"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    208) 1) "psubscribe"
    2) (integer) -2
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    209) 1) "smembers"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    210) 1) "cluster"
    2) (integer) -2
    3) 1) admin
    2) random
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    211) 1) "zremrangebyrank"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    212) 1) "pfcount"
    2) (integer) -2
    3) 1) readonly
    2) may_replicate
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @hyperloglog
    3) @slow
    213) 1) "bitpos"
    2) (integer) -3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @slow
    214) 1) "latency"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    215) 1) "hincrbyfloat"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    216) 1) "mset"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 2
    7) 1) @write
    2) @string
    3) @slow
    217) 1) "asking"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    218) 1) "xtrim"
    2) (integer) -4
    3) 1) write
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @slow
    219) 1) "hset"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    220) 1) "sinterstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    221) 1) "module"
    2) (integer) -2
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    222) 1) "eval"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    223) 1) "getset"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    224) 1) "georadius_ro"
    2) (integer) -6
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow

可用版本>= 2.8.13.

时间复杂度: O(N) where N is the total number of Redis commands

1.11.10 COMMAND COUNT

Redis Command Count 命令用于统计 redis 命令的个数。

  • 语法:

    1
    127.0.0.1:6379> COMMAND COUNT
  • 返回值:

    整数: 支持的命令类型总数。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> COMMAND COUNT
    (integer) 224
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(1)

1.11.11 COMMAND GETKEYS

以数据的形式检测一个 Redis 命令 中的 key。

COMMAND GETKEYS是一个辅助命令,让你可以从 Redis 命令中找到key。

COMMAND显示了某些命令拥有可变位置的key,这意味着必须分析完整的命令才能找到要存储或者检索的 key。 你可以使用COMMAND GETKEYS直接从 Redis 解析命令的方式来发现 key 的位置。

  • 语法:

    1
    127.0.0.1:6379> COMMAND GETKEYS
  • 返回值:

    数组: 命令参数中的 key。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> COMMAND GETKEYS MSET a b c d e f
    1) "a"
    2) "c"
    3) "e"
    127.0.0.1:6379> COMMAND GETKEYS EVAL "not consulted" 3 key1 key2 key3 arg1 arg2 arg3 argN
    1) "key1"
    2) "key2"
    3) "key3"
    127.0.0.1:6379> COMMAND GETKEYS SORT mylist ALPHA STORE outlist
    1) "mylist"
    2) "outlist"
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(N) where N is the number of arguments to the command

1.11.12 TIME

TIME 命令返回当前服务器的时间,包含两个条目 Unix 时间戳和这一秒已经过去的微秒数。基本上,该接口非常相似 gettimeofday。

  • 语法:

    1
    127.0.0.1:6379> TIME
  • 返回值:

    数组:

    返回内容包含两个元素

    • UNIX时间戳(单位:秒)
    • 微秒
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> TIME
    1) "1653066894"
    2) "387030"
    127.0.0.1:6379> TIME
    1) "1653066896"
    2) "328152"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.11.13 COMMAND INFO

以数组的形式返回多个Redis命令的详细信息。

此命令返回的结果与COMMAND相同,但是你可以指定返回哪些命令。

如果你指定了一些不存在的命令,那么在它们的返回位置将会是nil。

  • 语法:

    1
    127.0.0.1:6379> COMMAND INFO command-name [command-name ...]
  • 返回值:

    数组: 命令信息

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    127.0.0.1:6379> COMMAND INFO get set eval
    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
    3) 1) "eval"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    127.0.0.1:6379> COMMAND INFO foo evalsha config bar
    1) (nil)
    2) 1) "evalsha"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    3) 1) "config"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    4) (nil)
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(N) when N is number of commands to look up

1.11.14 CONFIG GET

Redis Config Get 命令用于获取 redis 服务的配置参数。

在 Redis 2.4 版本中, 有部分参数没有办法用 CONFIG GET 访问,但是在最新的 Redis 2.6 版本中,所有配置参数都已经可以用 CONFIG GET 访问了。

CONFIG GET对应的是修改运行时参数的命令 CONFIG SET.

CONFIG GET命令只接受一个 glob 风格的正则参数,所有配置参数都采用key-value的形式。 例如:

1
2
3
4
5
6
7
redis> config get *max-*-entries*
1) "hash-max-zipmap-entries"
2) "512"
3) "list-max-ziplist-entries"
4) "512"
5) "set-max-intset-entries"
6) "512"

通过 redis-cli 提示符下输入 CONFIG GET * 可以查看 Redis 所有支持的参数。

所有支持的参数都与 redis.conf 里面的一样,除了如下的重要差异:

  • 10kb2gb 这些在配置文件中所使用的储存单位缩写,不可以用在 CONFIG 命令中, CONFIG SET 的值只能通过数字值显式地设定。像 CONFIG SET xxx 1k 这样的命令是错误的,正确的格式是 CONFIG SET xxx 1000
  • save 选项在 redis.conf 中是用多行文字储存的,但在 CONFIG GET命令中,它只打印一行文字。

例如,redis.conf 里面的有如下配置:

1
2
save 900 1
save 300 10

它的意思是:如果900秒内有一个数据发生变化,或者300秒内有10个数据发生变化则执行 SAVE ,那么使用 CONFIG GET查看时将会看到 “900 1 300 10”。

  • 语法:

    1
    127.0.0.1:6379> CONFIG GET parameter
  • 返回值:

    数组: 给定配置参数的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> config get *max-*-entries* 
    1) "hash-max-ziplist-entries"
    2) "512"
    3) "set-max-intset-entries"
    4) "512"
    5) "zset-max-ziplist-entries"
    6) "128"
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.11.15 CONFIG REWRITE

Redis CONFIG REWRITE 命令对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写。
CONFIG SET 命令可以对服务器的当前配置进行修改, 而修改后的配置可能和 redis.conf 文件中所描述的配置不一样, CONFIG REWRITE 的作用就是通过尽可能少的修改, 将服务器当前所使用的配置记录到 redis.conf 文件中。

  1. 重写以非常保守的方式执行

    • 注释和原始 redis.conf 文件的整体结构会尽可能的保留下来。
    • 如果一个选项在旧的 redis.conf 文件中已经存在,那么它会在相同的位置(行号)被重写。
    • 如果某个选项在配置文件中尚不存在,但被设置为了该选项的默认值,那么他将不会被重写进程写入配置文件。
    • 如果某个选项在配置文件中尚不存在,但被设置了一个非默认值,那么它会被追加到文件的末尾。
    • 未使用的行将会留空。例如,如果你之前在配置文件中有多个 save 配置项,但由于你禁用了 RDB 持久化,当前的 save 配置变少了或者变为空,那么所有的那些行将会是空行。

    如果原始文件由于某些原因不再存在,CONFIG REWRITE 也能够从头开始重写配置文件。但是,如果服务器启动的时候没有指定任何配置文件,则 CONFIG REWRITE 将只会返回一个错误。

  2. 原子重写过程

    为了保证redis.conf文件始终是一致的,也即,在异常或者崩溃的时候,你的配置文件要么是旧的文件,或者是重写完的新文件。重写是通过一次具有足够内容的write(2)调用来执行的,至少和旧的文件一样大。有时会以注释的形式添加额外的padding,以确保生成的文件足够大,稍后文件会被截断以删除末尾的padding。

  • 语法:

    1
    127.0.0.1:6379> CONFIG REWRITE parameter
  • 返回值:

    字符串: 当配置被正确重写时返回OK,否则返回错误。

  • 实例:

    以下是执行 CONFIG REWRITE 前, 被载入到 Redis 服务器的 redis.conf 文件中关于 appendonly 选项的设置:

    1
    2
    3
    4
    5
    # ... 其他选项

    appendonly no

    # ... 其他选项

    在执行以下命令之后:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> CONFIG GET appendonly       # appendonly 处于关闭状态
    1) "appendonly"
    2) "no"
    127.0.0.1:6379> CONFIG SET appendonly yes # 打开 appendonly
    OK
    127.0.0.1:6379> CONFIG GET appendonly
    1) "appendonly"
    2) "yes"
    127.0.0.1:6379> CONFIG REWRITE # 将 appendonly 的修改写入到 redis.conf 中
    OK
    127.0.0.1:6379>

    重写后的 redis.conf 文件中的 appendonly 选项将被改写:

    1
    2
    3
    4
    5
    # ... 其他选项

    appendonly yes

    # ... 其他选项

可用版本>= 2.8.0.

1.11.16 CONFIG SET

CONFIG SET 命令用于在服务器运行期间重写某些配置,而不用重启 Redis。可以使用此命令更改不重要的参数或从一个参数切换到另一个持久性选项。

可以通过 CONFIG GET * 获得CONFIG SET命令支持的配置参数列表,该命令是用于获取有关正在运行的 Redis 实例的配置信息的对称命令。

所有使用CONFIG SET设置的配置参数将会立即被 Redis 加载,并从下一个执行的命令开始生效。

所有支持的参数与 [redis.conf][hgcarr22rc] 文件中使用的等效配置参数具有相同含义,但有以下重要区别:

  • 在指定字节或其他数量的选项中,不能使用在redis.conf中使用的简写形式(如10k2gb等),所有内容都应该指定为格式良好的64位整数,以配置指令的基本单位表示。但从Redis3.0以及更高版本开始,可以将CONFIG SET与内存单元一起用于maxmemory、客户端输出缓冲以及复制积压大小(repl-backlog-size)指定内存单位。
  • save参数是一个以空格分隔的整数字符串。每对整数代表一个秒/修改阈值。

例如在 redis.conf 中看起来像这样:

1
2
save 900 1
save 300 10

这意味着,如果数据集有 1 个以上变更,则在 900 秒后保存;如果有 10 个以上变更,则在 300 秒后就保存,应使用CONFIG SET SAVE “900 1 300 10” 来设置。

可以使用CONFIG SET命令将持久化从 RDB 快照切换到 AOF 文件(或其他相似的方式)。 有关如何执行此操作的详细信息,请查看persistencepage

一般来说,你应该知道将 appendonly 参数设置为 yes 将启动后台进程以保存初始 AOF 文件(从内存数据集中获取),并将所有后续命令追加到 AOF 文件,从而达到了与一个 Redis 服务器从一开始就开启了 AOF 选项相同的效果。

如果你愿意,可以同时开启 AOF 和 RDB 快照,这两个选项不是互斥的。

  • 语法:

    1
    127.0.0.1:6379> CONFIG Set parameter value
  • 返回值:

    字符串: 当配置被正确设置时返回OK,否则将返回错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> CONFIG GET slowlog-max-len
    1) "slowlog-max-len"
    2) "128"
    127.0.0.1:6379> CONFIG SET slowlog-max-len 10086
    OK
    127.0.0.1:6379> CONFIG GET slowlog-max-len
    1) "slowlog-max-len"
    2) "10086"
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.11.17 CONFIG RESETSTAT

Redis CONFIG RESETSTAT 命令用于重置 INFO 命令中的某些统计数据,包括:

1
2
3
4
5
6
7
8
- Keyspace hits (键空间命中次数)
- Keyspace misses (键空间不命中次数)
- Number of commands processed (执行命令的次数)
- Number of connections received (连接服务器的次数)
- Number of expired keys (过期key的数量)
- Number of rejected connections (被拒绝的连接数量)
- Latest fork(2) time(最后执行 fork(2) 的时间)
- The aof_delayed_fsync counter(aof_delayed_fsync 计数器的值)
  • 语法:

    1
    127.0.0.1:6379> CONFIG RESETSTAT
  • 返回值:

    字符串: OK.

  • 实例:

    重置前 INFO 命令输出信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:17277
    process_supervised:no
    run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
    tcp_port:6379
    server_time_usec:1653069721652249
    uptime_in_seconds:128889
    uptime_in_days:1
    hz:10
    configured_hz:10
    lru_clock:8902553
    executable:/opt/software/redis-6.2.6/./src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:0
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:879352
    used_memory_human:858.74K
    used_memory_rss:3055616
    used_memory_rss_human:2.91M
    used_memory_peak:977792
    used_memory_peak_human:954.88K
    used_memory_peak_perc:89.93%
    used_memory_overhead:811872
    used_memory_startup:810112
    used_memory_dataset:67480
    used_memory_dataset_perc:97.46%
    allocator_allocated:988920
    allocator_active:1265664
    allocator_resident:3502080
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:43008
    used_memory_lua_human:42.00K
    used_memory_scripts:248
    used_memory_scripts_human:248B
    number_of_cached_scripts:2
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.28
    allocator_frag_bytes:276744
    allocator_rss_ratio:2.77
    allocator_rss_bytes:2236416
    rss_overhead_ratio:0.87
    rss_overhead_bytes:-446464
    mem_fragmentation_ratio:3.75
    mem_fragmentation_bytes:2239976
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:0
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653062505
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:475136
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:561152
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:95
    total_commands_processed:933
    instantaneous_ops_per_sec:0
    total_net_input_bytes:36763
    total_net_output_bytes:432050
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:6902
    evicted_keys:0
    keyspace_hits:194
    keyspace_misses:13
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:668
    total_forks:76
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:84
    dump_payload_sanitizations:0
    total_reads_processed:944
    total_writes_processed:931
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:250.581855
    used_cpu_user:278.320178
    used_cpu_sys_children:0.452773
    used_cpu_user_children:0.073380
    used_cpu_sys_main_thread:250.516158
    used_cpu_user_main_thread:278.278268

    # Modules

    # Errorstats
    errorstat_ERR:count=51
    errorstat_NOAUTH:count=13
    errorstat_NOTBUSY:count=3
    errorstat_WRONGPASS:count=4
    errorstat_WRONGTYPE:count=13

    # Cluster
    cluster_enabled:0

    # Keyspace
    db0:keys=21,expires=0,avg_ttl=0
    db1:keys=5,expires=0,avg_ttl=0
    db2:keys=3,expires=0,avg_ttl=0

    重置后查看 INFO 命令输出信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    # 重置操作
    127.0.0.1:6379> CONFIG RESETSTAT
    OK
    # 重置后查看 INFO 命令输出信息:
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:17277
    process_supervised:no
    run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
    tcp_port:6379
    server_time_usec:1653069741529106
    uptime_in_seconds:128909
    uptime_in_days:1
    hz:10
    configured_hz:10
    lru_clock:8902573
    executable:/opt/software/redis-6.2.6/./src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:24
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:879048
    used_memory_human:858.45K
    used_memory_rss:3051520
    used_memory_rss_human:2.91M
    used_memory_peak:977792
    used_memory_peak_human:954.88K
    used_memory_peak_perc:89.90%
    used_memory_overhead:832376
    used_memory_startup:810112
    used_memory_dataset:46672
    used_memory_dataset_perc:67.70%
    allocator_allocated:1026488
    allocator_active:1343488
    allocator_resident:3624960
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:43008
    used_memory_lua_human:42.00K
    used_memory_scripts:248
    used_memory_scripts_human:248B
    number_of_cached_scripts:2
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.31
    allocator_frag_bytes:317000
    allocator_rss_ratio:2.70
    allocator_rss_bytes:2281472
    rss_overhead_ratio:0.84
    rss_overhead_bytes:-573440
    mem_fragmentation_ratio:3.65
    mem_fragmentation_bytes:2215232
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:20504
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653062505
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:475136
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:561152
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:0
    total_commands_processed:1
    instantaneous_ops_per_sec:0
    total_net_input_bytes:14
    total_net_output_bytes:5
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:0
    evicted_keys:0
    keyspace_hits:0
    keyspace_misses:0
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:0
    total_forks:0
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:0
    dump_payload_sanitizations:0
    total_reads_processed:1
    total_writes_processed:1
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:250.620934
    used_cpu_user:278.359987
    used_cpu_sys_children:0.452773
    used_cpu_user_children:0.073380
    used_cpu_sys_main_thread:250.556253
    used_cpu_user_main_thread:278.316859

    # Modules

    # Errorstats

    # Cluster
    cluster_enabled:0

    # Keyspace
    db0:keys=21,expires=0,avg_ttl=0
    db1:keys=5,expires=0,avg_ttl=0
    db2:keys=3,expires=0,avg_ttl=0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.11.18 DBSIZE

Redis DBSIZE 返回当前数据库中 key 的数量。

  • 语法:

    1
    127.0.0.1:6379> DBSIZE
  • 返回值:

    整数:当前数据库中 key 的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> DBSIZE
    (integer) 21
    # 增加一个key,再看看效果
    127.0.0.1:6379> SET new_key "hello kungs"
    OK
    127.0.0.1:6379> DBSIZE
    (integer) 22
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.19 DEBUG OBJECT

Redis DEBUG OBJECT 是一个调试命令,它不应该被客户端所使用。
查看 OBJECT 命令获取更多信息。

  • 语法:

    1
    127.0.0.1:6379> DEBUG OBJECT key
  • 返回值:

    字符串: 当 key 存在时,返回有关信息。 当 key 不存在时,返回 (error) ERR no such key。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SET new_key "hello kungs"
    OK
    127.0.0.1:6379> DEBUG OBJECT new_key
    Value at:0x7fceb660e9e0 refcount:1 encoding:embstr serializedlength:12 lru:8902992 lru_seconds_idle:4
    127.0.0.1:6379> DEBUG OBJECT new_key1
    (error) ERR no such key
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.20 DEBUG SEGFAULT

DEBUG SEGFAULT 执行一个不合法的内存访问从而让 Redis 崩溃,仅在开发时用于模拟 BUG 。

  • 语法:

    1
    127.0.0.1:6379> DEBUG SEGFAULT
  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    127.0.0.1:6379> DEBUG SEGFAULT
    Error: Server closed the connection
    (0.69s)
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.21 FLUSHALL

清空整个 Redis 中的数据(清空所有数据库的所有 key,不仅仅是当前 select 的数据库 )。

此命令不会失败。

FLUSHALL ASYNC (Redis 4.0.0 or greater)

支持在后台单独的线程执行删除 key 的操作而不阻塞 Redis。

FLUSHALLFLUSHDB 增加了ASYNC 来使整个数据集或单个数据库异步释放。

异步FLUSHALLFLUSHDB 命令仅仅删除它们被调用时已经存在的 key。命令调用之后,删除 key 的过程中新建的 key 不受影响。

  • 语法:

    1
    127.0.0.1:6379> FLUSHALL
  • 返回值:

    字符串: OK

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 0 号数据库的 key 数量
    127.0.0.1:6379> DBSIZE
    (integer) 22
    # 切换到 1 号数据库
    127.0.0.1:6379> SELECT 1
    OK
    # 1 号数据库的 key 数量
    127.0.0.1:6379[1]> DBSIZE
    (integer) 5
    # 清空所有数据库的所有 key
    127.0.0.1:6379[1]> FLUSHALL
    OK
    # 不但 1 号数据库被清空了
    127.0.0.1:6379[1]> DBSIZE
    (integer) 0
    # 0 号数据库(以及其他所有数据库)也一样
    127.0.0.1:6379[1]> SELECT 0
    OK
    127.0.0.1:6379> DBSIZE
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度是 O(N), N 代表所有数据库中 key 的总数。

1.11.22 FLUSHDB

清空当前 select 数据库中的所有 key。此命令不会失败。

  • 语法:

    1
    127.0.0.1:6379> FLUSHDB
  • 返回值:

    字符串: OK

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    # 清空前的 key 数量
    127.0.0.1:6379> DBSIZE
    (integer) 4
    127.0.0.1:6379> FLUSHDB
    OK
    # 清空后的 key 数量
    redis 127.0.0.1:6379> DBSIZE
    (integer) 0

可用版本>= 1.0.0.

时间复杂度是 O(N), N 代表当前数据库中 key 的总数。

1.11.23 INFO

INFO命令以一种易于理解和阅读的格式,返回关于Redis服务器的各种信息和统计数值。

通过给定可选的参数 section ,可以让命令只返回某一部分的信息:

  • server: 查看 Redis 服务器信息,如 Redis 的版本
  • clients: 客户端的连接部分
  • memory: 内存消耗相关信息
  • persistence: RDB和AOF相关信息
  • stats: 一般统计
  • replication: 主/从复制信息
  • cpu: 统计CPU的消耗
  • commandstats: Redis命令统计
  • cluster: Redis集群信息
  • keyspace: 数据库的相关统计
  • modules: Module 相关信息

它也可以采取以下值:

  • all: 返回所有信息
  • default: 值返回默认设置的信息
  • everything: 包括 allmodules

如果没有使用任何参数时,默认为default

注意:

请注意不同Redis版本会添加或者删除一些字段。一个健壮的客户端应用解析该命令的结果时,应该跳过未知的字段,并且优雅的处理缺少的字段。

以下是Redis >= 2.4的字段说明。

下面是所有 server 相关的信息:

  • redis_version: Redis 服务器版本
  • redis_git_sha1: Git SHA1
  • redis_git_dirty: Git dirty flag
  • redis_build_id: 构建ID
  • redis_mode: 服务器模式(standalone,sentinel或者cluster)
  • os: Redis 服务器的宿主操作系统
  • arch_bits: 架构(32 或 64 位)
  • multiplexing_api: Redis 所使用的事件处理机制
  • atomicvar_api: Redis使用的Atomicvar API
  • gcc_version: 编译 Redis 时所使用的 GCC 版本
  • process_id: 服务器进程的 PID
  • run_id: Redis 服务器的随机标识符(用于 Sentinel 和集群)
  • tcp_port: TCP/IP 监听端口
  • uptime_in_seconds: 自 Redis 服务器启动以来,经过的秒数
  • uptime_in_days: 自 Redis 服务器启动以来,经过的天数
  • hz: 服务器的频率设置
  • lru_clock: 以分钟为单位进行自增的时钟,用于 LRU 管理
  • executable: 服务器的可执行文件路径
  • config_file: 配置文件路径

下面是所有 clients 相关的信息:

  • connected_clients: 已连接客户端的数量(不包括通过从属服务器连接的客户端)
  • client_longest_output_list: 当前连接的客户端当中,最长的输出列表
  • client_biggest_input_buf: 当前连接的客户端当中,最大输入缓存
  • blocked_clients: 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量

下面是所有 memory 相关的信息:

  • 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_peak_perc: 使用内存占峰值内存的百分比
  • used_memory_overhead: 服务器为管理其内部数据结构而分配的所有开销的总和(以字节为单位)
  • used_memory_startup: Redis在启动时消耗的初始内存大小(以字节为单位)
  • used_memory_dataset: 以字节为单位的数据集大小(usedmemory减去usedmemory_overhead)
  • used_memory_dataset_perc: usedmemorydataset占净内存使用量的百分比(usedmemory减去usedmemory_startup)
  • total_system_memory: Redis主机具有的内存总量
  • total_system_memory_human: 以人类可读的格式返回 Redis主机具有的内存总量
  • used_memory_lua: Lua 引擎所使用的内存大小(以字节为单位)
  • used_memory_lua_human: 以人类可读的格式返回 Lua 引擎所使用的内存大小
  • maxmemory: maxmemory配置指令的值
  • maxmemory_human: 以人类可读的格式返回 maxmemory配置指令的值
  • maxmemory_policy: maxmemory-policy配置指令的值
  • mem_fragmentation_ratio: used_memory_rssused_memory之间的比率
  • mem_allocator: 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。
  • active_defrag_running: 指示活动碎片整理是否处于活动状态的标志
  • lazyfree_pending_objects: 等待释放的对象数(由于使用ASYNC选项调用UNLINK或FLUSHDB和FLUSHALL)

在理想情况下, usedmemoryrss 的值应该只比 used_memory 稍微高一点儿。

当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。

内存碎片的比率可以通过 memfragmentationratio 的值看出。

当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。

由于Redis无法控制其分配的内存如何映射到内存页,因此常住内存(usedmemoryrss)很高通常是内存使用量激增的结果。

当 Redis 释放内存时,内存将返回给分配器,分配器可能会,也可能不会,将内存返还给操作系统。

如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致。

查看 usedmemorypeak 的值可以验证这种情况是否发生。

要获得有关服务器内存的其他内省信息,可以参考MEMORY STATSMEMORY DOCTOR

下面是所有 persistence 相关的信息:

  • loading: 指示转储文件(dump)的加载是否正在进行的标志
  • rdb_changes_since_last_save: 自上次转储以来的更改次数
  • rdb_bgsave_in_progress: 指示RDB文件是否正在保存的标志
  • rdb_last_save_time: 上次成功保存RDB的基于纪年的时间戳
  • rdb_last_bgsave_status: 上次RDB保存操作的状态
  • rdb_last_bgsave_time_sec: 上次RDB保存操作的持续时间(以秒为单位)
  • rdb_current_bgsave_time_sec: 正在进行的RDB保存操作的持续时间(如果有)
  • rdb_last_cow_size: 上次RDB保存操作期间copy-on-write分配的字节大小
  • aof_enabled: 表示AOF记录已激活的标志
  • aof_rewrite_in_progress: 表示AOF重写操作正在进行的标志
  • aof_rewrite_scheduled: 表示一旦进行中的RDB保存操作完成,就会安排进行AOF重写操作的标志
  • aof_last_rewrite_time_sec: 上次AOF重写操作的持续时间,以秒为单位
  • aof_current_rewrite_time_sec: 正在进行的AOF重写操作的持续时间(如果有)
  • aof_last_bgrewrite_status: 上次AOF重写操作的状态
  • aof_last_write_status: 上一次AOF写入操作的状态
  • aof_last_cow_size: 上次AOF重写操作期间copy-on-write分配的字节大小

changes_since_last_save指的是从上次调用SAVE或者BGSAVE以来,在数据集中产生某种变化的操作的数量。

如果启用了AOF,则会添加以下这些额外的字段:

  • aof_current_size: 当前的AOF文件大小
  • aof_base_size: 上次启动或重写时的AOF文件大小
  • aof_pending_rewrite: 指示AOF重写操作是否会在当前RDB保存操作完成后立即执行的标志。
  • aof_buffer_length: AOF缓冲区大小
  • aof_rewrite_buffer_length: AOF重写缓冲区大小
  • aof_pending_bio_fsync: 在后台IO队列中等待fsync处理的任务数
  • aof_delayed_fsync: 延迟fsync计数器

如果正在执行加载操作,将会添加这些额外的字段:

  • loading_start_time: 加载操作的开始时间(基于纪元的时间戳)
  • loading_total_bytes: 文件总大小
  • loading_loaded_bytes: 已经加载的字节数
  • loading_loaded_perc: 已经加载的百分比
  • loading_eta_seconds: 预计加载完成所需的剩余秒数

下面是所有 stats 相关的信息:

  • total_connections_received: 服务器接受的连接总数
  • total_commands_processed: 服务器处理的命令总数
  • instantaneous_ops_per_sec: 每秒处理的命令数
  • rejected_connections: 由于maxclients限制而拒绝的连接数
  • expired_keys: key到期事件的总数
  • evicted_keys: 由于maxmemory限制而导致被驱逐的key的数量
  • keyspace_hits: 在主字典中成功查找到key的次数
  • keyspace_misses: 在主字典中查找key失败的次数
  • pubsub_channels: 拥有客户端订阅的全局pub/sub通道数
  • pubsub_patterns: 拥有客户端订阅的全局pub/sub模式数
  • latest_fork_usec: 最新fork操作的持续时间,以微秒为单位

下面是所有 replication 相关的信息:

  • role: 如果实例不是任何节点的从节点,则值是”master”,如果实例从某个节点同步数据,则是”slave”。 请注意,一个从节点可以是另一个从节点的主节点(菊花链)。

如果实例是从节点,则会提供以下这些额外字段:

  • master_host: 主节点的Host名称或IP地址
  • master_port: 主节点监听的TCP端口
  • master_link_status: 连接状态(up或者down)
  • master_last_io_seconds_ago: 自上次与主节点交互以来,经过的秒数
  • master_sync_in_progress: 指示主节点正在与从节点同步

如果SYNC操作正在进行,则会提供以下这些字段:

  • master_sync_left_bytes: 同步完成前剩余的字节数
  • master_sync_last_io_seconds_ago: 在SYNC操作期间自上次传输IO以来的秒数

如果主从节点之间的连接断开了,则会提供一个额外的字段:

  • master_link_down_since_seconds: 自连接断开以来,经过的秒数

以下字段将始终提供:

  • connected_slaves: 已连接的从节点数

对每个从节点,将会添加以下行:

  • slaveXXX: id,地址,端口号,状态

下面是所有 cpu 相关的信息:

  • used_cpu_sys: 由Redis服务器消耗的系统CPU
  • used_cpu_user: 由Redis服务器消耗的用户CPU
  • used_cpu_sys_children: 由后台进程消耗的系统CPU
  • used_cpu_user_children: 由后台进程消耗的用户CPU

commandstats部分提供基于命令类型的统计,包含调用次数,这些命令消耗的总CPU时间,以及每个命令执行所消耗的平均CPU。

对于每一个命令类型,添加以下行:

  • cmdstat_XXX: calls=XXX,usec=XXX,usec_per_call=XXX

cluster部分当前只包含一个唯一的字段:

  • cluster_enabled: 表示已启用Redis集群

keyspace部分提供有关每个数据库的主字典的统计,统计信息是key的总数和带有过期key的总数。

对于每个数据库,提供以下行:

  • dbXXX: keys=XXX,expires=XXX
  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    多行字符串: 文本行的合集

    每一行包含了包含一种信息或者属性(从#字符开始)。 所有的属性都是以字段:值(field:value)的形式,以\r\n结尾。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:19069
    process_supervised:no
    run_id:94c6005986e59722cbf438a37cf5513236a5d841
    tcp_port:6379
    server_time_usec:1653071002486948
    uptime_in_seconds:449
    uptime_in_days:0
    hz:10
    configured_hz:10
    lru_clock:8903834
    executable:/opt/software/redis-6.2.6/src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:0
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:873840
    used_memory_human:853.36K
    used_memory_rss:3063808
    used_memory_rss_human:2.92M
    used_memory_peak:935096
    used_memory_peak_human:913.18K
    used_memory_peak_perc:93.45%
    used_memory_overhead:810112
    used_memory_startup:810112
    used_memory_dataset:63728
    used_memory_dataset_perc:100.00%
    allocator_allocated:1032136
    allocator_active:1355776
    allocator_resident:3592192
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:37888
    used_memory_lua_human:37.00K
    used_memory_scripts:0
    used_memory_scripts_human:0B
    number_of_cached_scripts:0
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.31
    allocator_frag_bytes:323640
    allocator_rss_ratio:2.65
    allocator_rss_bytes:2236416
    rss_overhead_ratio:0.85
    rss_overhead_bytes:-528384
    mem_fragmentation_ratio:3.78
    mem_fragmentation_bytes:2253680
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:0
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653070888
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:180224
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:-1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:0
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:2
    total_commands_processed:11
    instantaneous_ops_per_sec:0
    total_net_input_bytes:237
    total_net_output_bytes:20373
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:21
    evicted_keys:0
    keyspace_hits:0
    keyspace_misses:0
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:245
    total_forks:1
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:0
    dump_payload_sanitizations:0
    total_reads_processed:12
    total_writes_processed:11
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:6a79d6f2d97cb3525136444bb32aae6dd41d07e1
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:1.938793
    used_cpu_user:1.406728
    used_cpu_sys_children:0.002974
    used_cpu_user_children:0.000991
    used_cpu_sys_main_thread:1.937100
    used_cpu_user_main_thread:1.407383

    # Modules

    # Errorstats

    # Cluster
    cluster_enabled:0

    # Keyspace
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.24 LASTSAVE

以 UNIX 时间戳格式返回最近一次 Redis 成功将数据保存到磁盘上的时间。

LASTSAVE 通常被用来检查 BGSAVE 命令是否执行完成。通常是每隔几秒钟看一下 LASTSAVE 的是是否有变化。

  • 语法:

    1
    127.0.0.1:6379> LASTSAVE
  • 返回值:

    整数: 一个 UNIX 时间戳。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> LASTSAVE
    (integer) 1653070888
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.25 MONITOR

Redis MONITOR 命令用于实时打印出 Redis 服务器接收到的命令,调试用。

MONITOR 用来帮助我们知道数库正在做什么。可以通过 redis-clitelnet 调用 MONITOR

当 Redis 用做数据库或者分布式缓存时,MONITOR 可以帮助我们发现程序中的 bug 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost redis-6.2.6]# ./src/redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> set x 6
OK
127.0.0.1:6379> get x
"6"
127.0.0.1:6379> del x
(integer) 1
127.0.0.1:6379> GET x
(nil)
127.0.0.1:6379> QUIT
[root@localhost redis-6.2.6]#

通过 redis-cli 运行 MONITOR 时,可以发送 SIGINT (Ctrl+C) 信号来停止退出。

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> MONITOR
OK
+1339518083.107412 [0 127.0.0.1:60866] "keys" "*"
+1339518087.877697 [0 127.0.0.1:60866] "dbsize"
+1339518090.420270 [0 127.0.0.1:60866] "set" "x" "6"
+1339518096.506257 [0 127.0.0.1:60866] "get" "x"
+1339518099.363765 [0 127.0.0.1:60866] "del" "x"
+1339518100.544926 [0 127.0.0.1:60866] "get" "x"
QUIT
+OK
Connection closed by foreign host.

通过 telnet 运行 MONITOR 时,可以发送 QUIT来停止退出。

  1. MONITOR 不记录的命令:

    处于安全方面的考虑,所有的管理相关的命令不会记录到 MONITOR的输出者。

    下面几个命令也不会记录:

    • AUTH
    • EXEC
    • HELLO
    • QUIT
  2. MONITOR 的消耗:

    因为 MONITOR流返回所有命令,所以用起来会有一定的消耗。 下面是一个基准测试对比:

    不带 MONITOR命令:

    1
    2
    3
    4
    5
    6
    $ src/redis-benchmark -c 10 -n 100000 -q
    PING_INLINE: 101936.80 requests per second
    PING_BULK: 102880.66 requests per second
    SET: 95419.85 requests per second
    GET: 104275.29 requests per second
    INCR: 93283.58 requests per second

    MONITOR命令 (redis-cli monitor > /dev/null):

    1
    2
    3
    4
    5
    6
    $ src/redis-benchmark -c 10 -n 100000 -q
    PING_INLINE: 58479.53 requests per second
    PING_BULK: 59136.61 requests per second
    SET: 41823.50 requests per second
    GET: 45330.91 requests per second
    INCR: 41771.09 requests per second

    通过上面的例子可以看到运行一个 MONITOR命令降低了超过 50% 的吞吐量。 运行多个 MONITOR会进一步降低性能。

  • 语法:

    1
    127.0.0.1:6379> MONITOR
  • 返回值:

    输出Redis服务器处理的指令流直到退出。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> MONITOR
    OK
    +1339518083.107412 [0 127.0.0.1:60866] "keys" "*"
    +1339518087.877697 [0 127.0.0.1:60866] "dbsize"
    +1339518090.420270 [0 127.0.0.1:60866] "set" "x" "6"
    +1339518096.506257 [0 127.0.0.1:60866] "get" "x"
    +1339518099.363765 [0 127.0.0.1:60866] "del" "x"
    +1339518100.544926 [0 127.0.0.1:60866] "get" "x"

可用版本>= 1.0.0.

1.11.26 ROLE

Redis ROLE 命令返回实例在复制中担任的角色, 这个角色可以是 masterslave 或者 sentinel

除了角色之外, 命令还会返回与该角色相关的其他信息, 其中:

  • 主服务器将返回属下从服务器的 IP 地址和端口。
  • 从服务器将返回自己正在复制的主服务器的 IP 地址、端口、连接状态以及复制偏移量。
  • Sentinel 将返回自己正在监视的主服务器列表。
  • 语法:

    1
    127.0.0.1:6379> ROLE
  • 返回值:

    数组:第一个参数是 master, slave, sentinel 三个中的一个。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> ROLE
    1) "master"
    2) (integer) 0
    3) (empty array)
    127.0.0.1:6379>

可用版本>= 2.8.12.

1.11.27 SAVE

Redis SAVE 命令用于执行同步保存操作,把 Redis 实例中某一时点的所有数据的快照以 RDB 文件的形式保存到磁盘上。

生产环境不要执行 SAVE 命令,因为这会阻塞所有其它的客户端。

可以使用 BGSAVE 代替。尽管如此,BGSAVE 也有执行失败的危险,SAVE 是转存最新数据集的最好也是最后一个方法。

详细参考 persistence documentation

  • 语法:

    1
    127.0.0.1:6379> SAVE
  • 返回值:

    字符串: 成功时返回 “OK”。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SAVE 
    OK
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.28 SHUTDOWN

SHUTDOWN 命令执行如下操作:

1
2
3
4
- 停止所有客户端
- 如果配置了save 策略 则执行一个阻塞的save命令
- 如果开启了AOF,则刷新aof文件
- 关闭redis服务进程(redis-server)

如果配置了持久化策略,那么这个命令将能够保证在关闭redis服务进程的时候数据不会丢失。

如果仅仅在客户端执行 QUIT 命令,然后 执行 QUIT 命令,那么数据的完整性将不会被保证,因为其他客户端可能在执行这两个命令的期间修改数据库的数据。

注意: 一个没有配置持久化策略的redis实例 (没有aof配置, 没有 “save” 命令) 将不会在执行SHUTDOWN命令的时候转存一个rdb文件,可以提高关闭的速度,例如仅用来做缓存的 redis 不需要配置持久化转存。

  1. SAVE 和 NOSAVE 修饰符

    通过指定一个可选的修饰符可以改变这个命令的表现形式,比如:

    • SHUTDOWN SAVE 能够在即使没有配置持久化的情况下强制数据库存储。
    • SHUTDOWN NOSAVE 能够在配置一个或者多个持久化策略的情况下阻止数据库存储. (你可以假想它为一个中断服务的 ABORT 命令)。
  2. SHUTDOWN 关闭失败的情况

    当配置了 AOF 时,shutdown 可能会失败由于系统处于不允许立刻执行磁盘持久化操纵。

    当有一个AOF的子进程在执行AOF重写时,Redis 会简单的kill 该子进程。有两种列外的情况,SHUTDOWN 会返回失败:

    • AOF 刚刚打开,首次进行 AOF rewrite 创建初始的 AOF 文件。这种情况下停止redis将会丢失所有数据:一旦停止 redis时,虽然开启了AOF,但是还没有创建任何AOF文件。
    • 复制节点打开了 AOF,向 master 发起重连,执行数据全同步,然后重起AOF,创建初始AOF文件。可能会丢失复制自master节点的数据。

    如果我们只是想立刻关闭redis,而不管其它情况。正确的做法是先发送CONFIG appendonly no ,然后执行SHUTDOWN NOSAVE.。前一个命令关闭 AOF(如果打开AOF),终止可能存在的 AOF 重写子进程,这样后一个命令关闭不会失败。

  • 语法:

    1
    127.0.0.1:6379> SHUTDOWN [NOSAVE] [SAVE] 
  • 返回值:

    字符串: 当发生错误的时候返回状态码 . 当成功的时候不返回任何值,因为服务退出,链接关闭。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> PING
    Error: Server closed the connection
    127.0.0.1:6379> PING
    PONG
    127.0.0.1:6379> SHUTDOWN
    not connected> redis
    Could not connect to Redis at 127.0.0.1:6379: Connection refused
    not connected>

可用版本>= 1.0.0.

1.11.29 SLAVEOF

Redis SLAVEOF 命令可以将当前服务器转变为指定服务器的从属服务器(slave server)。

注意: 从 Redis 5 起使用 REPLICAOF 替代 SLAVEOF。当然,为了向后兼容 SLAVEOF 命令仍然可用。

SLAVEOF 命令可以临时修改从节点的复制配置。如果当前服务器已经是某个主服务器(master server)的从属服务器,SLAVEOF NO ONE 命令会停止复制,把节点改为主节点。

SLAVEOF hostname port 可以使正在复制其它节点的 Redis 改为复制新的 hostname 和 port。

SLAVEOF hostname port 将会停止从旧的主节点复制,丢弃已经同步的旧的数据,并开始从新的节点同步数据。

SLAVEOF NO ONE 用来停止复制,把从节点改为主节点,但是不会丢弃已复制的数据。所以,当 Master 主节点出现问题时,可以把从节点变成 Master 主节点,使应用读/写新的主节点。当原来的主节点修复之后,可以把新的 Master 节点重新配置为从节点。

利用『 SLAVEOF NO ONE 不会丢弃同步所得数据集』这个特性,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行。

  • 语法:

    1
    127.0.0.1:6379> SLAVEOF host port
  • 返回值:

    字符串:总是返回 OK 。

  • 实例:

    1
    2
    3
    4
    127.0.0.1:6379> SLAVEOF 127.0.0.1 6379
    OK
    127.0.0.1:6379> SLAVEOF NO ONE
    OK

可用版本>= 1.0.0.

1.11.30 SLOWLOG

Redis slowlog 是 Redis 用来记录查询执行时间的日志系统。

查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间。

另外,slow log 保存在内存里面,读写速度非常快,因此你可以放心地使用它,不必担心因为开启 slow log 而损害 Redis 的速度。

  1. 读取 slow log

    慢日志记录在内存中,不会写到文件上。所以即使记录所有执行的命令到慢日志中性能开销也很小。

    读取慢日志命令:

    SLOWLOG GET 返回每一条慢日志。

    SLOWLOG GET n 返回最新的n条慢日志。

    注意:请使用新版 redis-cli 以便能解析慢日志输出,较老版本的 redis-cli 不支持多行嵌套。

  2. 响应输出格式

    1. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      redis 127.0.0.1:6379> slowlog get 2
      1) 1) (integer) 14
      2) (integer) 1309448221
      3) (integer) 15
      4) 1) "ping"
      2) 1) (integer) 13
      2) (integer) 1309448128
      3) (integer) 30
      4) 1) "slowlog"
      2) "get"
      3) "100"

    Redis 4.0 及之后版本新增域:

    1
    2
    5) "127.0.0.1:58217"
    6) "worker-123"

    每条慢日志由 4 或 6 部分组成:

    • 每条慢日志有一个递增的唯一 ID。
    • 记录慢日志的 Unix 时间戳。
    • 执行这个命令花费的时间,单位是微妙。
    • 数组形式的命令参数。
    • 客户端 ip 和端口 (4.0 only)。
    • 通过 CLIENT SETNAME 命令设置的客户端名字 (4.0 only)。

    可以用唯一 ID 来避免慢日志被处理多次(例如你有一个每当产生新的慢日志发送报警的脚本)。

    ID 在 Redis 运行期间不会重置,Redis 重启之后会重置 ID。

  3. 查询当前 slowlog 的长度

    SLOWLOG LEN 获取 slow log 的长度。

  4. 重置 slow log

    SLOWLOG RESET 命令用来重置 slowlog。一旦删除 slowlog 不可恢复。

  • 语法:

    1
    127.0.0.1:6379> SLOWLOG subcommand [argument]
  • 返回值:

    取决于不同命令,返回不同的值。

  • 实例:

    查看日志信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> slowlog get 2
    1) 1) (integer) 14
    2) (integer) 1309448221
    3) (integer) 15
    4) 1) "ping"
    2) 1) (integer) 13
    2) (integer) 1309448128
    3) (integer) 30
    4) 1) "slowlog"
    2) "get"
    3) "100"

    查看当前日志的数量:

    1
    2
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 14

    使用命令 SLOWLOG RESET 可以清空 slow log 。

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 14
    127.0.0.1:6379> SLOWLOG RESET
    OK
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 0

可用版本>= 2.2.12.

1.11.31 SYNC

从主服务节点初始化流复制。

Redis 从节点调用 SYNC 来从主节点启动流复制。在 redis 新版本中已经被 PSYNC 代替。

更多信息可以参考 Redis 复制

  • 语法:

    1
    127.0.0.1:6379> SYNC
  • 返回值:

    非标准数据, bulk 数据 + PING + 来自master的写请求。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SYNC
    Entering replica output mode... (press Ctrl-C to quit)
    SYNC with master, discarding 175 bytes of bulk transfer...
    SYNC done. Logging commands from master.
    "ping"
    "ping"

可用版本>= 1.0.0.

1.12 Redis HyperLogLog

1.12.1 PFADD

Redis Pfadd 命令将所有元素参数添加到 HyperLogLog 数据结构中。

作为这个命令的副作用, HyperLogLog 内部可能会被更新, 以便反映一个不同的唯一元素估计数量(也即是集合的基数)。

如果 HyperLogLog 估计的近似基数(approximated cardinality)在命令执行之后出现了变化, 那么命令返回 1 , 否则返回 0 。 如果命令执行时给定的键不存在, 那么程序将先创建一个空的 HyperLogLog 结构, 然后再执行命令。

调用 PFADD 命令时可以只给定键名而不给定元素:

  • 如果给定键已经是一个 HyperLogLog , 那么这种调用不会产生任何效果;
  • 但如果给定的键不存在, 那么命令会创建一个空的 HyperLogLog , 并向客户端返回 1

要了解更多关于 HyperLogLog 数据结构的介绍知识, 请查阅 PFCOUNT命令的文档。

  • 语法:

    1
    127.0.0.1:6379> PFADD key element [element ...]
  • 返回值:

    整数, specifically:

    • 如果 HyperLogLog 的内部储存被修改了, 那么返回 1 , 否则返回 0 。
  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PFADD myset a b c d e f g
    (integer) 1
    127.0.0.1:6379> PFCOUNT myset
    (integer) 7
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(1) to add every element.

1.12.2 PFCOUNT

Redis PFCOUNT 命令返回给定 HyperLogLog 的基数估算值。
PFCOUNT 命令作用于单个键时, 返回储存在给定键的 HyperLogLog 的近似基数, 如果键不存在, 那么返回 0 。
PFCOUNT 命令作用于多个键时, 返回所有给定 HyperLogLog 的并集的近似基数, 这个近似基数是通过将所有给定 HyperLogLog 合并至一个临时 HyperLogLog 来计算得出的。
通过 HyperLogLog 数据结构, 用户可以使用少量固定大小的内存, 来储存集合中的唯一元素 (每个 HyperLogLog 只需使用 12k 字节内存,以及几个字节的内存来储存键本身)。
命令返回的可见集合(observed set)基数并不是精确值, 而是一个带有 0.81% 标准错误(standard error)的近似值。
举个例子, 为了记录一天会执行多少次各不相同的搜索查询, 一个程序可以在每次执行搜索查询时调用一次 PFADD, 并通过调用 PFCOUNT命令来获取这个记录的近似结果。

  • 语法:

    1
    127.0.0.1:6379> PFCOUNT key [key ...]
  • 返回值:

    整数, specifically:

    • 给定 HyperLogLog 包含的唯一元素的近似数量。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs3
    (integer) 1
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs4
    (integer) 1
    127.0.0.1:6379> PFADD myset kungs1 kungs1 kungs1
    (integer) 0
    127.0.0.1:6379> PFADD myset kungs1 kungs2
    (integer) 0
    127.0.0.1:6379> PFCOUNT myset
    (integer) 4
    127.0.0.1:6379> PFADD myset-other a b c
    (integer) 1
    127.0.0.1:6379> PFCOUNT myset myset-other
    (integer) 7
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(1) with a very small average constant time when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.

1.12.3 PFMERGE

Redis PFMERGE 命令将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。

合并得出的 HyperLogLog 会被储存在 destkey 键里面, 如果该键并不存在, 那么命令在执行之前, 会先为该键创建一个空的 HyperLogLog 。

  • 语法:

    1
    127.0.0.1:6379> PFMERGE destkey sourcekey [sourcekey ...]
  • 返回值:

    字符串: OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs3
    (integer) 1
    127.0.0.1:6379> PFADD myset-other a b c
    (integer) 1
    127.0.0.1:6379> PFMERGE out myset myset-other
    OK
    127.0.0.1:6379> PFCOUNT out
    (integer) 6
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(N) to merge N HyperLogLogs, but with high constant times.

Redis协议详细规范

Redis客户端和服务器端通信使用名为 RESP (REdis Serialization Protocol) 的协议。虽然这个协议是专门为Redis设计的,它也可以用在其它 client-server 通信模式的软件上。

RESP 是下面条件的折中:

  • 实现起来简单。
  • 解析速度快。
  • 有可读性。

RESP 能序列化不同的数据类型,例如整型(integers)、字符串(strings)、数组(arrays)。额外还有特殊的错误类型。请求从客户端以字符串数组的形式发送到redis服务器,这些字符串表示要执行的命令的参数。Redis用特定于命令的数据类型回复。

RESP 是二进制安全的,并且不需要处理从一个进程发到另外一个进程的批量数据,因为它使用前缀长度来传输批量数据。

注意:这里概述的协议仅用于客户机-服务器通信。Redis集群使用不同的二进制协议在节点之间交换消息。

1. 网络层

连到Redis服务器的客户端建立了一个到6379端口的TCP连接。

虽然RESP在技术上不特定于TCP,但是在Redis的上下文中,该协议仅用于TCP连接(或类似的面向流的连接,如unix套接字)。

2. 请求-响应模型

Redis接受由不同参数组成的命令。一旦收到命令,就会对其进行处理,并将应答发送回客户端。

这是最简单的模型,但是有两个例外:

  • Redis 支持管道pipelining。所以,客户端可以一次发送多个命令,然后再等待应答。
  • 当一个Redis客户端订阅一个频道,那么协议会改变语义并变成pushprotocol, 也就是说,客户客户端不再需要发送命令,因为服务器端会一收到新消息,就会自动发送给客户端。

除了上面两个例外情况,Redis协议是一个简单的请求-响应协议。

3. RESP 协议解释

RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准。这个协议需要在你的Redis客户端实现。

RESP 是一个支持多种数据类型的序列化协议:简单字符串(Simple Strings),错误( Errors),整型( Integers), 大容量字符串(Bulk Strings)和数组(Arrays)。

RESP在Redis中作为一个请求-响应协议以如下方式使用:

  • 客户端以大容量字符串RESP数组的方式发送命令给服务器端。
  • 服务器端根据命令的具体实现返回某一种RESP数据类型。

在 RESP 中,数据的类型依赖于首字节:

  • 单行字符串(Simple Strings): 响应的首字节是 “+”
  • 错误(Errors): 响应的首字节是 “-“
  • 整型(Integers): 响应的首字节是 “:”
  • 多行字符串(Bulk Strings): 响应的首字节是“$“
  • 数组(Arrays): 响应的首字节是 “*

另外,RESP可以使用大容量字符串或者数组类型的特殊变量表示空值,下面会具体解释。RESP协议的不同部分总是以 “\r\n” (CRLF) 结束。

4. RESP 单行字符串

单行字符串编码方法: 加号后面跟着一个不包含回车或换行字符的字符串 (不允许出现换行),以CRLF(“\r\n”)结尾。

单行字符串通常被用来传输非二进制安全字符串并且消耗极小。例如,许多redis命令在成功时回复”OK”,即简单字符串用以下5个字节编码:

1
"+OK\r\n"

为了发送二进制安全的字符串,需要使用RESP的多行字符串(Bulk Strings)替代。

当Redis返回单行字符串(Simple String)时,客户端lib应该返回去掉首字符加号和结尾CRLF字符的字符串给调用者。

5. RESP 错误

RESP 有特殊类型来处理错误。errors类型除了首字符是减号 ‘-‘不是加号以外,其它跟简单字符串一样。RESP中简单字符和错误的真正区别是:错误被客户端当作异常处理,组成错误类型的字符串是错误消息自身。

基本格式如下:

1
"-Error message\r\n"

错误应答只在发生异常时发送,例如,要执行命令的参数数据类型不匹配或者命令不存在等。当收到错误返回时,客户端lib应该抛出一个异常。

错误返回例子:

1
2
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

从”-“后面第一个单词起,直到第一个空格或者换行,表示返回的错误类型。这是Redis的一种约定,并不是RESP协议的要求。

ERR 是一个通用错误, 而 WRONGTYPE 是表示更具体的错误,意味着客户端在错误的数据类型上执行操作。这被叫做错误前缀(Error Prefix), 使客户端不用依赖具体错误消息就知道返回的错误类型,错误消息可能会随着时间而变化。

客户端实现可能会对不同异常返回不同类型的错误,或者可能提供一种通用的方式来捕获错误,通过以字符串的形式直接返回错误名给调用者。

尽管如此,这种特性不能认为很重要,因为它很少被使用。一小部分客户端的实现可能会返回通用错误条件,例如false。

6. RESP 整数

整数类型是由以冒号开头,CRLF结尾,中间是字符串形式表示的数字。 例如 “:0\r\n”, 或 “:1000\r\n” 都是整数回复。

很多Redis命令返回RESP整数,像 INCR, LLENLASTSAVE.

返回的整数并没有特别的意义, INCR 返回的是一个递增的数字, LASTSAVE 返回的是Unix时间戳等。返回的整数有效值需要在有符号64位整数范围内。

整数返回也被广泛的用来返回 true 或 false。比如 EXISTSSISMEMBER 命令返回1表示true,返回0表示false。

其它命令像 SADD, SREMSETNX 如果操作被执行则返回1,否则返回0。

返回整数回复的命令: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.

6. RESP 多行字符串

多行字符串被用来表示最大512MB长的二进制安全字符串。

多行字符串编码方式:

  • 美元符 “$“ 后面跟着组成字符串的字节数(前缀长度),并以 CRLF 结尾。
  • 实际的字符串数据。
  • 结尾是 CRLF。

所以,字符串 “foobar” 编码如下:

1
"$6\r\nfoobar\r\n"

空字符串编码格式:

1
"$0\r\n\r\n"

RESP 多行字符串(Bulk Strings) 也可以使用一个特殊的用来表示空值的格式表示不存在的值。在这种格式里长度值为-1,数据部分不存在,所以空(Null)用如下方式表示:

1
"$-1\r\n"

叫做空的多行字符串Null Bulk String。

客户端API库不应该返回空串,当服务器端响应一个空的多行字符串时,API库可以返回一个空对象给调用者。例如,Ruby库应该返回 ‘nil’ ,而C库应该返回NULL。

7. RESP 数组

客户端使用 RESP 数组发送命令到 Redis 服务端。同样地,某些命令的应答使用RESP数组返回元素的集合给Redis客户端。 LRANGE 命令返回元素列表就是一个例子。

RESP 数组使用如下格式发送:

  • 以星号* 为首字符,接着是表示数组中元素个数的十进制数,最后以 CRLF 结尾。
  • 外加数组中每个 RESP 类型的元素。

空数组表示:

1
"*0\r\n"

有两个 RESP 多行字符串”foo” 和”bar”元素的 RESP 数组 :

1
"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

在前缀 *<count>CRLF 的后面,组成数组的其它数据类型一个接在另一个后面。 例如包含三个整数的数组编码方式:

1
"*3\r\n:1\r\n:2\r\n:3\r\n"

数组可以包含混合类型,不一定必须是同一种类型。例如,4个整型和1个多行字符串编码方式:

1
2
3
4
5
6
7
*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(为了方便阅读,应答分成多行来展示)

第一个行表示 *5\r\n 说明后面有5个应答。这些应答组成一个大的应答一起发送。

空数组的概念也是存在的,另一个表示空值的方式(通常使用多行空字符串,历史遗留导致有这两种格式)。

例如,当 BLPOP 命令超时,它会返回一个空数组,数组的计数器是-1 :

1
"*-1\r\n"

当 Redis 返回一个空数组的时候,Redis客户端库API应该返回一个空对象而不是返回一个空数组。 这对区分空列表和其它不同情况(像 BLPOP 命令超时情况)是必要的。

数组的数组也是可行的。例如,一个含有两个数组元素的数组编码方式:

1
2
3
4
5
6
7
8
*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

(为了方便阅读,分成多行来展示).

上面的 RESP 数据类型包含两个数组,一个数组包含三个整数1, 2, 3 ,另一个是简单字符串和一个错误类型。

8. 数组中的空元素

数组中可以有为空的元素。主要使用在Redis应答中,为了表示这个元素丢失并且不是一个空的字符串。当SORT命令使用GET 模式选项,并且特定的key丢失的时会出现这种应答。 含有有空元素的应答数组例子:

1
2
3
4
5
6
*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n

第二个元素是空,客户端库应该返回像下面这样的数据:

1
["foo",nil,"bar"]

这不是前面提到的异常情况,这只是说明协议的一个例子。

9. 发送命令到Redis服务器

至此,我们已经很熟悉RESP序列化格式,写一个Redis客户端库的实现会变得很容易。我们可以进一步说明客户端和服务端如何交互工作:

  • 客户端发送包含只有多行字符串的数组给Redis服务器。
  • Redis 服务器给客户端发送任意有效的 RESP 数据类型作为应答。

下面是一个典型的交互过程例子:

客户端发送命令 LLEN mylist 来获取存储在 mylist 键中列表的长读,然后服务器端返回整数应答(C: 代表客户端, S: 代表服务器端).

1
2
3
4
5
6
7
C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n

S: :48293\r\n

为了方便理解我们用换行把协议分成不同部分,实际上客户端发送的是一个整体没有换行:*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.

10. 管道和多个命令

客户端可以使用同一个连接发送多个命令。通过管道客户端可以一次写操作发送多个命令,发送下一个命令前不需要等待前一个命令的应答。所有应答可以在最后被读取。

关于管道详细参考 page about Pipelining.

11. 内联命令

有时你手边只能操作telnet 并且需要给Redis 服务器端发送命令。虽然Redis协议是容易实现的,但并不适合用在交互会话。redis-cli 也不是随时都能可用。因此,redis还以一种特殊的方式接受为人类设计的命令,称为内联命令格式。

以下是使用内联命令进行服务器/客户端聊天的示例(服务器聊天以s开头,客户端聊天以c开头)。

1
2
C: PING
S: +PONG

以下是返回整数的内联命令的另一个示例:

1
2
C: EXISTS somekey
S: :0

基本上,您只需在telnet会话中编写空格分隔的参数。由于统一请求协议中没有以*开头的命令,因此Redis能够检测到这种情况并解析您的命令。

12. Redis 协议的高性能解析器

虽然redis协议是非常容易被人阅读和实现的,但是它可以以类似于二进制协议的性能来实现。

RESP 使用带前缀的长度来传输批量数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

批量和多批量长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

RESP 使用带前缀的长度来传输多行数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

多行和多个多行长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void) {
unsigned char *p = "$123\r\n";
int len = 0;

p++;
while(*p != '\r') {
len = (len*10)+(*p - '0');
p++;
}

/* Now p points at '\r', and the len is in bulk_len. */
printf("%d\n", len);
return 0;
}

在识别出第一个CR之后,可以跳过它和下面的LF,而不需要任何处理。然后,可以使用不以任何方式检查有效负载的单个读取操作读取大容量数据。最后,剩余的CR和LF字符将被丢弃,而不进行任何处理。

Redis协议有着与二进制协议可比的性能,更重要的是易于在大多数高级语言中实现,从而减少了客户端软件中的错误数量。

Redis键空间通知

重要:键空间通知功能自2.8.0版本开始可用。

1. 功能概述

键空间通知允许客户端订阅发布/订阅频道,以便以某种方式接收影响Redis数据集的事件。可能接收的事件示例如下:

  • 所有影响给定键的命令。
  • 所有接收LPUSH操作的键。
  • 所有在数据库0中到期的键。

事件使用Redis的普通发布/订阅层传递,因此实现了发布/订阅的客户端无需修改即可使用此功能。由于Redis的发布/订阅是fire and forget,因此如果你的应用要求可靠的事件通知,目前还不能使用这个功能,也就是说,如果你的发布/订阅客户端断开连接,并在稍后重连,那么所有在客户端断开期间发送的事件将会丢失。将来有计划允许更可靠的事件传递,但可能会在更一般的层面上解决,要么为发布/订阅本身带来可靠性,要么允许Lua脚本拦截发布/订阅的消息以执行推送等操作,就像往队列里推送事件一样。

2. 事件类型

键空间通知的实现是为每一个影响Redis数据空间的操作发送两个不同类型的事件。例如,在数据库0中名为mykey的键上执行DEL操作,将触发两条消息的传递,完全等同于下面两个PUBLISH命令:

1
2
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey

以上很容易看到,一个频道允许监听所有以键mykey为目标的所有事件,以及另一个频道允许获取有关所有DEL操作目标键的信息。第一种事件,在频道中使用keyspace前缀的被叫做键空间通知,第二种,使用keyevent前缀的,被叫做键事件通知。在以上例子中,为键mykey生成了一个del事件。 会发生什么:

  • 键空间频道接收到的消息是事件的名称。
  • 键事件频道接收到的消息是键的名称。

可以只启用其中一种通知,以便只传递我们感兴趣的事件子集。

3. 配置

默认情况下,键空间事件通知是不启用的,因为虽然不太明智,但该功能会消耗一些CPU。可以使用redis.conf中的notify-keyspace-events或者使用CONFIG SET命令来开启通知。将参数设置为空字符串会禁用通知。 为了开启通知功能,使用了一个非空字符串,由多个字符组成,每一个字符都有其特殊的含义,具体参见下表:

1
2
3
4
5
6
7
8
9
10
11
K     键空间事件,以__keyspace@<db>__前缀发布。
E 键事件事件,以__keyevent@<db>__前缀发布。
g 通用命令(非类型特定),如DEL,EXPIRE,RENAME等等
$ 字符串命令
l 列表命令
s 集合命令
h 哈希命令
z 有序集合命令
x 过期事件(每次键到期时生成的事件)
e 被驱逐的事件(当一个键由于达到最大内存而被驱逐时产生的事件)
A g$lshzxe的别名,因此字符串AKE表示所有的事件。

字符串中应当至少存在K或者E,否则将不会传递事件,不管字符串中其余部分是什么。例如,要为列表开启键空间事件,则配置参数必须设置为Kl,以此类推。字符串KEA可以用于开启所有可能的事件。

4. 不同的命令生成的事件

根据以下列表,不同的命令产生不同种类的事件。

  • DEL命令为每一个删除的key生成一个del事件。
  • RENAME生成两个事件,一个是为源key生成的rename_from事件,一个是为目标key生成的rename_to事件。
  • EXPIRE在给一个键设置有效期时,会生成一个expire事件,或者每当设置有效期导致键被删除时,生成expired事件(请查阅EXPIRE文档以获取更多信息)。
  • SORT会在使用STORE选项将结果存储到新键时,生成一个sortstore事件。如果结果列表为空,且使用了STORE选项,并且已经存在具有该名称的键时,那个键将被删除,因此在这种场景下会生成一个del事件。
  • SET以及所有其变种(SETEXSETNXGETSET)生成set事件。但是SETEX还会生成一个expire事件。
  • MSET为每一个key生成一个set事件。
  • SETRANGE生成一个setrange事件。
  • INCRDECRINCRBYDECRBY命令都生成incrby事件。
  • INCRBYFLOAT生成一个incrbyfloat事件。
  • APPEND生成一个append事件。
  • LPUSHLPUSHX生成一个lpush事件,即使在可变参数情况下也是如此。
  • RPUSHRPUSHX生成一个rpush事件,即使在可变参数情况下也是如此。
  • RPOP生成rpop事件。此外,如果键由于列表中的最后一个元素弹出而被删除,则会生成一个del事件。
  • LPOP生成lpop事件。此外,如果键由于列表中的最后一个元素弹出而被删除,则会生成一个del事件。
  • LINSERT生成一个linsert事件。
  • LSET生成一个lset事件。
  • LTRIM生成ltrim事件,此外,如果结果列表为空或者键被移除,将会生成一个del事件。
  • RPOPLPUSHBRPOPLPUSH生成rpop事件和lpush事件。这两种情况下,顺序都将得到保证(lpush事件将总是在rpop事件之后传递)。此外,如果结果列表长度为零且键被删除,则会生成一个del事件。
  • HSETHSETNX以及HMSET都生成一个hset事件。
  • HINCRBY生成一个hincrby事件。
  • HINCRBYFLOAT生成一个hincrbyfloat事件。
  • HDEL生成一个hdel事件,此外,如果结果哈希集为空或者键被移除,将生成一个del事件。
  • SADD生成一个sadd事件,即使在可变参数情况下也是如此。
  • SREM生成一个srem事件,此外,如果结果集合为空或者键被移除,将生成一个del事件。
  • SMOVE为每一个源key生成一个srem事件,以及为每一个目标key生成一个sadd事件。
  • SPOP生成一个spop事件,此外,如果结果集合为空或者键被移除,将生成一个del事件。
  • SINTERSTORESUNIONSTORESDIFFSTORE分别生成sinterstoresunionostoresdiffstore事件。在特殊情况下,结果集是空的,并且存储结果的键已经存在,因为删除了键,所以会生成del事件。
  • ZINCR生成一个zincr事件。
  • ZADD生成一个zadd事件,即使添加了多个元素。
  • ZREM生成一个zrem事件,即使删除了多个元素。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZREMBYSCORE生成一个zrembyscore事件。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZREMBYRANK生成一个zrembyrank事件。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZINTERSTOREZUNIONSTORE分别生成zinterstorezunionstore事件。在特殊情况下,结果有序集合是空的,并且存储结果的键已经存在,因为删除了键,所以会生成del事件。
  • 每次一个拥有过期时间的键由于过期而从数据集中移除时,将生成一个expired事件。
  • 每次一个键由于maxmemory策略而被从数据集中驱逐,以便释放内存时,将生成一个evicted事件。

重要 所有命令仅在真正修改目标键时才生成事件。例如,使用SREM命令从集合中删除一个不存在的元素将不会改变键的值,因此不会生成任何事件。如果对某个命令如何生成事件有疑问,最简单的方法是自己观察:

1
2
3
4
$ redis-cli config set notify-keyspace-events KEA
$ redis-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1

此时,在另外一个终端使用redis-cli发送命令到Redis服务器,并观察生成的事件:

1
2
3
"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...

5. 过期事件的时间安排

设置了生存时间的键由Redis以两种方式过期:

  • 当命令访问键时,发现键已过期。
  • 通过后台系统在后台逐步查找过期的键,以便能够收集那些从未被访问的键。

当通过以上系统之一访问键且发现键已经过期时,将生成expired事件。因此无法保证Redis服务器在键过期的那一刻同时生成expired事件。如果没有命令不断地访问键,并且有很多键都有关联的TTL,那么在键的生存时间降至零到生成expired事件之间,将会有明显的延迟。基本上,expired事件是在Redis服务器删除键的时候生成的,而不是在理论上生存时间达到零值时生成的。

Redis复制

在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。

这个系统的运行依靠三个主要的机制:

  • 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
  • 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
  • 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。

客户端可以使用 WAIT 命令来请求同步复制某些特定的数据。但是,WAIT 命令只能确保在其他 Redis 实例中有指定数量的已确认的副本:在故障转移期间,由于不同原因的故障转移或是由于 Redis 持久性的实际配置,故障转移期间确认的写入操作可能仍然会丢失。你可以查看 Sentinel 或 Redis 集群文档,了解关于高可用性和故障转移的更多信息。本文的其余部分主要描述 Redis 基本复制功能的基本特性。

接下来的是一些关于 Redis 复制的非常重要的事实:

  • Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量
  • 一个 master 可以拥有多个 slave
  • slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
  • Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
  • 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,假设你在 redis.conf 中配置了让 Redis 这样做的话。否则,你可以配置如果复制流断开, Redis slave 会返回一个 error 给客户端。但是,在初次同步之后,旧数据集必须被删除,同时加载新的数据集。 slave 在这个短暂的时间窗口内(如果数据集很大,会持续较长时间),会阻塞到来的连接请求。自 Redis 4.0 开始,可以配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行,但是,加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。
  • 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
  • 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。

1. 当 master 关闭持久化时,复制的安全性

在使用 Redis 复制功能时的设置中,强烈建议在 master 和在 slave 中启用持久化。当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启

为了更好地理解为什么关闭了持久化并配置了自动重启的 master 是危险的,检查以下故障模式,这些故障模式中数据会从 master 和所有 slave 中被删除:

  1. 我们设置节点 A 为 master 并关闭它的持久化设置,节点 B 和 C 从 节点 A 复制数据。
  2. 节点 A 崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。
  3. 节点 B 和 节点 C 会从节点 A 复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。

当 Redis Sentinel 被用于高可用并且 master 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, master 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。

任何时候数据安全性都是很重要的,所以如果 master 使用复制功能的同时未配置持久化,那么自动重启进程这项应该被禁用。

2. Redis 复制功能是如何工作的

每一个 Redis master 都有一个 replication ID :这是一个较大的伪随机字符串,标记了一个给定的数据集。每个 master 也持有一个偏移量,master 将自己产生的复制流发送给 slave 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时,也会自增,所以基本上每一对给定的

Replication ID, offset

都会标识一个 master 数据集的确切版本。

当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式, master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,或者如果 slave 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。

下面是一个全量同步的工作细节:

master 开启一个后台保存进程,以便于生产一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台保存完成时, master 将数据集文件传输给 slave, slave将之保存在磁盘上,然后加载文件到内存。再然后 master 会发送所有缓冲的命令发给 slave。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。

你可以用 telnet 自己进行尝试。在服务器正在做一些工作的同时连接到 Redis 端口并发出 SYNC 命令。你将会看到一个批量传输,并且之后每一个 master 接收到的命令都将在 telnet 回话中被重新发出。事实上 SYNC 是一个旧协议,在新的 Redis 实例中已经不再被使用,但是其仍然向后兼容:但它不允许部分重同步,所以现在 PSYNC 被用来替代 SYNC。

之前说过,当主从之间的连接因为一些原因崩溃之后, slave 能够自动重连。如果 master 收到了多个 slave 要求同步的请求,它会执行一个单独的后台保存,以便于为多个 slave 服务。

3. 无需磁盘参与的复制

正常情况下,一个全量重同步要求在磁盘上创建一个 RDB 文件,然后将它从磁盘加载进内存,然后 slave以此进行数据同步。

如果磁盘性能很低的话,这对 master 是一个压力很大的操作。Redis 2.8.18 是第一个支持无磁盘复制的版本。在此设置中,子进程直接发送 RDB 文件给 slave,无需使用磁盘作为中间储存介质。

4. 配置

配置基本的 Redis 复制功能是很简单的:只需要将以下内容加进 slave 的配置文件:

slaveof 192.168.1.1 6379

当然你需要用你自己的 master IP 地址(或者主机名)和端口替换掉 192.168.1.1 6379。另一种方法,你也可以使用 SLAVEOF 命令, master 会开启一个跟 slave 间的同步。

还有一些参数用于调节内存中保存的缓冲积压部分(replication backlog),以便执行部分重同步。详见 redis.conf 和 Redis Distribution 了解更多信息。

无磁盘复制可以使用 repl-diskless-sync 配置参数。repl-diskless-sync-delay 参数可以延迟启动数据传输,目的可以在第一个 slave就绪后,等待更多的 slave就绪。可以在 Redis Distribution 例子中的 redis.conf 中看到更多细节信息。

5. 只读性质的 slave

自从 Redis 2.6 之后, slave 支持只读模式且默认开启。redis.conf 文件中的 slave-read-only 变量控制这个行为,且可以在运行时使用 CONFIG SET 来随时开启或者关闭。

只读模式下的 slave 将会拒绝所有写入命令,因此实践中不可能由于某种出错而将数据写入 slave 。但这并不意味着该特性旨在将一个 slave 实例暴露到 Internet ,或者更广泛地说,将之暴露在存在不可信客户端的网络,因为像 DEBUG 或者 CONFIG 这样的管理员命令仍在启用。但是,在 redis.conf 文件中使用 rename-command 指令可以禁用上述管理员命令以提高只读实例的安全性。

您也许想知道为什么可以还原只读设置,并有可以通过写入操作来设置 slave 实例。如果 slave 跟 master 在同步或者 slave 在重启,那么这些写操作将会无效,但是将短暂数据存储在 writable slave 中还是有一些合理的用例的。

例如,计算 slow Set 或者 Sorted Set 的操作并将它们存储在本地 key 中是多次观察到的使用 writable slave 的用例。

但是注意,4.0 版本之前的 writable slaves 不能用生存时间来淘汰 key 。这意味着,如果你使用 EXPIRE 或者其他命令为 key 设置了最大 TTL 的话,你将会在键值计数(count of keys)中看到这个 key ,并且它还在内存中。所以总的来说,将 writable slaves 和设置过 TTL 的 key 混用将会导致问题。

Redis 4.0 RC3 及更高版本彻底解决了这个问题,现在 writable slaves 能够像 master 一样驱逐 TTL 设置过的 key 了,但 DB 编号大于 63(但默认情况下,Redis实例只有16个数据库)的 key 除外。

另请注意,由于 Redis 4.0 writable slaves 仅能本地,并且不会将数据传播到与该实例相连的 sub-slave 上。sub-slave 将总是接收与最顶层 master 向 intermediate slaves 发送的复制流相同的复制流。所以例如在以下设置中:

A —-> B ——> C

及时节点 B 是可写的,C 也不会看到 B 的写入,而是将拥有和 master 实例 A 相同的数据集。

6. 设置一个 slave 对 master 进行验证

如果你的 master 通过 requirepass 设置了密码,则在所有同步操作中配置 slave 使用该密码是很简单的。

要在正在运行的实例上执行此操作,请使用 redis-cli 并输入:

config set masterauth

要永久设置的话,请将其添加到您的配置文件中:

masterauth

7. 允许只写入 N 个附加的副本

从Redis 2.8开始,只有当至少有 N 个 slave 连接到 master 时,才有可能配置 Redis master 接受写查询。

但是,由于 Redis 使用异步复制,因此无法确保 slave 是否实际接收到给定的写命令,因此总会有一个数据丢失窗口。

以下是该特性的工作原理:

  • Redis slave 每秒钟都会 ping master,确认已处理的复制流的数量。
  • Redis master 会记得上一次从每个 slave 都收到 ping 的时间。
  • 用户可以配置一个最小的 slave 数量,使得它滞后 <= 最大秒数。

如果至少有 N 个 slave ,并且滞后小于 M 秒,则写入将被接受。

你可能认为这是一个尽力而为的数据安全机制,对于给定的写入来说,不能保证一致性,但至少数据丢失的时间窗限制在给定的秒数内。一般来说,绑定的数据丢失比不绑定的更好。

如果条件不满足,master 将会回复一个 error 并且写入将不被接受。

这个特性有两个配置参数:

  • min-slaves-to-write
  • min-slaves-max-lag <秒数>

有关更多信息,请查看随 Redis 源代码发行版一起提供的示例 redis.conf 文件。

8. Redis 复制如何处理 key 的过期

Redis 的过期机制可以限制 key 的生存时间。此功能取决于 Redis 实例计算时间的能力,但是,即使使用 Lua 脚本更改了这些 key,Redis slaves 也能正确地复制具有过期时间的 key。

为了实现这样的功能,Redis 不能依靠主从使用同步时钟,因为这是一个无法解决的并且会导致 race condition 和数据集不一致的问题,所以 Redis 使用三种主要的技术使过期的 key 的复制能够正确工作:

  • slave 不会让 key 过期,而是等待 master 让 key 过期。当一个 master 让一个 key 到期(或由于 LRU 算法将之驱逐)时,它会合成一个 DEL 命令并传输到所有的 slave。
  • 但是,由于这是 master 驱动的 key 过期行为,master 无法及时提供 DEL 命令,所以有时候 slave 的内存中仍然可能存在在逻辑上已经过期的 key 。为了处理这个问题,slave 使用它的逻辑时钟以报告只有在不违反数据集的一致性的读取操作(从主机的新命令到达)中才存在 key。用这种方法,slave 避免报告逻辑过期的 key 仍然存在。在实际应用中,使用 slave 程序进行缩放的 HTML 碎片缓存,将避免返回已经比期望的时间更早的数据项。
  • 在Lua脚本执行期间,不执行任何 key 过期操作。当一个Lua脚本运行时,从概念上讲,master 中的时间是被冻结的,这样脚本运行的时候,一个给定的键要么存在要么不存在。这可以防止 key 在脚本中间过期,保证将相同的脚本发送到 slave ,从而在二者的数据集中产生相同的效果。

一旦一个 slave 被提升为一个 master ,它将开始独立地过期 key,而不需要任何旧 master 的帮助。

9. 在 Docker 和 NAT 中配置复制

当使用 Docker 或其他类型的容器使用端口转发或网络地址转换时,Redis 复制需要特别小心,特别是在使用 Redis Sentinel 或其他系统(其中扫描 master INFO 或 ROLE 命令的输出情况以便于发现 slave 地址的)。

问题是 ROLE 命令和 INFO 输出的复制部分在发布到 master 实例中时,将显示 slave 具有的用于连接到 master 的 IP 地址,而在使用 NAT 的环境中,和 slave 实例的逻辑地址(客户机用来连接 slave 的地址)相比较可能会不同。

类似地,slaves 将以 redis.conf 文件中监听的端口为序列出,在重新映射端口的情况下,该端口可能与转发的端口不同。

为了解决这两个问题,从 Redis 3.2.2 开始,可以强制一个 slave 向 master 通告一对任意的 IP 和端口。使用的两个配置指令是:

slave-announce-ip 5.5.5.5

slave-announce-port 1234

在近期 Redis distributions 中的 redis.conf 的样例中可以找到记录。

10. INFO 和 ROLE 命令

有两个 Redis 命令可以提供有关主从实例当前复制参数的很多信息。一个是INFO。如果使用复制参数像 INFO replication 调用该命令,,则只显示与复制相关的信息。另一个更加 computer-friendly 的命令是 ROLE,它提供 master 和 slave 的复制状态以及它们的复制偏移量,连接的 slaves 列表等等。

11. 重新启动和故障转移后的部分重同步

从 Redis 4.0 开始,当一个实例在故障转移后被提升为 master 时,它仍然能够与旧 master 的 slaves 进行部分重同步。为此,slave 会记住旧 master 的旧 replication ID 和复制偏移量,因此即使询问旧的 replication ID,其也可以将部分复制缓冲提供给连接的 slave 。

但是,升级的 slave 的新 replication ID 将不同,因为它构成了数据集的不同历史记录。例如,master 可以返回可用,并且可以在一段时间内继续接受写入命令,因此在被提升的 slave 中使用相同的 replication ID 将违反一对复制标识和偏移对只能标识单一数据集的规则。

另外,slave 在关机并重新启动后,能够在 RDB 文件中存储所需信息,以便与 master 进行重同步。这在升级的情况下很有用。当需要时,最好使用 SHUTDOWN 命令来执行 slave 的保存和退出操作。