biancheng-Redis教程

目录http://c.biancheng.net/redis/

1Redis是什么
2Windows下载安装Redis
3Ubuntu下载安装Redis
4Redis配置文件
5Redis数据类型
6Redis命令行模式
7Redis key键
8Redis string字符串
9Redis bitmap位图
10Redis数值操作命令
11Redis list列表
12Redis hash哈希散列
13Redis set集合
14Redis zset有序集合
15Redis连接命令
16Redis安全策略
17Redis客户端命令
18Redis服务器命令
19Redis基数统计
20Redis发布订阅
21Redis消息队列
22Redis布隆过滤器
23Redis地理位置
24Redis事务
25Redis Lua脚本
26Redis性能测试
27Redis分区技术
28Redis管道技术
29Redis数据备份和还原
30Redis RDB持久化
31Redis AOF持久化
32Redis主从模式
33Redis哨兵模式
34Redis分布式锁
35Redis缓存问题
36Java使用Redis
37PHP使用Redis
38Python使用Redis
39Redis配置项汇总

Redis是什么

与其他内存型数据库相比,Redis 具有以下特点:

  • Redis 不仅可以将数据完全保存在内存中,还可以通过磁盘实现数据的持久存储;
  • Redis 支持丰富的数据类型,包括 string、list、set、zset、hash 等多种数据类型,因此它也被称为“数据结构服务器”;
  • Redis 支持主从同步,即 master-slave 主从复制模式。数据可以从主服务器向任意数量的从服务器上同步,有效地保证数据的安全性;
  • Redis 支持多种编程语言,包括 C、C++、Python、Java、PHP、Ruby、Lua 等语言。


与 SQL 型数据库截然不同,Redis 没有提供新建数据库的操作,因为它自带了 16 (0—15)个数据库(默认使用 0 库)。在同一个库中,key 是唯一存在的、不允许重复的,它就像一把“密钥”,只能打开一把“锁”。键值存储的本质就是使用 key 来标识 value,当想要检索 value 时,必须使用与 value 相对应的 key 进行查找。

Redis 数据库没有“表”的概念,它通过不同的数据类型来实现存储数据的需求,不同的数据类型能够适应不同的应用场景,从而满足开发者的需求。

Redis架构

Redis体系架构主要分为两个部分:

  • Redis服务端
  • Redis客户端


客户端和服务端可以位于同一台计算机上,也可以位于不同的计算机上。服务端是整个架构的“大脑”,能够把数据存储到内存中,并且起到管理数据的作用。

Redis优势

下面对 Redis 的优势进行了简单总结:

  • 性能极高:Redis 基于内存实现数据存储,它的读取速度是 110000次/s,写速度是 81000次/s;
  • 多用途工具: Redis 有很多的用途,比如可以用作缓存、消息队列、搭建 Redis 集群等;
  • 命令提示功能:Redis 客户端拥有强大的命令提示功能,使用起来非常的方便,降低了学习门槛;
  • 可移植性:Redis 使用用标准 C语言编写的,能够在大多数操作系统上运行,比如 Linux,Mac,Solaris 等。

Redis应用场景

Redis 用来缓存一些经常被访问的热点数据、或者需要耗费大量资源的内容,通过把这些内容放到 Redis 中,可以让应用程序快速地读取它们。例如,网站的首页需要经常被访问,并且在创建首页的过程中会消耗的较多的资源,此时就可以使用 Redis 将整个首页缓存起来,从而降低网站的压力,减少页面访问的延迟时间。

我们知道,数据库的存储方式大体可分为两大类,基于磁盘存储和基于内存存储。磁盘存储的数据库,因为磁头机械运动以及系统调用等因素导致读写效率较低。Redis 基于内存来实现数据存取,相对于磁盘来说,其读写速度要高出好几个数量级。下表将 Redis 数据库与其他常用数据库做了简单对比:

Redis与其他数据库对比
名称类型数据存储选项附加功能
Redis 基于内存存储的键值非关系型数据库 字符串、列表、散列、有序集合、无序集合 发布与订阅、主从复制、持久化存储等
Memcached 基于内存存储的键值缓存型数据库 键值之间的映射 为提升性能构建了多线程服务器
MySQL 基于磁盘的关系型数据库 每个数据库可以包含多个表,每个表可以包含多条记录;
支持第三方扩展。
支持 ACID 性质、主从复制和主主复制
MongoDB 基于磁盘存储的非关系文档型数据库 每个数据库可以包含多个集合,每个集合可以插入多个文档 支持聚合操作、主从复制、分片和空间索引


Redis 基于内存来实现数据的存储,因此其速度非常快。但是我们知道,计算机的内存是非常珍贵的资源,所以 Redis 不适合存储较大的文件或者二进制数据,否则会出现错误,Redis 适合存储较小的文本信息。理论上 Redis 的每个 key、value 的大小不超过 512 MB。

总结

下面对安装过程中涉及到的命令进行总结,主要包括以下命令:

安装服务:redis-server --service-install
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
服务端启动时重命名:redis-server --service-start --service-name Redis1

Redis配置文件

配置项说明

下表对一些配置项做了简单地说明:
 

配置项说明
配置项参数说明
daemonize no/yes 默认为 no,表示 Redis 不是以守护进程的方式运行,通过修改为 yes 启用守护进程。
pidfile 文件路径 当 Redis 以守护进程方式运行时,会把进程 pid 写入自定义的文件中。
port 6379 指定 Redis 监听端口,默认端口为 6379。
bind 127.0.0.1 绑定的主机地址。
timeout 0  客户端闲置多长秒后关闭连接,若指定为 0 ,表示不启用该功能。
loglevel notice  指定日志记录级别,支持四个级别:debug、verbose、notice、warning,默认为 notice。
logfile stdout 日志记录方式,默认为标准输出。
databases 16 设置数据库的数量(0-15个)共16个,Redis 默认选择的是 0 库,可以使用 SELECT 命令来选择使用哪个数据库储存数据。
save[seconds]
[changes]
可以同时配置三种模式:
save 900 1
save 300 10
save 60 10000
表示在规定的时间内,执行了规定次数的写入或修改操作,Redis 就会将数据同步到指定的磁盘文件中。比如 900s 内做了一次更改,Redis 就会自动执行数据同步。
rdbcompression yes/no 当数据存储至本地数据库时是否要压缩数据,默认为 yes。
dbfilename dump.rdb 指定本地存储数据库的文件名,默认为 dump.rdb。
dir ./ 指定本地数据库存放目录。
 
slaveof <masterip>
<masterport>
主从复制配置选项 当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动与 master 主机进行数据同步。
requirepass  foobared 默认关闭 密码配置项,默认关闭,用于设置 Redis 连接密码。如果配置了连接密码,客户端连接 Redis 时需要通过<password> 密码认证。
maxmemory
<bytes>
最大内存限制配置项 指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会尝试清除已到期或即将到期的 Key,当此方法处理 后,若仍然到达最大内存设置,将无法再进行写入操作,但可以进行读取操作。
appendfilename appendonly.aof 指定 AOF 持久化时保存数据的文件名,默认为 appendonly.aof。
glueoutputbuf yes 设置向客户端应答时,是否把较小的包合并为一个包发送,默认开启状态。


如果想全面了解配置选项

Redis数据类型

 Redis 是 Key-Value 类型缓存型数据库,Redis 为了存储不同类型的数据,提供了五种常用数据类型,如下所示:

  • string(字符串)
  • hash(哈希散列)
  • list(列表)
  • set(集合)
  • zset(sorted set:有序集合)

Redis命令行模式

在 CMD 命令行输入以下命令启动一个 Redis 客户端:

redis-cli

远程服务器上运行命令

远程服务器顾名思义指的是服务器安装在另外一台计算机上,而非本地。这台远程计算机可以是局域网中的一台,也可以是 Internet 联网状态下的远程计算机。Redis 提供了连接远程服务器的命令,格式如下:

C:\Users\Administrator>redis-cli -h host -p port -a password

参数说明:

    • -h:用于指定远程 Redis 服务器的 IP 地址;
    • -p:用于指定 Redis 远程服务器的端口号;
    • -a:可选参数,若远程服务器设置了密码,则需要输入。

Redis key键

Redis键命令汇总

下表对常用的 Redis 键命令做了简单的总结:

Redis 键命令
命令说明
DEL key 若键存在的情况下,该命令用于删除键。
DUMP key 用于序列化给定 key ,并返回被序列化的值。
EXISTS key 用于检查键是否存在,若存在则返回 1,否则返回 0。
EXPIRE key 设置 key 的过期时间,以秒为单位。
EXPIREAT key 该命令与 EXPIRE 相似,用于为 key 设置过期时间,不同在于,它的时间参数值采用的是时间戳格式。
PEXPIRE key 设置 key 的过期,以毫秒为单位。
PEXPIREAT key 与 PEXPIRE 相似,用于为 key 设置过期时间,采用以毫秒为单位的时间戳格式。
KEYS pattern 此命令用于查找与指定 pattern 匹配的 key。
MOVE key db 将当前数据库中的 key 移动至指定的数据库中(默认存储为 0 库,可选 1-15中的任意库)。
PERSIST key 该命令用于删除 key 的过期时间,然后 key 将一直存在,不会过期。
PTTL key 用于检查 key 还剩多长时间过期,以毫秒为单位。
TTL key 用于检查 key 还剩多长时间过期,以秒为单位。
RANDOMKEY 从当前数据库中随机返回一个 key。
RENAME key newkey 修改 key 的名称。
RENAMENX key newkey 如果新键名不重复,则将 key 修改为 newkey。
SCAN cursor 基于游标的迭代器,用于迭代数据库中存在的所有键,cursor 指的是迭代游标。
TYPE key 该命令用于获取 value 的数据类型。

常用命令演示

下面对一些较难理解的命令做实例演示:

1) DUMP序列化

该命令用于将键对应的值做序列化处理,实例如下:

  • 127.0.0.1:6379> SET num 12
  • OK
  • 127.0.0.1:6379> DUMP num
  • "\x00\xc0\x0c\t\x00\xec\xd8\xa9\x9d\b\x82\xdfd"

如果 key 不存在时,则返回 nil。

2) EXPIRE设置过期时间

该命令用于设置 key 的过期时间,当 key 过期后将不可以再使用。

  • 127.0.0.1:6379> set www.biancheng.net Python
  • OK
  • 127.0.0.1:6379> set www.biancheng.net Python EX 60
  • OK
  • 127.0.0.1:6379> EXPIRE www.biancheng.net 120
  • (integer) 1

上面介绍了两种设置过期时间的方法,它们都可以实现过期时间设置,key 过期后将自动被删除。

3) PEXPIREAT设置过期时间

以时间戳格式设置过期时间,并以毫秒为单位。

  • 127.0.0.1:6379> set www.biancheng.net Python
  • OK
  • 127.0.0.1:6379> PEXPIREAT www.biancheng.net 12000000000
  • (integer) 1

设置成功返回 1,若 key 不存在或者不能为其设置过期时间,则返回 0。

4) KEYS命令查找键

查找指定模式的键。

  • redis 127.0.0.1:6379> SET course1 redis
  • OK
  • redis 127.0.0.1:6379> SET course2 php
  • OK
  • redis 127.0.0.1:6379> SET course3 python
  • OK
  • 127.0.0.1:6379> keys course*
  • 1) "course1"
  • 2) "course2"
  • 3) "course3"
  • #获取所有key
  • 127.0.0.1:6379> keys *
  • 1) "course1"
  • 2) "course2"
  • 3) "course3"
  • 4) "num"
  • 5) "www.biancheng.net"

注意:keys * 会返回当前库中所有的键。

5) SCAN cursor

SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 否则将无法继续跌代。如果新游标返回 0 则表示迭代结束。

SCAN 命令的语法格式如下:

SCAN cursor [MATCH pattern] [COUNT count]

参数说明:

  • cursor :指定游标,从 0 开始新的迭代。
  • pattern:指定匹配的模式。
  • count:返回多少个元素,默认值为 10 。


SCAN 令可以迭代数据库中的所有键,如果想针对特定的数据类型迭代,那么命令自然也要做相应的变化。如下所示:

  • SSCAN 命令用于迭代集合键中的元素。
  • HSCAN 命令用于迭代哈希键中的键值对。
  • ZSCAN 命令用于迭代有序集合中的元素。


该命令的使用示例如下:

  • 127.0.0.1:6379> SCAN 0
  • 1) "3"
  • 2) 1) "name"
  • 2) "website"
  • 3) "biancheng2"
  • 4) "www.biancheng.net"
  • 5) "biancheng3"
  • 6) "biancheng1"
  • 7) "course2"
  • 8) "topic"
  • 9) "course1"
  • 10) "age"
  • 127.0.0.1:6379> SCAN 3
  • 1) "0"
  • 2) 1) "biancheng"
  • 2) "course3"
  • 3) "userid:1"
  • 4) "num"

6) TTL命令

在 key 设置过期时间的情况下,使用该命令检查 key 剩余的过期时间。

当键没有设置过期时间,表示是永久有效时,TTL 命令返回 -1;当键过期或者被删除时,TTL 命令返回 -2。示例如下:

127.0.0.1:6379> SET www.biancheng.net hello
OK
127.0.0.1:6379> ttl www.biancheng.net
(integer) -1
127.0.0.1:6379> SET user:1 Jack EX 120
OK
127.0.0.1:6379> TTL user:1
(integer) 108
127.0.0.1:6379> DEL user:1
(integer) 1
127.0.0.1:6379> TTL user:1
(integer) -2

Redis string字符串

常用命令

Redis字符串命令
命令说明
SET key value 用于设定指定键的值。
GET key 用于检索指定键的值。
GETRANGE key start end 返回 key 中字符串值的子字符。
GETSET key value 将给定 key 的值设置为 value,并返回 key 的旧值。
GETBIT key offset 对 key 所存储的字符串值,获取其指定偏移量上的位(bit)。
MGET key1 [key2..] 批量获取一个或多个 key 所存储的值,减少网络耗时开销。
SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
SETEX key seconds value 将值 value 存储到 key中 ,并将 key 的过期时间设为 seconds (以秒为单位)。
SETNX key value 当 key 不存在时设置 key 的值。
SETRANGE key offset value 从偏移量 offset 开始,使用指定的 value 覆盖的 key 所存储的部分字符串值。
STRLEN key 返回 key 所储存的字符串值的长度。
MSET key value [key value ...] 该命令允许同时设置多个键值对。
MSETNX key value [key value ...] 当指定的 key 都不存在时,用于设置多个键值对。
PSETEX key milliseconds value 此命令用于设置 key 的值和有过期时间(以毫秒为单位)。
INCR key 将 key 所存储的整数值加 1。
INCRBY key increment 将 key 所储存的值加上给定的递增值(increment)。
INCRBYFLOAT key increment 将 key 所储存的值加上指定的浮点递增值(increment)。
DECR key 将 key 所存储的整数值减 1。
DECRBY key decrement 将 key 所储存的值减去给定的递减值(decrement)。
APPEND key value 该命令将 value 追加到 key 所存储值的末尾。


Redis string 的SET/GET命令只能一次设置/查询一个键值对,这样虽然简单,但是效率不高。为了提高命令的执行效率,Redis 提供了可以批量操作多个字符串的读写命令 MSET/MGET(“M”代表“Many”),它们允许你一次性设置或查询多个键值对,这样就有效地减少了网络耗时。

简单命令演示

下面对常用命令做简单演示:

1) GETRANGE命令

GETRANGE 命令用于截取一定长度的  value,并返回截取后的新值。语法格式如下:

redis 127.0.0.1:6379> GETRANGE KEY_NAME start end

注意,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内的闭区间)

示例如下:

127.0.0.1:6379> SET website www.biancheng.net
OK
#索引值
127.0.0.1:6379> GETRANGE website 0 4
"www.b"
#使用负数索引
127.0.0.1:6379> GETRANGE website 0 -1
"www.biancheng.net"
127.0.0.1:6379>

2) GETSET命令

GETSET 命令用于重新设置 value 值,并返回之前旧 value。示例如下:

127.0.0.1:6379> GETSET num first
"6"
127.0.0.1:6379> GETSET num second
"first"
#查看长度值
127.0.0.1:6379> strlen num
(integer) 6

注意:num 之前存储的值为“6”,所以结果返回“6”。

3) SETEX命令

将值 value 存储到 key 中 ,并将 key 的过期时间设为 seconds (以秒为单位)。示例如下:

#设置过期时间为60s
127.0.0.1:6379> SETEX www.biancheng.net 60 hello
OK
#查看过期时间
127.0.0.1:6379> ttl www.biancheng.net
(integer) 5

4) MSETNX命令

该命令了类似于 MSET 命令,但是它仅当指定的 key 不存在时才能够执行成功,用于同时设置多个键值对。示例如下:

#返回0,说明命令执行失败
127.0.0.1:6379> MSETNX www.biancheng.net hello title world
(integer) 0
#删除重复的键
127.0.0.1:6379> del www.biancheng.net
(integer) 1
#重新执行
127.0.0.1:6379> MSETNX www.biancheng.net hello title world
(integer) 1

由于 key 之前已经存在,所以第一次执行失败,当删除存在的后,命令就会执行成功。

5) SETRANGE命令

该命令使用指定的字符在给定的范围内覆盖 key 对应的 value ,其语法格式如下:

redis 127.0.0.1:6379> SETRANGE KEY_NAME OFFSET VALUE
  • KEY_NAME:指 key 的名字;
  • OFFSET:指初始偏移量;
  • VALUE:指要替换成的字符串。 

示例如下: 

127.0.0.1:6379> SET word "hello world"
OK
127.0.0.1:6379> SETRANGE word 6 www.biancheng.net
(integer) 23
127.0.0.1:6379> GET word
"hello www.biancheng.net"

Redis bitmap位图操作(图解)

在平时开发过程中,经常会有一些 bool 类型数据需要存取。比如记录用户一年内签到的次数,签了是 1,没签是 0。如果使用 key-value 来存储,那么每个用户都要记录 365 次,当用户成百上亿时,需要的存储空间将非常巨大。为了解决这个问题,Redis 提供了位图结构。

位图(bitmap)同样属于 string 数据类型。Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,这大大增加了 value 存储数量,它存储上限为2^32 

位图本质上就是一个普通的字节串,也就是 bytes 数组。您可以使用getbit/setbit命令来处理这个位数组,位图的结构如下所示:

位数组


位图适用于一些特定的应用场景,比如用户签到次数、或者登录次数等。上图是表示一位用户 10 天内来网站的签到次数,1 代表签到,0 代表未签到,这样可以很轻松地统计出用户的活跃程度。相比于直接使用字符串而言,位图中的每一条记录仅占用一个 bit 位,从而大大降低了内存空间使用率。

Redis 官方也做了一个实验,他们模拟了一个拥有 1 亿 2 千 8 百万用户的系统,然后使用 Redis 的位图来统计“日均用户数量”,最终所用时间的约为 50ms,且仅仅占用  16 MB内存。

位图应用原理

某网站要统计一个用户一年的签到记录,若用 sring 类型存储,则需要 365 个键值对。若使用位图存储,用户签到就存 1,否则存 0。最后会生成 11010101... 这样的存储结果,其中每天的记录只占一位,一年就是 365 位,约为 46 个字节。如果只想统计用户签到的天数,那么统计 1 的个数即可。

位图操作的优势,相比于字符串而言,它不仅效率高,而且还非常的节省空间。

Redis  的位数组是自动扩展的,如果设置了某个偏移位置超出了现有的内容范围,位数组就会自动扩充。

下面设置一个名为 a 的 key,我们对这个 key 进行位图操作,使得 a 的对应的 value 变为“he”。

首先我们分别获取字符“h”和字符“e”的八位二进制码,如下所示:

>>> bin(ord("h"))
'0b1101000'
>>> bin(ord("e"))
'0b1100101'

接下来,只要对需值为 1 的位进行操作即可。如下图所示:

bitmap位图应用


把 h 和 e 的二进制码连接在一起,第一位的下标是 0,依次递增至 15,然后将数字为 1 的位置标记出来,得到 1/2/4/9/10/13/15,我们把这组数字称为位的“偏置数”,最后按照上述偏置数对字符 a 进行如下位图操作。注意,key 的初始二进制位全部为 0。

C:\Users\Administrator>redis-cli
127.0.0.1:6379> SETBIT a 1 1
(integer) 0
127.0.0.1:6379> SETBIT a 2 1
(integer) 0
127.0.0.1:6379> SETBIT a 4 1
(integer) 0
127.0.0.1:6379> get hello
"h"
127.0.0.1:6379> SETBIT a 9 1
(integer) 0
127.0.0.1:6379> SETBIT a 10 1
(integer) 0
127.0.0.1:6379> SETBIT a 13 1
(integer) 0
127.0.0.1:6379> SETBIT a 15 1
(integer) 0
127.0.0.1:6379> get hello
"he"

从上述示例可以得出,位图操作会自动对 key 进行扩容。

如果对应位的字节是不可以被打印的,那么 Redis 会以该字符的十六进制数来表示它,如下所示:

127.0.0.1:6379> SETBIT b 0 1
(integer) 0
127.0.0.1:6379> SETBIT b 1 1
(integer) 0
127.0.0.1:6379> get b
"\xc0"

位图常用命令

1) SETBIT命令

用来设置或者清除某一位上的值,其返回值是原来位上存储的值。key 在初始状态下所有的位都为 0 ,语法格式如下:

SETBIT key offset value

其中 offset 表示偏移量,从 0 开始。示例如下:

127.0.0.1:6379> SET user:1 a
OK
#设置偏移量为0
127.0.0.1:6379> SETBIT user:1 0 1
(integer) 0
#当对应位的字符是不可打印字符,redis会以16进制形式显示
127.0.0.1:6379> GET user:1
"\xe1"

2) GETBIT命令

用来获取某一位上的值。示例如下:

127.0.0.1:6379> GETBIT user:1 0
(integer) 1

当偏移量 offset 比字符串的长度大,或者当 key 不存在时,返回 0。

redis> EXISTS bits
(integer) 0
redis> GETBIT bits 100000
(integer) 0

3) BITCOUNT命令

统计指定位区间上,值为 1 的个数。语法格式如下:

BITCOUNT key [start end]

示例如下:

127.0.0.1:6379> BITCOUNT user:1
(integer) 8

通过指定的 start 和 end 参数,可以让计数只在特定的字节上进行。start 和 end 参数和 GETRANGE 命令的参数类似,都可以使用负数,比如 -1 表示倒数第一个位, -2 表示倒数第二个位。

Redis INCR数值操作命令

Redis string 类型提供了一些专门操作数值的命令,比如 INCRBY(自增)、DECRBR(自减)、INCR(加1) 和 DECR(减1) 等命令。数值操作,同样有特定的应用场景,比如常见的点赞、取消点赞、关注、取消关注等,这类和计数相关的场景都可以使用数值操作来实现。

注意:此时  key 对应的 value 值是必须是一个整数,或浮点数,使用命令对这个数值进行自增或自减操作。当然,这个数值也不能无限的增大或减小, Redis 规定的数值范围是 -9223372036854775808 至 9223372036854775807,如果超过了这个数值范围,Redis 就会报错。

常用命令

1) INCR命令

INCR 命令指对 value 数值做加 1 操作,其数值范围是 64 位的有符号整型(-9223372036854775808 至 9223372036854775807)。

如果 key 不存在,那么 Redis 将自动创建 key,并将 value 初始化为 1。以下示例,自动创建一个记录粉丝数量的 key,也就是 fans:num。

自动创建key,并将值置为 "1"
127.0.0.1:6379> INCR fans:num
(integer) 1
#粉丝数量加1
127.0.0.1:6379> get fans:num
"1"

2) DECR命令

该命令与 INCR 命令相反,它对数值执行减 1 操作。

粉丝取消了关注
127.0.0.1:6379> DECR fans:num
(integer) 0
#取消关注,恢复为0粉丝
127.0.0.1:6379> get fans:num
"0"

3) INCRBY命令

与 INCR 命令类似,不过该命令不是加 1 操作,它表示在原数的基础上进行指定数值的自增运算,语法格式如下:

INCRBY key increment  

其中 increment 表示指定增量值。示例如下:粉丝数每次增加 3 个。

127.0.0.1:6379> INCRBY fans:num 3
(integer) 3
127.0.0.1:6379> INCRBY fans:num 5
(integer) 8
127.0.0.1:6379> INCRBY fans:num 10
(integer) 18

4) DECRBY命令

该命名与 INCRBY 命令相反,它表示在原数值的基础上进行指定数值的自减运算。

INCRBY key decrement  

其中 decrement 指定递减的步长。示例如下:

原来粉丝数是18,执行自减操作
127.0.0.1:6379> DECRBY fans:num 2
(integer) 16
127.0.0.1:6379> DECRBY fans:num 4
(integer) 12
127.0.0.1:6379> DECRBY fans:num 8
(integer) 4
127.0.0.1:6379> DECRBY fans:num 84
(integer) -80

5) INCRBYFLOAT

该命令是 string 中唯一操作浮点数的命令,浮点数可以为正数或者负数,从而实现对数值的加减操作。示例如下:

127.0.0.1:6379> INCRBY fans:num 10
(integer) -70
127.0.0.1:6379> INCRBY fans:num 100
(integer) 30
127.0.0.1:6379> INCRBYFLOAT fans:num 1.5
"31.5"
127.0.0.1:6379> INCRBYFLOAT fans:num -10.5
"21"

redis list列表

常用命令

list类型常用命令
命令说明
LPUSH key value1 [value2] 在列表头部插入一个或者多个值。
LRANGE key start stop 获取列表指定范围内的元素。
RPUSH key value1 [value2] 在列表尾部添加一个或多个值。
LPUSHX key value 当储存列表的 key 存在时,用于将值插入到列表头部。
RPUSHX key value 当存储列表的 key 存在时,用于将值插入到列表的尾部。
LINDEX key index 通过索引获取列表中的元素。
LINSERT key before|after pivot value 指定列表中一个元素在它之前或之后插入另外一个元素。
LREM key count value 表示从列表中删除元素与 value 相等的元素。count 表示删除的数量,为 0 表示全部移除。
LSET key index value 表示通过其索引设置列表中元素的值。
LTRIM key start stop 保留列表中指定范围内的元素值。
LPOP key 从列表的头部弹出元素,默认为第一个元素。
RPOP key 从列表的尾部弹出元素,默认为最后一个元素。
LLEN key 用于获取列表的长度。
RPOPLPUSH source destination 用于删除列表中的最后一个元素,然后将该元素添加到另一个列表的头部,并返回该元素值。
BLPOP key1 [key2 ] timeout 用于删除并返回列表中的第一个元素(头部操作),如果列表中没有元素,就会发生阻塞,
直到列表等待超时或发现可弹出元素为止。
BRPOP key1 [key2 ] timeout 用于删除并返回列表中的最后一个元素(尾部操作),如果列表中没有元素,就会发生阻塞, 直到列表等待超时或发现可弹出元素为止。
BRPOPLPUSH source destination timeout 从列表中取出最后一个元素,并插入到另一个列表的头部。如果列表中没有元素,就会发生
阻塞,直到等待超时或发现可弹出元素时为止。


在线练习工具:https://try.redis.io/

Redis hash哈希散列(图解)

常用命令汇总

hash常用命令汇总
命令说明
HDEL key field2 [field2] 用于删除一个或多个哈希表字段。
HEXISTS key field  用于确定哈希表字段是否存在。
HGET key field 获取 key 关联的哈希字段的值。
HGETALL key 获取 key 关联的所有哈希字段值。
HINCRBY key field increment 给 key 关联的哈希字段做整数增量运算 。
HINCRBYFLOAT key field increment  给 key 关联的哈希字段做浮点数增量运算 。
HKEYS key 获取 key 关联的所有字段和值。
HLEN key 获取 key 中的哈希表的字段数量。
HMSET key field1 value1 [field2 value2 ] 在哈希表中同时设置多个 field-value(字段-值)
HMGET key field1 [field2] 用于同时获取多个给定哈希字段(field)对应的值。
HSET key field value 用于设置指定 key 的哈希表字段和值(field/value)。
HSETNX key field value 仅当字段 field 不存在时,设置哈希表字段的值。
HVALS key 用于获取哈希表中的所有值。
HSCAN key cursor  迭代哈希表中的所有键值对,cursor 表示游标,默认为 0。

Redis set集合

set类型常用命令
命令说明
SADD key member1 [member2] 向集合中添加一个或者多个元素,并且自动去重。
SCARD key 返回集合中元素的个数。
SDIFF key1 [key2] 求两个或多个集合的差集。
SDIFFSTORE destination key1 [key2] 求两个集合或多个集合的差集,并将结果保存到指定的集合中。
SINTER key1 [key2] 求两个或多个集合的交集。
SINTERSTORE destination key1 [key2] 求两个或多个集合的交集,并将结果保存到指定的集合中。
SISMEMBER key member 查看指定元素是否存在于集合中。
SMEMBERS key 查看集合中所有元素。
SMOVE source destination member 将集合中的元素移动到指定的集合中。
SPOP key [count] 弹出指定数量的元素。
SRANDMEMBER key [count] 随机从集合中返回指定数量的元素,默认返回 1个。
SREM key member1 [member2] 删除一个或者多个元素,若元素不存在则自动忽略。
SUNION key1 [key2] 求两个或者多个集合的并集。
SUNIONSTORE destination key1 [key2] 求两个或者多个集合的并集,并将结果保存到指定的集合中。
SSCAN key cursor [match pattern] [count count] 该命令用来迭代的集合中的元素。

Redis zset有序集合(底层原理+图解)

有序集合常用命令
命令说明
ZADD key score1 member1 [score2 member2] 用于将一个或多个成员添加到有序集合中,或者更新已存在成员的 score 值
ZCARD key 获取有序集合中成员的数量
ZCOUNT key min max 用于统计有序集合中指定 score 值范围内的元素个数。
ZINCRBY key increment member 用于增加有序集合中成员的分值。
ZINTERSTORE destination numkeys key [key ...] 求两个或者多个有序集合的交集,并将所得结果存储在新的 key 中。
ZLEXCOUNT key min max 当成员分数相同时,计算有序集合中在指定词典范围内的成员的数量。
ZRANGE key start stop [WITHSCORES] 返回有序集合中指定索引区间内的成员数量。
ZRANGEBYLEX key min max [LIMIT offset count] 返回有序集中指定字典区间内的成员数量。
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 返回有序集合中指定分数区间内的成员。
ZRANK key member 返回有序集合中指定成员的排名。
ZREM key member [member ...] 移除有序集合中的一个或多个成员。
ZREMRANGEBYLEX key min max 移除有序集合中指定字典区间的所有成员。
ZREMRANGEBYRANK key start stop 移除有序集合中指定排名区间内的所有成员。
ZREMRANGEBYSCORE key min max 移除有序集合中指定分数区间内的所有成员。
ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定区间内的成员,通过索引,分数从高到低。
ZREVRANGEBYSCORE key max min [WITHSCORES] 返回有序集中指定分数区间内的成员,分数从高到低排序。
ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序。
ZSCORE key member 返回有序集中,指定成员的分数值。
ZUNIONSTORE destination numkeys key [key ...] 求两个或多个有序集合的并集,并将返回结果存储在新的 key 中。
ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值)。

Redis连接命令详解

Redis连接命令

Redis 连接命令是主要用于验证 Redis 服务器的连接状态,比如验证客户端与 Redis 服务器是否连接成功,以及检查服务器运行状态,以及是否断开当前连接等。

我们知道,只有当客户端与服务器正常连接后才能够实现彼此的交互、通信。Redis 通过“Redis序列化协议”(简称“RESP”),实现客户端与服务端之间的连接通信,该协议主要包括两个部分:网络模型和序列化协议。

    • 网络模型主要负责数据交互的组织方式;
    • 序列化协议则实现了数据的序列化; 
命令说明
AUTH password 验证密码是否正确
ECHO message 打印字符串
PING 查看服务是否运行正常
QUIT 关闭当前连接
SELECT index 切换到指定的数据库

Redis安全策略

Redis 提供了诸多安全策略,比如为了保证数据安全,提供了设置密码的功能。Redis 密码设置主要有两种方式:一种是使用CINFIG命令来设置密码;另外一种则是手动修改 Redis 的配置文件。虽然看似前者更为简单,其实两种方式各有特点。本节将对它们进行介绍。

命令配置密码

通过执行以下命令查看是否设置了密码验证:

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

在默认情况下 requirepass 参数值为空的,表示无需通过密码验证就可以连接到 Redis 服务。

下面执行以下命令设置密码。如下所示:

127.0.0.1:6379> CONFIG set requirepass "www.biancheng.net"
OK
127.0.0.1:6379> CONFIG get requirepass
1) "requirepass"
2) "www.biancheng.net"

执行完上述操作后,客户端要连接到 Redis 服务就需要密码验证,如果不验证就无法操作 Redis 数据库。如下所示:

127.0.0.1:6379> set key name www.biancheng.net
#报错无法操作
(error) NOAUTH Authentication required.

使用AUTH命令验证密码:

127.0.0.1:6379> AUTH www.biancheng.net
OK
#执行命令成功
127.0.0.1:6379> SET name www.biancheng.net
OK
127.0.0.1:6379> GET name
www.biancheng.net

注意:通过命令行设置的密码并非永久有效,当您重启服务后密码就会失效,所以一般不采用这种方式。下面介绍一种永久有效的修改方式,也就是手动配置密码。

手动配置密码

手动修改配置密码也非常的简单,首先,您要在 Redis 的安装目录中找到 redis.windows.conf 配置文件,然后打开该文件,并使用 Ctrl+F 搜索 requirepass 关键字,找到配置项并配置密码,如下所示:

# requirepass foobared
requirepass www.biancheng.net //配置自己的密码

然后使用更改后的配置文件重启服务器,依次执行以下命令:

#首先停止服务:
C:\Users\Administrator>redis-server.exe --service-stop
#重启服务器
C:\Users\Administrator>redis-server.exe --service-start
#重新登陆
C:\Users\Administrator>redis-cli.exe -h 127.0.0.1 -p 6379 -a www.biancheng.net
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 requirepass
1)"requirepass"
2)"www.biancheng.net"

手动配置无须验证密码,只需要重新启动 Redis 服务器。这种配置方式,密码永远有效。如果想取消密码设置,您需要将配置文件更改回原来的状态,然后再次重启服务器,即可取消。

除了需要为 Redis 配置密码外,我们在使用 Redis 时也需要注意一些常见的安全风险以及防范措施,从而避免数据泄露和丢失,以及人为操作失误等。

指令安全

Redis 有一些非常危险的命令,这些命令会对 Redis 的稳定以及数据安全造成非常严重的影响。比如 keys 指令会导致 Redis 卡顿,而 flushdb 和 flushall 会让 Redis 的所有数据全部清空。那么如何避免这些操作失误带来的灾难性后果呢?

Redis 在配置文件中提供了 rename-command 指令用于将某些危险的指令修改成特别的名称,用来避免人为误操作。比如在配置文件的 security 模块增加以下内容:

rename-command keys 123keys123

如果您还想执行 keys 命令,那就需要在命令行输入123keys123。 当然也可以将指令 rename 成空字符串,这样就无法通过字符串来执行 keys 命令了。

rename-command flushall ""

端口安全

Redis 默认监听*:6379,如果当前的服务器主机有外网地址,那么 Redis 的服务将会直接暴露在公网上,别有用心的人使用适当的探测工具就可以对 IP 地址进行端口扫描,从而威胁您的系统安全。

如果 Redis 的服务地址一旦可以被外网直接访问,其内部数据就彻底丧失了安全性。黑客们可以通过 Redis 执行 Lua 脚本拿到服务器权限,然后清空您的 Redis 数据库。因此务必在 Redis 的配置文件中绑定要监听的 IP 地址,避免类似的情况发生。如下所示:

bind 193.168.1.1 #绑定外网ip地址

不仅如此,还可以增加 Redis 的密码访问限制,客户端必须使用 auth 命令传入正确的密码才可以访问 Redis。

requirepass yourspassword

这样即使地址暴露出去了,普通黑客也无法对 Redis 服务器进行任何指令操作。

密码配置也会影响到主从复制。要求从机必须配置与主服务相同的密码才可以进行主从复制。

masterauth yourspassword

Redis客户端(client)命令

Redis IO多路复用

Redis 的底层是一个单线程模型,单线程指的是使用一个线程来处理所有的网络事件请求,这样就避免了多进程或者多线程切换导致的 CPU 消耗,而且也不用考虑各种锁的问题。

Redis 为了充分利用单线程,加快服务器的处理速度,它采用 IO 多路复用模型来处理客户端与服务端的连接,这种模型有三种实现方式,分别是 select、poll、epoll。Redis 正是采用 epoll 的方式来监控多个 IO 事件。当客户端空闲时,线程处于阻塞状态;当一个或多个 IO 事件触发时(客户端发起网路连接请求),线程就会从阻塞状态唤醒,并同时使用epoll来轮询触发事件,并依次提交给线程处理。

注意:“多路”指的是多个网络连接,“复用”指的是复用同一个线程。多路 IO 复用技术可以让单个线程高效的处理多个连接请求。

Redis 提供了一些操作客户端(client)的命令,比如查询所有已连接到服务器的客户端数量,控制客户端的连接状态(关闭或者挂起)等。通过客户命令我们可以轻松的实现对客户端的管理、控制。

Redis 服务器通过监听 TCP 端口的方式来接受客户端的连接。当一个连接建立后,Redis 会自动执行以下过程:

  • 首先客户端 socket 被设置为非阻塞模式,这是因为 Redis 在网络事件处理上采用了非阻塞式 IO(即 IO 多路复用模型);
  • 其次设置 socket 的 TCP_NODELAY 属性,从而禁用 Nagle 算法;
  • 最后创建一个可读的文件事件,用它来监听客户端 socket 的数据发送。


Redis 使用命令的格式向客户端输入数据,这个数据量是非常小的。当向客户端输入命令后,我们希望能快速的得到服务器的应答,也就是低延时性,但如果开启了Nagle算法就会出现频繁延时的现象,导致用户体验极差。

常用命令

客户端常用命令
命令说明
CLIENT LIST 以列表的形式返回所有连接到 Redis 服务器的客户端。
CLIENT SETNAME 设置当前连接的名称。
CLIENT GETNAME 获取通过 CLIENT SETNAME 命令设置的服务名称。
CLIENT PAUSE 挂起客户端连接,将所有客户端挂起指定的时间(以毫秒为计算)。
CLIENT KILL 关闭客户端连接。
CLIENT ID 返回当前客户端 ID。
CLIENT REPLY 控制发送到当前连接的回复,可选值包括 on|off|skip。

Redis服务器命令

Redis 服务器是对客户端提供服务的主体,只要是安装了 Redis 数据库的计算机都可以通过本地,或者远程的方式对外提供服务。

Redis 服务器能够以高可用集群的方式对外提供服务。所谓高可用集群,指的是多台 Redis 服务器组成的服务器架构,每台服务器都提供相同的服务,从而让服务器达到一个稳定,高效的运行状态。有关 Redis 集群的相关知识在后续内容中详介绍。

从 3.0 版本开始,Redis 已经实现了对 Redis-cluster 集群部署的支持。

Redis 提供了诸多操作服务器的命令,这些命令都有着各自重要的作用,比如BGSAVE命令,用异步的方式将 Redis 数据库的数据同步到本地磁盘中,实现数据的持久化存储,这对服务器的数据安全有着重要的作用。下表介绍了 Redis 服务器的常用命令:

Redis服务器命令
命令说明
BGREWRITEAOF 在后台以异步的方式执行一个 AOF 文件的重写操作,对源文件进行压缩,使其体积变小。
AOF 是实现数据持久化存储的方式之一。
BGSAVE 在后台执行初始化操作,并以异步的方式将当前数据库的数据保存到磁盘中。
CLIENT KILL [ip:port] [ID client-id] 关闭客户端连接。
CLIENT LIST 获取连接到服务器的客户端连接列表。
CLIENT GETNAME 获取当前连接客户端的名称。
CLIENT PAUSE timeout 使服务器在指定的时间停止执行来自客户端的命令。
CLIENT SETNAME connection-name 设置当前连接客户端的名称。
COMMAND 返回所有 Redis 命令的详细描述信息。
COMMAND COUNT 此命令用于获取 Redis 命令的总数。
COMMAND GETKEYS 获取指定命令的所有键。
INFO [section] 获取 Redis 服务器的各种信息和统计数值。
COMMAND INFO command-name [command-name ...] 用于获取指定 Redis 命令的描述信息。
CONFIG GET parameter 获取指定配置参数的值。
CONFIG REWRITE 修改启动 Redis 服务器时所指定的 redis.conf 配置文件。
CONFIG SET parameter value 修改 Redis 配置参数,无需重启。
CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据。
DBSIZE 返回当前数据库中 key 的数量。
DEBUG OBJECT key 获取 key 的调试信息。当 key 存在时,返回有关信息;当 key 不存在时,返回一个错误。
DEBUG SEGFAULT 使用此命令可以让服务器崩溃。
FLUSHALL 清空数据库中的所有键。
FLUSHDB 清空当前数据库的所有 key。
LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 格式表示。
MONITOR 实时打印出 Redis 服务器接收到的命令。
ROLE 查看主从实例所属的角色,角色包括三种,分别是 master、slave、sentinel。
SAVE 执行数据同步操作,将 Redis 数据库中的所有数据以 RDB 文件的形式保存到磁盘中。
RDB 是 Redis 中的一种数据持久化方式。
SHUTDOWN [NOSAVE] [SAVE] 将数据同步到磁盘后,然后关闭服务器。
SLAVEOF host port 此命令用于设置主从服务器,使当前服务器转变成为指定服务器的从属服务器,
或者将其提升为主服务器(执行 SLAVEOF NO ONE 命令)。
SLOWLOG subcommand [argument] 用来记录查询执行时间的日志系统。
SYNC 用于同步主从服务器。
SWAPDB index index 用于交换同一 Redis 服务器上的两个数据库,可以实现访问其中一个数据库的客户端连接,也可以立即访问另外一个数据库的数据。
TIME 此命令用于返回当前服务器时间。

注意:上述一些命令在后续内容还会做相应介绍,比如 Redis 主从服务器设置,以及 Redis 数据持久化等。

Redis HyperLoglog基数统计

Redis 经常使用的数据类型有字符串、列表、散列、集合和有序集合,但这些类型并不能满足所有的应用场景,因此,Redis 的后续版本不断的扩增其他数据类型来增强 Redis 适用能力。在 Redis 2.8.9 版本中新增了 HyperLogLog 类型。

什么是HyperLoglog

HyperLoglog 是 Redis 重要的数据类型之一,它非常适用于海量数据的计算、统计,其特点是占用空间小,计算速度快。

HyperLoglog 采用了一种基数估计算法,因此,最终得到的结果会存在一定范围的误差(标准误差为 0.81%)。每个 HyperLogLog key 只占用 12 KB 内存,所以理论上可以存储大约2^64个值,而 set(集合)则是元素越多占用的内存就越多,两者形成了鲜明的对比 。

HyperLoglog 使用起来较为方便,但是其内部原理较为复杂,不建议大家深入研究,只要会用即可。

基数定义

基数定义:一个集合中不重复的元素个数就表示该集合的基数,比如集合 {1,2,3,1,2} ,它的基数集合为 {1,2,3} ,所以基数为 3。HyperLogLog 正是通过基数估计算法来统计输入元素的基数。

HyperLoglog 不会储存元素值本身,因此,它不能像 set 那样,可以返回具体的元素值。HyperLoglog 只记录元素的数量,并使用基数估计算法,快速地计算出集合的基数是多少。

场景应用

HyperLogLog 也有一些特定的使用场景,它最典型的应用场景就是统计网站用户月活量,或者网站页面的 UV(网站独立访客)数据等。

UV 与 PV(页面浏览量) 不同,UV 需要去重,同一个用户一天之内的多次访问只能计数一次。这就要求用户的每一次访问都要带上自身的用户 ID,无论是登陆用户还是未登陆用户都需要一个唯一 ID 来标识。

当一个网站拥有巨大的用户访问量时,我们可以使用 Redis 的 HyperLogLog 来统计网站的 UV (网站独立访客)数据,它提供的去重计数方案,虽说不精确,但 0.81% 的误差足以满足 UV 统计的需求。

常用命令

HyperLoglog命令
命令说明
PFADD key element [element ...] 添加指定元素到 HyperLogLog key 中。
PFCOUNT key [key ...] 返回指定 HyperLogLog key 的基数估算值。
PFMERGE destkey sourcekey [sourcekey ...] 将多个 HyperLogLog key 合并为一个 key。
 

基本命令

HyperLogLog 提供了三个常用命令,分别是PFADDPFCOUNTPFMERGE

下面看一组实例演示:假设有 6 个用户(user01-user06),他们分别在上午 8 与 9 点访问了www.biancheng.netC语言中文网。

#向指定的key中添加用户
127.0.0.1:6379> PFADD user:uv:2021011308 user01 user02 user03
(integer) 1
#向指定的key中添加用户
127.0.0.1:6379> PFADD user:uv:2021011309 user04 user05
(integer) 1
#统计基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer) 3
#重复元素不能添加成功,其基数仍然为3
127.0.0.1:6379> PFADD user:uv:2021011308 user01 user02
(integer) 0
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer) 3
#添加新元素值
127.0.0.1:6379> PFADD user:uv:2021011308 user06
(integer) 1
#基数值变为4
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer) 4
#统计两个key的基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308 user:uv:2021011309
(integer) 6
#将两个key值合并为一个
127.0.0.1:6379> PFMERGE user:uv:2021011308-09 user:uv:2021011308 user:uv:2021011309
OK
#使用合并后key统计基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308-09
(integer) 6

Redis PubSub发布订阅(详细图解)

发布/订阅流程

下面的示例演示了“发布/订阅者”模式的工作流程,示意图如下所示:

1) 订阅者/等待接收消息

首先打开 Redis 客户端,然后订阅了一个名为“www.biancheng.net”的 channel,使用如下命令:

#订阅channel
127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "www.biancheng.net"
3) (integer) 1 

上述示例使用SUBSCRIBE命令订阅了名为 www.biancheng.net 的 channel。命令执行后该客户端会出处于等待接收消息的阻塞状态。

2) 发布者/发送消息

下面再启动一个 Redis 客户端,输入如下命令:

127.0.0.1:6379> PUBLISH www.biancheng.net "this is website"
(integer) 1
127.0.0.1:6379> PUBLISH www.biancheng.net "hello world"
(integer) 1
127.0.0.1:6379> PUBLISH www.biancheng.net "how are you"
(integer) 1

通过上述PUBLISH命令发布了三条信息。现在两个客户端在处于同一个名为“www.biancheng.net”的频道上,前者负责接收消息,后者负责发布消息。

3) 订阅者/成功接收消息

完成了上述操作后,您会在接收消息的客户端得到如下输出结果:

127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "www.biancheng.net"
3) (integer) 1
1) "message"
2) "www.biancheng.net"
Redis PubSub常用命令
命令说明
PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合指定模式的频道。
PUBSUB subcommand [argument [argument ...]] 查看发布/订阅系统状态,可选参数
1) channel 返回在线状态的频道。
2) numpat 返回指定模式的订阅者数量。
3) numsub 返回指定频道的订阅者数量。
PUBSUB subcommand [argument [argument ...]] 将信息发送到指定的频道。
PUNSUBSCRIBE [pattern [pattern ...]] 退订所有指定模式的频道。
SUBSCRIBE channel [channel ...] 订阅一个或者多个频道的消息。
UNSUBSCRIBE [channel [channel ...]] 退订指定的频道。

 

Redis Stream消息队列

什么是Stream?

Stream 实际上是一个具有消息发布/订阅功能的组件,也就常说的消息队列。其实这种类似于 broker/consumer(生产者/消费者)的数据结构很常见,比如 RabbitMQ 消息中间件、Celery 消息中间件,以及 Kafka 分布式消息系统等,而 Redis Stream 正是借鉴了 Kafaka 系统。

1) 优点

Strean 除了拥有很高的性能和内存利用率外, 它最大的特点就是提供了消息的持久化存储,以及主从复制功能,从而解决了网络断开、Redis 宕机情况下,消息丢失的问题,即便是重启 Redis,存储的内容也会存在。

2) 流程

Stream 消息队列主要由四部分组成,分别是:消息本身、生产者、消费者和消费组,对于前述三者很好理解,下面了解什么是消费组。

一个 Stream 队列可以拥有多个消费组,每个消费组中又包含了多个消费者,组内消费者之间存在竞争关系。当某个消费者消费了一条消息时,同组消费者,都不会再次消费这条消息。被消费的消息 ID 会被放入等待处理的 Pending_ids 中。每消费完一条信息,消费组的游标就会向前移动一位,组内消费者就继续去争抢下消息。

Redis Stream 消息队列结构程如下图所示:

下面对上图涉及的专有名词做简单解释:

  • Stream direction:表示数据流,它是一个消息链,将所有的消息都串起来,每个消息都有一个唯一标识 ID 和对应的消息内容(Message content)。
  • Consumer Group :表示消费组,拥有唯一的组名,使用 XGROUP CREATE 命令创建。一个 Stream 消息链上可以有多个消费组,一个消费组内拥有多个消费者,每一个消费者也有一个唯一的 ID 标识。
  • last_delivered_id :表示消费组游标,每个消费组都会有一个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
  • pending_ids :Redis 官方称为 PEL,表示消费者的状态变量,它记录了当前已经被客户端读取的消息 ID,但是这些消息没有被 ACK(确认字符)。如果客户端没有 ACK,那么这个变量中的消息 ID 会越来越多,一旦被某个消息被 ACK,它就开始减少。

3) ACK 

ACK(Acknowledge character)即确认字符,在数据通信中,接收方传递给发送方的一种传输类控制字符。表示发来的数据已确认接收无误。在 TCP/IP 协议中,如果接收方成功的接收到数据,那么会回复一个 ACK 数据。通常 ACK 信号有自己固定的格式,长度大小,由接收方回复给发送方。

常用命令汇总

Redis Stream命令
命令说明
XADD  添加消息到末尾。
XTRIM 对 Stream 流进行修剪,限制长度。
XDEL 删除指定的消息。
XLEN 获取流包含的元素数量,即消息长度。
XRANGE 获取消息列表,会自动过滤已经删除的消息。
XREVRANGE  反向获取消息列表,ID 从大到小。
XREAD 以阻塞或非阻塞方式获取消息列表。
XGROUP CREATE 创建消费者组。
XREADGROUP GROUP 读取消费者组中的消息。
XACK 将消息标记为"已处理"。
XGROUP SETID 为消费者组设置新的最后递送消息ID。
XGROUP DELCONSUMER 删除消费者。
XGROUP DESTROY 删除消费者组。
XPENDING 显示待处理消息的相关信息。
XCLAIM  转移消息的归属权。
XINFO 查看 Stream 流、消费者和消费者组的相关信息。
XINFO GROUPS 查看消费者组的信息。
XINFO STREAM  查看 Stream 流信息。
XINFO CONSUMERS key group 查看组内消费者流信息。

Redis布隆过滤器(原理+图解)

安装与使用

布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,它被作为插件加载到 Redis 服务器中,给 Redis 提供强大的去重功能。

相比于 Set 集合的去重功能而言,布隆过滤器在空间上能节省 90% 以上,但是它的不足之处是去重率大约在 99% 左右,也就是说有 1% 左右的误判率,这种误差是由布隆过滤器的自身结构决定的。俗话说“鱼与熊掌不可兼得”,如果想要节省空间,就需要牺牲 1% 的误判率,而且这种误判率,在处理海量数据时,几乎可以忽略。

应用场景

布隆过滤器是 Redis 的高级功能,虽然这种结构的去重率并不完全精确,但和其他结构一样都有特定的应用场景,比如当处理海量数据时,就可以使用布隆过滤器实现去重。

下面举两个简单的例子:

1) 示例:

百度爬虫系统每天会面临海量的 URL 数据,我们希望它每次只爬取最新的页面,而对于没有更新过的页面则不爬取,因策爬虫系统必须对已经抓取过的 URL 去重,否则会严重影响执行效率。但是如果使用一个 set(集合)去装载这些 URL 地址,那么将造成资源空间的严重浪费。

2) 示例:

垃圾邮件过滤功能也采用了布隆过滤器。虽然在过滤的过程中,布隆过滤器会存在一定的误判,但比较于牺牲宝贵的性能和空间来说,这一点误判是微不足道的。

工作原理

布隆过滤器(Bloom Filter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机映射函数(即哈希函数)两部分组成。

布隆过滤器使用exists()来判断某个元素是否存在于自身结构中。当布隆过滤器判定某个值存在时,其实这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在,这个误判概率大约在 1% 左右。

1) 工作流程-添加元素

布隆过滤器主要由位数组和一系列 hash 函数构成,其中位数组的初始状态都为 0。

下面对布隆过滤器工作流程做简单描述,如下图所示:

 

 

 


当使用布隆过滤器添加 key 时,会使用不同的 hash 函数对 key 存储的元素值进行哈希计算,从而会得到多个哈希值。根据哈希值计算出一个整数索引值,将该索引值与位数组长度做取余运算,最终得到一个位数组位置,并将该位置的值变为 1。每个 hash 函数都会计算出一个不同的位置,然后把数组中与之对应的位置变为 1。通过上述过程就完成了元素添加(add)操作。

2) 工作流程-判定元素是否存在

当我们需要判断一个元素是否存时,其流程如下:首先对给定元素再次执行哈希计算,得到与添加元素时相同的位数组位置,判断所得位置是否都为 1,如果其中有一个为 0,那么说明元素不存在,若都为 1,则说明元素有可能存在。

3) 为什么是可能“存在”

您可能会问,为什么是有可能存在?其实原因很简单,那些被置为 1 的位置也可能是由于其他元素的操作而改变的。比如,元素1 和 元素2,这两个元素同时将一个位置变为了 1(图1所示)。在这种情况下,我们就不能判定“元素 1”一定存在,这是布隆过滤器存在误判的根本原因。

在 Redis 4.0 版本之后,布隆过滤器才作为插件被正式使用。布隆过滤器需要单独安装,下面介绍安装 RedisBloom 的几种方法:

1) docker安装

docker 安装布隆过滤器是最简单、快捷的一种方式:

docker pull redislabs/rebloom:latest
docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest
docker exec -it redis-redisbloom bash
redis-cli
#测试是否安装成功
127.0.0.1:6379> bf.add www.biancheng.net hello

2) 直接编译安装

如果您对 docker 不熟悉,也可以采用直接编译的方式来安装。

下载地址:
https://github.com/RedisBloom/RedisBloom
解压文件:
unzip RedisBloom-master.zip
进入目录:
cd RedisBloom-master
执行编译命令,生成redisbloom.so 文件:
make
拷贝至指定目录:
cp redisbloom.so /usr/local/redis/bin/redisbloom.so
在redis配置文件里加入以下配置:
loadmodule /usr/local/redis/bin/redisbloom.so
配置完成后重启redis服务:
sudo /etc/init.d/redis-server restart
#测试是否安装成功
127.0.0.1:6379> bf.add www.biancheng.net hello

常用命令汇总

布隆过滤器基本命令
命令说明
bf.add 只能添加元素到布隆过滤器。
bf.exists 判断某个元素是否在于布隆过滤器中。
bf.madd 同时添加多个元素到布隆过滤器。
bf.mexists 同时判断多个元素是否存在于布隆过滤器中。
bf.reserve 以自定义的方式设置布隆过滤器参数值,共有 3 个参数分别是 key、error_rate(错误率)、initial_size(初始大小)。

1) 命令应用

127.0.0.1:6379> bf.add spider:url www.biancheng.net
(integer) 1
127.0.0.1:6379> bf.exists spider:url www.biancheng.net
(integer) 1
127.0.0.1:6379> bf.madd spider:url www.taobao.com www.123qq.com
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.mexists spider:url www.jd.com www.taobao.com
1) (integer) 0
2) (integer) 1

Redis GEO地理位置

在 Redis 3.2 版本中,新增了存储地理位置信息的功能,即 GEO(英文全称 geographic),它的底层通过 Redis 有序集合(zset)实现。不过 Redis GEO 并没有与 zset 共用一套的命令,而是拥有自己的一套命令。

Redis GEO 提供了 6 个常用命令:

  • GEOADD
  • GEOPOS
  • GEODIST
  • GEORADIUS
  • GEORADIUSBYMEMBER
  • GEOHASH


Redis GEO 有很多应用场景,举一个简单的例子,你一定点过外卖,或者用过打车软件,在这种 APP上会显示“店家距离你有多少米”或者“司机师傅距离你有多远”,类似这种功能就可以使用 Redis GEO 实现。数据库中存放着商家所处的经纬度,你的位置则由手机定位获取,这样 APP 就计算出了最终的距离。再比如微信中附近的人、摇一摇、实时定位等功能都依赖地理位置实现。

GEO 提供以下操作命令,如下表所示:

Redis GEO命令
序号命令说明
1 GEOADD 将指定的地理空间位置(纬度、经度、名称)添加到指定的 key 中。
2 GEOPOS 从 key 里返回所有给定位置元素的位置(即经度和纬度)
3 GEODIST 返回两个地理位置间的距离,如果两个位置之间的其中一个不存在, 那么命令返回空值。
4 GEORADIUS 根据给定地理位置坐标(经纬度)获取指定范围内的地理位置集合。
5 GEORADIUSBYMEMBER 根据给定地理位置(具体的位置元素)获取指定范围内的地理位置集合。
6 GEOHASH 获取一个或者多个的地理位置的 GEOHASH 值。
7 ZREM 通过有序集合的 zrem 命令实现对地理位置信息的删除。


1) GEOADD

将指定的地理空间位置(纬度、经度、名称)添加到指定的 key 中。语法格式如下:

GEOADD key longitude latitude member [longitude latitude member ...]    

  • longitude:位置地点所处的经度;
  • latitude:位置地点所处的纬度;
  • member:位置名称。


将给定的经纬度的位置名称(纬度、经度、名字)与  key 相对应,这些数据以有序集合的形式进行储存。

GEOADD命令以标准的x,y形式接受参数, 所以用户必须先输入经度,然后再输入纬度。GEOADD命令能够记录的坐标数量是有限的,如果位置非常接近两极(南极/北极)区域,那么将无法被索引到。因此当您输入经纬度时,需要注意以下规则:

  • 有效的经度介于 -180 度至 180 度之间。
  • 有效的纬度介于 -85.05112878 度至 85.05112878 度之间。

注意:如果您输入一个超出范围的经纬度时,GEOADD 命令将返回一个错误。

示例演示如下:

#添加城市地理位置
127.0.0.1:6379> geoadd city 116.20 39.56 beijing 120.52 30.40 shanghai
(integer) 2
#查询城市地理位置
127.0.0.1:6379> GEOPOS city beijing shanghai
1) 1) "116.19999736547470093"
   2) "39.56000019952067248"
2) 1) "120.52000075578689575"
   2) "30.39999952668997452"

2) GEODIST

 该命令用于获取两个地理位置间的距离。返回值为双精度浮点数,其语法格式如下:

GEODIST key member1 member2 [unit]   

参数 unit 是表示距离单位,取值如下所示:

  • m 表示单位为米;
  • km 表示单位为千米;
  • mi 表示单位为英里;
  • ft 表示单位为英尺。


注意:如果没有指出距离单位,那么默认取值为m。示例如下:

127.0.0.1:6379> GEODIST city beijing shanghai
"1091868.8970"
127.0.0.1:6379> GEODIST city beijing shanghai km
"1091.8689"
127.0.0.1:6379> GEODIST city beijing shanghai mi
"678.4576"

注意:计算举例时存在 0.5% 左右的误差,这是由于 Redis GEO 把地球假设成了完美的球体。

3) GEORADIUS

以给定的经纬度为中心,计算出 key 包含的地理位置元素与中心的距离不超过给定最大距离的所有位置元素,并将其返回。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

参数说明:

  • WITHDIST :在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
  • WITHCOORD :返回位置元素的经度和维度。
  • WITHHASH :采用 GEOHASH 对位置元素进行编码,以 52 位有符号整数的形式返回有序集合的分值,该选项主要用于底层调试,实际作用不大。
  • COUNT:指定返回位置元素的数量,在数据量非常大时,可以使用此参数限制元素的返回数量,从而加快计算速度。

注意:该命令默认返回的是未排序的位置元素。通过 ASC 与 DESC 可让返回的位置元素以升序或者降序方式排列。


命令应用示例如下:

#添加几个地理位置元素
127.0.0.1:6379> GEOADD city 106.45 29.56 chongqing 120.33 36.06 qingdao 103.73 36.03 lanzhou
(integer) 3
127.0.0.1:6379> GEOADD city 106.71 26.56 guiyang
(integer) 1
#以首都的坐标为中心,计算各个城市距离首都的距离,最大范围设置为1500km
#同时返回距离,与位置元素的经纬度
127.0.0.1:6379> GEORADIUS city 116.41 39.91 1500 km WITHCOORD WITHDIST
1) 1) "chongqing"
   2) "1465.5618"
   3) 1) "106.4500012993812561"
      2) "29.56000053864853072"
2) 1) "lanzhou"
   2) "1191.2793"
   3) 1) "103.72999995946884155"
      2) "36.03000049919800318"
3) 1) "shanghai"
   2) "1121.4882"
   3) 1) "120.52000075578689575"
      2) "30.39999952668997452"
4) 1) "qingdao"
   2) "548.9304"
   3) 1) "120.3299984335899353"
      2) "36.05999892411877994"
5) 1) "beijing"
   2) "42.8734"
   3) 1) "116.19999736547470093"
      2) "39.56000019952067248"

4) GEORADIUSBYMEMBER

根据给定的地理位置坐标(即经纬度)获取指定范围内的位置元素集合。其语法格式如下:

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DES]

  • m :米,默认单位;
  • km :千米(可选);
  • mi :英里(可选);
  • ft :英尺(可选);
  • ASC:根据距离将查找结果从近到远排序;
  • DESC:根据距离将查找结果从远到近排序。


该命令与 GEORADIUS 命令相似,不过它选择的中心的是具体的位置元素,而非经纬度坐标。示例如下:

#以贵阳为中心,最大距离不超过900km
127.0.0.1:6379> GEORADIUSBYMEMBER city guiyang 900 km WITHCOORD WITHDIST
1) 1) "guiyang"
   2) "0.0000"
   3) 1) "106.70999854803085327"
      2) "26.56000089385899798"
#只有重庆符合条件
2) 1) "chongqing"
   2) "334.6529"
   3) 1) "106.4500012993812561"
      2) "29.56000053864853072"

5) GEOHASH

返回一个或多个位置元素的哈希字符串,该字符串具有唯一 ID 标识,它与给定的位置元素一一对应。示例如下:

127.0.0.1:6379> GEOHASH city lanzhou beijing shanghai
1) "wq3ubrjcun0"
2) "wx49h1wm8n0"
3) "wtmsyqpuzd0"

6) ZREM

用于删除指定的地理位置元素,示例如下:

127.0.0.1:6379> zrem city beijing shanghai
(integer) 2

Redis Transaction事务

Redis事务特性

Redis 事务具有两个重要特性:

1) 单独的隔离操作

事务中的所有命令都会被序列化,它们将按照顺序执行,并且在执行过的程中,不会被其他客户端发送来的命令打断。

2) 不保证原子性

在 Redis 的事务中,如果存在命令执行失败的情况,那么其他命令依然会被执行,不支持事务回滚机制。

Redis 事务的目的是方便用户一次执行多个命令。执行 Redis 事务可分为三个阶段:

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

Redis事务命令

Redis事务应用

您可以把事务可以理解为一个批量执行 Redis 命令的脚本,但这个操作并非原子性操作,也就是说,如果中间某条命令执行失败,并不会导致前面已执行命令的回滚,同时不会中断后续命令的执行(不包含监听 key 的情况)。示例如下:

开启事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR 1
QUEUED #命令入队成功
127.0.0.1:6379> SET num 10
QUEUED
#批量执行命令
127.0.0.1:6379> EXEC
1) (integer) 1
2) OK

若您在事务开启之前监听了某个 key,那么您不应该在事务中尝试修改它,否则会导致事务中断。

开启事务之前设置key/value,并监听
127.0.0.1:6379> set www.biancheng.net hello
OK
127.0.0.1:6379> WATCH www.biancheng.net
OK
127.0.0.1:6379> get www.biancheng.net
"hello"
#开启事务
127.0.0.1:6379> MULTI
OK
#更改key的value值
127.0.0.1:6379> set www.biancheng.net HELLO
QUEUED
127.0.0.1:6379> GET www.biancheng.net
QUEUED
#命令执行失败
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
#取消监听key
127.0.0.1:6379> UNWATCH 
OK 
Redis事务命令
命令说明
MULTI 开启一个事务
EXEC 执行事务中的所有命令
WATCH key [key ...] 在开启事务之前用来监视一个或多个key 。如果事务执行时这些 key 被改动过,那么事务将被打断。
DISCARD 取消事务。
UNWATCH 取消 WATCH 命令对 key 的监控。

Redis Lua脚本

第一个Lua脚本命令

Lua 是一种轻量小巧、开源的脚本语言,用标准 C语言编写。其设计目的就是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。它被广泛的应用于:游戏开发、独立应用脚本、Web 应用脚本、扩展和数据库插件等。

Redis 使用EVAL命令编写 lua 脚本,其语法格式如下:

127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]  

参数说明如下:

  • script: 该参数表示使用 Lua 语言编写的一段脚本程序,该脚本不必定义为 Lua 函数格式;
  • numkeys: 用于指定 key 参数的数量;
  • key [key ...]: 从 EVAL 命令的第三个参数算起,表示脚本中用到的所有 key。这些 key 可以使用全局变量 KEYS 数组来访问,比如 KEYS[1] 、KEYS[2] 以此类推。
  • arg [arg ...]:表示附加参数,在 Lua 语言中通过全局变量 ARGV 数组访问,访问的形式与 KEYS 数组相同,比如 ARGV[1] 、 ARGV[2]。

为什么使用Lua脚本

虽然 Redis 官网提供了丰富指令集(200多个),但是在某些特定的领域需要对指令进行扩充,因此 Redis 允许我们使用 Lua 语言以自定义的方式编写脚本命令,这满足了一部分用户的需求。Redis 服务器会以单线程、原子性的方式执行 Lua 脚本,保证 Lua 脚本在处理过程中不会被其他请求中断。

使用 Lua 脚本有如下好处:

    • 减少网络开销:可以将多个请求通过脚本的形式一次发送,从而减少网络时延,比如本来 10 次网络请求,我们就可以通过 Lua 脚本一次性完成。
    • 原子操作:Redis 会将整个脚本作为一个整体执行,中间不会被其他请求干扰。因此在脚本运行过程中无需使用事务。
    • 脚本复用:客户端发送的脚本会一直存储在 Redis 中,这样其他客户端只需对这个脚本稍作修改就可以达到复用的目的,极大地提升了编写脚本的效率。

举一个简单的示例:在 Redis 客户端使用 Lua 语言编写“Hello World”并将其输出。

127.0.0.1:6379> EVAL "return 'Hello world'" 0
"Hello world"

常用脚本命令

Redis脚本命令
命令说明
EVAL script numkeys key [key ...] arg [arg ...] 使用 Lua 解释器执行脚本。
EVALSHA sha1 numkeys key [key ...] arg [arg ...] Lua 解释器根据 sha1 校验码执行脚本。
SCRIPT EXISTS script [script ...] 查看指定的脚本是否保存在于缓存当中。
SCRIPT FLUSH 从脚本缓存中移除所有脚本。
SCRIPT KILL 杀死当前正在运行的 Lua 脚本。
SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但不马上执行这个脚本。

Redis Benchmark性能测试

Redis 提供了一种行性能测试工具 redis-benchmark(也称压力测试工具),它通过同时执行多组命令实现对 Redis 的性能测试。

性能测试的作用是让我们了解 Redis 服务器的性能优劣。在实际的业务场景中,性能测试是必不可少的。在业务系统上线之前,我们都需要清楚地了解 Redis 服务器的性能,从而避免发生某些意外情况,比如数据量过大会导致服务器宕机等。

测试命令格式

执行测试命令,要在 Redis 的安装目录下执行,命令如下所示:

redis-benchmark [option] [option value]

其中 option 为可选参数, option value 为具体的参数值。 redis-benchmark 命令的可选参数如下所示:

Benchmark性能测试参数
参数选项说明
-h 指定服务器主机名。
-p 指定服务器端口。
-s 指定服务器 socket。
-c 指定并发连接数。
-n 指定请求的具体数量。
-d 以字节的形式指定 SET/GET 值的数据大小。
-k 1 表示 keep alive;0 表示 reconnect,默认为 1。
-r SET/GET/INCR 使用随机 key, SADD 使用随机值。
-P Pipeline 请求
-q 强制退出 Redis,仅显示 query/sec 值。
--csv 以 CSV 格式输出。
-l 生成循环,永久执行测试。
-t 仅运行以逗号分隔的测试命令列表。
-I(大写i) 空闲模式,打开 N 个空闲连接并等待连接。



在 Windows 系统下,其目录文件如图所示:

 

执行测试命令

1) Windows环境

在 Windows 10 系统环境下,同时执行了 10000 个命令来检测 Redis 服务器的性能,示例如下:

D:\Redis-x64-5.0.10>redis-benchmark.exe -n 10000 -q
PING_INLINE: 21786.49 requests per second
PING_BULK: 21231.42 requests per second
#每秒执行22935.78个请求
SET: 22935.78 requests per second
GET: 22573.36 requests per second
INCR: 19011.41 requests per second
LPUSH: 7473.84 requests per second
RPUSH: 20618.56 requests per second
LPOP: 17793.60 requests per second
RPOP: 21367.52 requests per second
SADD: 15847.86 requests per second
HSET: 21551.72 requests per second
SPOP: 19531.25 requests per second
LPUSH (needed to benchmark LRANGE): 18348.62 requests per second
LRANGE_100 (first 100 elements): 6835.27 requests per second
LRANGE_300 (first 300 elements): 4535.15 requests per second
LRANGE_500 (first 450 elements): 3913.89 requests per second
LRANGE_600 (first 600 elements): 3177.63 requests per second
MSET (10 keys): 15128.59 requests per second

注意:若是 Linux 系统,其每秒钟执行的请求数量是 Windows 系统的好几倍。

2) Linux环境

Linux 环境下,Redis 的性能测试结果,如下所示:

$ redis-benchmark -n 10000  -q
PING_INLINE: 141043.72 requests per second
PING_BULK: 142857.14 requests per second
#服务器每秒执行的请求数量
SET: 141442.72 requests per second
GET: 145348.83 requests per second
INCR: 137362.64 requests per second
LPUSH: 145348.83 requests per second
LPOP: 146198.83 requests per second
SADD: 146198.83 requests per second
SPOP: 149253.73 requests per second
LPUSH (needed to benchmark LRANGE): 148588.42 requests per second
LRANGE_100 (first 100 elements): 58411.21 requests per second
LRANGE_300 (first 300 elements): 21195.42 requests per second
LRANGE_500 (first 450 elements): 14539.11 requests per second
LRANGE_600 (first 600 elements): 10504.20 requests per second
MSET (10 keys): 93283.58 requests per second

3) 执行指定的测试命令 

带参数的命令,使用示例如下:

D:\Redis-x64-5.0.10>redis-benchmark.exe -h 127.0.0.1 -p 6379 -n 10000 -t set,get,lpush -q
SET: 17064.85 requests per second
GET: 16051.36 requests per second
LPUSH: 14224.75 requests per second

Redis分区技术详解

Redis 分区技术(又称 Redis Partition)指的是将 Redis 中的数据进行拆分,然后把拆分后的数据分散到多个不同的 Redis 实例(即服务器)中,每个实例仅存储数据集的某一部分(一个子集),我们把这个过程称之为 Redis 分区操作。

Redis 实例指的是一台安装了 Redis 服务器的计算机。

分区(Partition)不仅是 Redis 中的概念,几乎所有数据库管理系统都会涉及到“分区”的应用。因此本节重点介绍有关分区的知识。

分区的优势

Redis 分区技术有两个方面的优势,一是提升服务器的性能,二是提高了服务器的数据存储能力。

一方面,单台机器的 Redis 服务器,其网络 IO 能力和计算资源都是非常有限的,但是如果我们将请求分散到多台机器上,那么就能充分利用多台计算机的算力和网络带宽,从而整体上提升 Redis 服务器的性能。另一方面,随着存储数据的不断增加,单台机器的存储容量会达到极限,若将数据分散存储到多台 Redis 服务器上,其存储能力也将得到大幅度提升。

注意,Redis 分区技术可以利用多台计算机的内存总和,从而创建出大型的 Redis 数据库。

分区常用方法

分区技术有两种常用方法,分别是“范围分区”和“哈希分区”。

1) 范围分区

范围分区是最简单、最有效的分区方法之一。所谓范围分区指的是将特定范围的 key 映射到指定的 Redis 实例上。key 的命名格式如下:

object_name:<id>

比如:user:1、user:2 ...用来表示不同 id  的用户。下面通过一个示例了解范围分区的具体流程:

假设现在共有 3000 个用户,您可以把 id 从 0 到 1000 的用户映射到实例 R0 上,id 从 1001 到 2000 的用户映射到实例 R1 上,以此类推,将 id 从 2001 到 3000 的用户映射到实例 R2 上。

范围分区不仅简单,而且实用,适合许多的特定场景。但当存储的 key 不能按照范围划分时,那么范围分区就不再适用了,比如 key 是一组 uuid(通用唯一识别码)。如下所示:

9eb4d81b-31ec-4c69-a721-c7e1771413dd

此时范围分区就不再适用,就要用到另外一种分区方式——哈希分区。

2) 哈希分区

哈希分区与范围分区相比,它最显著的优势是适合任何形式的 key。哈希分区方法并不复杂比,id 表达式如下所示:

id=hash(key)%N

这里的 id 指的是 Redis 实例的编号,而 N 表示共有多少个 Redis 实例。

首先调用一个 crc32() 哈希函数,它可以将 key 转换为一个整数。 如下所示:

crc32(key)

假如转换后的整数是 93024922,此时共有 4 个 Redis 实例,对整数与实例的数量进行取模运算,就会得到一个 0 到 3 之间的整数,如下所示:

93024922 % 4 = 2

上述计算结果为 2 ,我们就把这个 key 映射到 R2 实例中,如果为 3 就映射到 R3实例中。以此类推,通过这种方式可以将所有的 key 分散到 4 个不同的 Redis 实例中。

分区技术的不足

虽然 Redis 分区技术有诸多优势,但是它也存在一些不足之处。下面做简单介绍:

  • 涉及操作多个 key 时,通常不被支持。这是由于批量操作的 key 会被映射到不同的 Redis 实例中,此时无法实现在一个实例中操作分散开的 key;
  • 不支持包含多个 key 的 Redis 事务;
  • 当使用分区的时候,数据的处理变的非常复杂,比如需要处理多个 .rdb 或者 .aof 存储文件,并且还需要从多个 Redis 实例中备份数据;
  • 添加、删除实例变的复杂,比如 Redis 集群支持在运行时增加或减少实例,分区技术不支持这种功能。

分区技术问题解决

我们知道,应用 Redis 分区技术时存在一些不足之处,比如在增加、删除 Redis 实例时会非常麻烦,但这种情况在实际应用中经常遇到。比如今天需要删除 10 台 Redis 实例,明天又要增加 20 台实例。那么对于这种问题,有没有一种较好的解决办法呢?下面进行简单介绍:

其实 Redis 是一种很轻量级的服务(每个实例仅占用 1 MB),针对它的这种特性,我们提出以下解决办法:

在一台机器上开启多个 Redis 实例,您可以从中选择一定数量的实例作为 Redis 工作集群。当集群中某一台机器存储不足时,您可以将一部分 Redis 实例移动到另外一台机器上,依次类推。这样就保证了 Redis 的实例总数不变,又达到了增加机器的目的。

Redis Pipeline管道技术

我们知道, Redis 服务器是以单线程的方式来处理客户端的网络 IO 请求的。如果每执行一次请求都要创建和断开一次连接,就会消耗过多的时间,导致执行效率降低。因此 Redis 提供了 Pipeline(管道技术),使用该技术可以一次性向服务器发送多条命令,并返回多个执行结果。这样就节省了发送命令和创建连接的时间,从而提高了执行效率。

注意:你需要在 Liunx 系统上使用 Pipeline 管道技术。

为什么需要Pipeline

Redis 是使用了客户端-服务器(C/S)模型和请求/响应协议的 TCP 服务器。这意味着发送一个请求会遵循以下步骤:

  • 客户端通常以阻塞的方式向服务器发送命令,以获取服务器的响应。
  • 服务器接收并处理命令,然后将响应发送回客户端。


所谓阻塞式,指的是只有当客户端接收完当前命令的响应信息,服务端才可以继续处理下一条指令,即一条一条的逐次执行。

不管命令是以数据包的形式从客户端传输到服务端,还是客户端获得服务端的响应信息,这个过程都需要花费一定的时间,我把这个时间称为“往返延时”。因此当客户端执行一串请求的时候很容易看出延时对其性能造成的影响。

如果我们可以减少网络请求的次数,那么就可以大幅度提高 Redis 应用性能。Redis 的 Pipeline 就是这样一种技术,它能够把多次网络请求打包成一次请求发送给服务端,从而减少多次请求的“往返时间”。

注意,记住“速度不够,管道来凑”这句话,能够帮助你牢记管道技术的作用。

执行Pipeline语句

Pipeline 技术有其固定的语法格式,以下是在 Linux 终端执行的语句,具体命令如下:

(echo -en "PING\r\n SET name www.biancheng\r\n GET name\r\n INCR num\r\n INCR num\r\n INCR num\r\n"; sleep 2)|nc localhost 6379

上述语句,首先使用 PING 命令检查 Redis 是否正常工作,然后又分别使用了 SET/GET/INCR 命令,以及 sleep 阻塞 2 秒,最后将这些命令一次性的提交给 Redis 服务器,Redis 服务器在阻塞了 2 秒之后,一次性输出了所有命令的响应信息。

注意: 每个命令字符串必须以 \r\n 结尾。至于语句最后的 nc localhost 6379 是固定格式无需更改。

客户端一次性接收到所有命令的执行结果,如下所示:

$(echo -en "PING\r\n SET name www.biancheng\r\n GET name\r\n INCR num\r\n INCR num\r\n INCR num\r\n"; sleep 2)|nc localhost 6379
+PONG
+OK
www.bianchneg.net
:1
:2
:3 

Redis数据备份和还原

Redis SAVE 命令用于创建当前数据库的备份文件,文件名默认为dump.rdb。备份数据库数据可以增强对数据的保护,提升数据的安全性。当数据不小心丢失或者被删除时,我们就可以通过相应的操作进行数据恢复。本节介绍 Redis 的数据备份和数据还原操作。

备份数据

SAVE 命令基本语法如下:

redis 127.0.0.1:6379> SAVE

执行备份命令:

redis 127.0.0.1:6379> SAVE
OK

注意:命令执行后,将在 Redis 安装目录中自动创建dump.rdb文件。如下图所示:

 

恢复数据

如果您想恢复数据,只需将备份文件 dump.rdb 移动到 Redis 安装目录下,然后重启 Redis 服务器,即可进行数据还原。

下面使用CONFIG命令获取 Redis 安装目录,如下所示:

127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "D:\\Redis-x64-5.0.10"

从上述命令可以得知 Redis 的安装目录为 D:\\Redis-x64-5.0.10。

后台备份数据

Redis 还提供了一个BGSAVE命令,同样也可以创建 Redis 备份文件,它与SAVE命令的不同之处在于,该命令在后台运行。示例演示:

127.0.0.1:6379> BGSAVE
Background saving started

Redis RDB持久化详解(原理+配置策略)

Redis 是一款基于内存的非关系型数据库,它会将数据全部存储在内存中。但是如果 Redis 服务器出现某些意外情况,比如宕机或者断电等,那么内存中的数据就会全部丢失。因此必须有一种机制能够保证 Redis 储存的数据不会因故障而丢失,这就是 Redis 的数据持久化机制。

数据的持久化存储是 Redis 的重要特性之一,它能够将内存中的数据保存到本地磁盘中,实现对数据的持久存储。这样即使在服务器发生故障之后,也能通过本地磁盘对数据进行恢复。

Redis 提供了两种持久化机制:第一种是 RDB,又称快照(snapshot)模式,第二种是 AOF 日志,也就追加模式。本节先讲解 RDB 快照模式,关于 AOF 日志会在《Redis AOF持久化详解》一节讲解。

RDB快照模式原理

RDB 即快照模式,它是 Redis 默认的数据持久化方式,它会将数据库的快照保存在 dump.rdb 这个二进制文件中。

提示:所谓“快照”就是将内存数据以二进制文件的形式保存起来。

我们知道 Redis 是单线程的,也就说一个线程要同时负责多个客户端套接字的并发读写,以及内存数据结构的逻辑读写。

Redis 服务器不仅需要服务线上请求,同时还要备份内存快照。在备份过程中 Redis 必须进行文件 IO 读写,而 IO 操作会严重服务器的性能。那么如何实现既不影响客户端的请求,又实现快照备份操作呢,这时就用到了多进程。

Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化操作。

RDB 实际上是 Redis 内部的一个定时器事件,它每隔一段固定时间就去检查当前数据发生改变的次数和改变的时间频率,看它们是否满足配置文件中规定的持久化触发条件。当满足条件时,Redis 就会通过操作系统调用 fork() 来创建一个子进程,该子进程与父进程享有相同的地址空间。

Redis 通过子进程遍历整个内存空间来获取存储的数据,从而完成数据持久化操作。注意,此时的主进程则仍然可以对外提供服务,父子进程之间通过操作系统的 COW 机制实现了数据段分离,从而保证了父子进程之间互不影响。

RDB持久化触发策略

RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。

1) 手动触发策略

手动触发是通过SAVAE命令或者BGSAVE命令将内存数据保存到磁盘文件中。如下所示:

127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>  LASTSAVE
(integer) 1611298430

上述命令BGSAVE从后台执行数据保存操作,其可用性要优于执行 SAVE 命令。

SAVE 命令会阻塞 Redis 服务器进程,直到 dump.rdb 文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求。

BGSAVE命令是非阻塞式的,所谓非阻塞式,指的是在该命令执行的过程中,并不影响 Redis 服务器处理客户端的其他请求。这是因为 Redis 服务器会 fork() 一个子进程来进行持久化操作(比如创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完后会向父进程发送一个信号,通知它已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。

因为SAVE命令无需创建子进程,所以执行速度要略快于BGSAVE命令,但是SAVE命令是阻塞式的,因此其可用性欠佳,如果在数据量较少的情况下,基本上体会不到两个命令的差别,不过仍然建议您使用 BGSAVE命令。

注意:LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。

2) 自动触发策略

自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE命令。自动触发的条件包含在了 Redis 的配置文件中,如下所示:

Redis RDB数据持久化
图1:数据持久化策略


上图所示, save m n 的含义是在时间 m 秒内,如果 Redis 数据至少发生了 n 次变化,那么就自动执行BGSAVE命令。配置策略说明如下:

  • save 900 1 表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
  • save 300 10 表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 BGSAVE 命令,将数据保存到硬盘。
  • save 60 10000 表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。


只要上述三个条件任意满足一个,服务器就会自动执行BGSAVE命令。当然您可以根据实际情况自己调整触发策略。

注意:每次创建 RDB 文件之后,Redis 服务器为实现自动持久化而设置的时间计数和次数计数就会被清零,并重新开始计数,因此多个策略的效果不会叠加。

RDB持久化优劣势

最后我们对 RDB 持久化的优劣势做简单地分析:

我们知道,在 RDB 持久化的过程中,子进程会把 Redis 的所有数据都保存到新建的 dump.rdb 文件中,这是一个既消耗资源又浪费时间的操作。因此 Redis 服务器不能过于频繁地创建 rdb 文件,否则会严重影响服务器的性能。

RDB 持久化的最大不足之处在于,最后一次持久化的数据可能会出现丢失的情况。我们可以这样理解,在 持久化进行过程中,服务器突然宕机了,这时存储的数据可能并不完整,比如子进程已经生成了 rdb 文件,但是主进程还没来得及用它覆盖掉原来的旧 rdb 文件,这样就把最后一次持久化的数据丢失了。

RDB 数据持久化适合于大规模的数据恢复,并且还原速度快,如果对数据的完整性不是特别敏感(可能存在最后一次丢失的情况),那么 RDB 持久化方式非常合适。

Redis AOF持久化详解(含配置策略)

AOF 被称为追加模式,或日志模式,是 Redis 提供的另一种持久化策略,它能够存储 Redis 服务器已经执行过的的命令,并且只记录对内存有过修改的命令,这种数据记录方法,被叫做“增量复制”,其默认存储文件为appendonly.aof

开启AOF持久化

AOF 机制默认处于未开启状态,可以通过修改 Redis 配置文件开启 AOF,如下所示:

1) Windows系统

执行如下操作:

#修改配置文件,把no改为 yes
appendonly yes
#确定存储文件名是否正确
appendfilename "appendonly.aof"
#重启服务器
redis-server --service-stop
redis-server --service-start

2) Linux系统

执行如下操作:

#修改配置文件:
vim /etc/redis/redis.conf
appendonly yes # 把 no 改为 yes
#确定存储文件名是否正确
appendfilename "appendonly.aof"
#重启服务:
sudo /etc/init.d/redis-server restart

提示:本节建议在您在 Linux 系统上操作 Redis,否则一些 AOF 的性能无法体现。

AOF持久化机制

每当有一个修改数据库的命令被执行时,服务器就将命令写入到 appendonly.aof 文件中,该文件存储了服务器执行过的所有修改命令,因此,只要服务器重新执行一次 .aof 文件,就可以实现还原数据的目的,这个过程被形象地称之为“命令重演”。

1) 写入机制

Redis 在收到客户端修改命令后,先进行相应的校验,如果没问题,就立即将该命令存追加到 .aof 文件中,也就是先存到磁盘中,然后服务器再执行命令。这样就算遇到了突发的宕机情况情况,也只需将存储到  .aof 文件中的命令,进行一次“命令重演”就可以恢复到宕机前的状态。

在上述执行过程中,有一个很重要的环节就是命令的写入,这是一个 IO 操作。Redis 为了提升写入效率,它不会将内容直接写入到磁盘中,而是将其放到一个内存缓存区(buffer)中,等到缓存区被填满时才真正将缓存区中的内容写入到磁盘里。

2) 重写机制

Redis 在长期运行的过程中,aof 文件会越变越长。如果机器宕机重启,“重演”整个 aof 文件会非常耗时,导致长时间 Redis 无法对外提供服务。因此就需要对 aof 文件做一下“瘦身”运动。

为了让 aof 文件的大小控制在合理的范围内,Redis 提供了 AOF 重写机制,手动执行BGREWRITEAOF命令,开始重写 aof 文件,如下所示:

127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

通过上述操作后,服务器会生成一个新的 aof 文件,该文件具有以下特点:

  • 新的 aof 文件记录的数据库数据和原 aof 文件记录的数据库数据完全一致;
  • 新的 aof 文件会使用尽可能少的命令来记录数据库数据,因此新的 aof 文件的体积会小很多;
  • AOF 重写期间,服务器不会被阻塞,它可以正常处理客户端发送的命令。


下表对原有 aof 文件和新生成的 aof 文件做了对比,如下所示:

重写机制AOF文件对比
原有aof文件重写后aof文件
select 0 SELECT 0
sadd myset Jack SADD myset Jack Helen JJ Lisa
sadd myset Helen SET msg 'hello tarena'
sadd myset JJ RPUSH num 4 6 8
sadd myset Lisa  
INCR number  
INCR number  
DEL number  
SET message 'www.baidu.com'  
SET message 'www.biancheng.net'  
RPUSH num 2 4 6  
RPUSH num 8  
LPOP num  


从上表可以看出,新生成的 aof 文件中,它的命令格式做了很大程度的简化。

3) 自动触发AOF重写

Redis 为自动触发 AOF 重写功能,提供了相应的配置策略。如下所示:修改 Redis 配置文件,让服务器自动执行 BGREWRITEAOF 命令。

#默认配置项
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #表示触发AOF重写的最小文件体积,大于或等于64MB自动触发。

该配置项表示:触发重写所需要的 aof 文件体积百分比,只有当 aof 文件的增量大于 100% 时才进行重写,也就是大一倍。比如,第一次重写时文件大小为 64M,那么第二次触发重写的体积为 128M,第三次重写为 256M,以此类推。如果将百分比值设置为 0 就表示关闭 AOF 自动重写功能。

AOF策略配置

在上述介绍写入机制的过程中,如果遇到宕机前,缓存内的数据未能写入到磁盘中,那么数据仍然会有丢失的风险。服务器宕机时,丢失命令的数量,取决于命令被写入磁盘的时间,越早地把命令写入到磁盘中,发生意外时丢失的数据就会越少,否则越多。

Redis 为数据的安全性考虑,同样为 AOF 持久化提供了策略配置,打开 Redis 配置文件,如下图所示:

Redis AOF持久化
图1:AOF策略配置


上述配置策略说明如下:

  • Always:服务器每写入一个命令,就调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据,但是其执行速度较慢;
  • Everysec(默认):服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据,通常都使用它作为 AOF 配置策略;
  • No:服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的,所以这种策略,不确定性较大,不安全。

注意:Linux 系统的 fsync() 函数可以将指定文件的内容从内核缓存刷到硬盘中。

由于是 fsync 是磁盘 IO 操作,所以它很慢!如果 Redis 执行一条指令就要 fsync 一次(Always),那么 Redis 高性能将严重受到影响。

在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作( Everysec),这样既保持了高性能,也让数据尽可能的少丢失。最后一种策略(No),让操作系统来决定何时将数据同步到磁盘,这种策略存在许多不确定性,所以不建议使用。

从三种策略的运行速度来看,Always 的速度最慢,而 Everysec 和 No 都很快。

AOF和RDB对比

RDB与AOF持久化对比
RDB持久化AOF持久化
全量备份,一次保存整个数据库。 增量备份,一次只保存一个修改数据库的命令。
每次执行持久化操作的间隔时间较长。 保存的间隔默认为一秒钟(Everysec)
数据保存为二进制格式,其还原速度快。 使用文本格式还原数据,所以数据还原速度一般。
执行 SAVE 命令时会阻塞服务器,但手动或者自动触发的 BGSAVE 不会阻塞服务器 AOF持久化无论何时都不会阻塞服务器。


如果进行数据恢复时,既有 dump.rdb文件,又有 appendonly.aof 文件,您应该先通过 appendonly.aof 恢复数据,这能最大程度地保证数据的安全性。

Redis Cluster主从模式详解

主从模式解析

主从模式的结构图如下:

 

 如图 1 所示,Redis 主机会一直将自己的数据复制给 Redis 从机,从而实现主从同步。在这个过程中,只有 master 主机可执行写命令,其他 salve 从机只能只能执行读命令,这种读写分离的模式可以大大减轻 Redis 主机的数据读取压力,从而提高了Redis 的效率,并同时提供了多个数据备份。主从模式是搭建 Redis Cluster 集群最简单的一种方式。

主从模式实现

Redis 提供了两种实现主从模式的方法,下面进行逐一介绍。为了方便演示,我们只从一台机器上搭建主从模式。

1) 使用命令实现

使用命令在服务端搭建主从模式,其语法格式如下:

redis-server --port <slave-port> --slaveof <master-ip> <master-port>

执行以下命令:

#开启开启一个port为6300的从机,它依赖的主机port=6379
C:\Users\Administrator> redis-server --port 6300 --slaveof 127.0.0.1 6379


输出结果如下图:

Redis主从模式
图2:Redis 主从模式
 

接下来开启客户端,并执行查询命令,如下所示:

C:\Users\Administrator>redis-cli -p 6300
127.0.0.1:6300> get name
"jack"
127.0.0.1:6300> get website
"www.biancheng.net"
#不能执行写命令
127.0.0.1:6300> set myname BangDe
(error) READONLY You can't write against a read only slave.
127.0.0.1:6300> keys *
1) "myset:__rand_int__"
2) "ID"
3) "title"
4) "course2"
5) "website"
6) "age"
7) "user:2"
8) "salary"
9) "mystream"
10) "key:__rand_int__"
11) "user:uv:2021011308"
....

注意:此时 port=6300 的服务端界面不能关闭。从上述命令可以看出,port =6300 的从机,完全备份了主机的数据,它可以执行查询命令,但是不能执行写入命令。

如果你注意观察服务端的话,您会看到以下提示:

[18160] 20 Jan 17:40:34.101 # Server initialized #服务初始化
[18160] 20 Jan 17:40:34.108 * Ready to accept connections #准备连接
[18160] 20 Jan 17:40:34.108 * Connecting to MASTER 127.0.0.1:6379 #连接到主服务器
[18160] 20 Jan 17:40:34.109 * MASTER <-> REPLICA sync started #启动副本同步
[18160] 20 Jan 17:40:34.110 * Non blocking connect for SYNC fired the event.#自动触发SYNC命令,请求同步数据
[18160] 20 Jan 17:40:34.110 * Master replied to PING, replication can continue...
[18160] 20 Jan 17:40:34.112 * Partial resynchronization not possible (no cached master)
[18160] 20 Jan 17:40:34.431 * Full resync from master: 6eb220706f73107990c2b886dbc2c12a8d0d9d05:0
[18160] 20 Jan 17:40:34.857 * MASTER <-> REPLICA sync: receiving 6916 bytes from master #从主机接受了数据,并将其存在于磁盘
[18160] 20 Jan 17:40:34.874 * MASTER <-> REPLICA sync: Flushing old data #清空原有数据
[18160] 20 Jan 17:40:34.874 * MASTER <-> REPLICA sync: Loading DB in memory #将磁盘中数据载入内存
[18160] 20 Jan 17:40:34.879 * MASTER <-> REPLICA sync: Finished with success #同步数据完成

可以看出主从模式下,数据的同步是自动完成的,这个数据同步的过程,又称为全量复制。

您也可以使用下面的命令来创建主从模式。启动一个服务端,并指定端口号:

#指定端口号为63001,不要关闭
redis-server --port 63001


打开一个客户端,连接服务器,如下所示:

#连接port=63001的服务器
C:\Users\Administrator>redis-cli -p 63001
#现在处于主机模式下,所以允许读写数据
127.0.0.1:63001> keys *
1) "FANS"
2) "user:login"
3) "course2"
4) "1"
5) "age"
6) "ID"
7) "title"
8) "counter:__rand_int__"
9) "key:__rand_int__"
10) "user:3"
11) "user:2"
...
127.0.0.1:63001> set myname 123456
OK
#将当前服务器设置成从服务器,从属于6379
127.0.0.1:63001> SLAVEOF 127.0.0.1 6379
OK
#写入命令执行失败
127.0.0.1:63001> SET mywebsite www.biancheng.net
(error) READONLY You can't write against a read only replica.
#再次切换为主机模式,执行下面命令
127.0.0.1:63001> SLAVEOF no one
OK
#写入成功
127.0.0.1:63001> SET mywebsite www.biancheng.net
OK

上述示例中,主要使用了两个命令,如下所示:

slaveof IP PORT #设置从服务器
slaveof no one  #使服务器切换为独立主机

2) 修改配置文件实现

每个 Redis 服务器都有一个与其对应的配置文件,通过修改该配置文件也可以实现主从模式,下面在 Ubuntu 环境下对该方法进行演练。

新建 redis_6302.conf 文件,并添加以下配置信息:

slaveof 127.0.0.1 6379 #指定主机的ip与port
port 6302 #指定从机的端口

启动 Redis 服务器,执行以下命令:

$ redis-server redis_6302.conf

客户端连接服务器,并进行简单测试。执行以下命令:

$ redis-cli -p 6302
127.0.0.1:6300> HSET user:username biangcheng
#写入失败
(error) READONLY You can't write against a read only slave.

提示:通过命令搭建主从模式,简单又快捷,所以不建议您使用修改配置文件的方法。

主从模式不足

主从模式并不完美,它也存在许多不足之处,下面做了简单地总结:

  • 1) Redis 主从模式不具备自动容错和恢复功能,如果主节点宕机,Redis 集群将无法工作,此时需要人为干预,将从节点提升为主节点。
  • 2) 如果主机宕机前有一部分数据未能及时同步到从机,即使切换主机后也会造成数据不一致的问题,从而降低了系统的可用性。
  • 3) 因为只有一个主节点,所以其写入能力和存储能力都受到一定程度地限制。
  • 4) 在进行数据全量同步时,若同步的数据量较大可能会造卡顿的现象。

如图 1 所示,Redis 主机会一直将自己的数据复制给 Redis 从机,从而实现主从同步。在这个过程中,只有 master 主机可执行写命令,其他 salve 从机只能只能执行读命令,这种读写分离的模式可以大大减轻 Redis 主机的数据读取压力,从而提高了Redis 的效率,并同时提供了多个数据备份。主从模式是搭建 Redis Cluster 集群最简单的一种方式。

Redis集群:Sentinel哨兵模式(详细图解)

哨兵模式原理

哨兵模式是一种特殊的模式,Redis 为其提供了专属的哨兵命令,它是一个独立的进程,能够独立运行。下面使用 Sentinel 搭建 Redis 集群,基本结构图如下所示:

在上图过程中,哨兵主要有两个重要作用:

  • 第一:哨兵节点会以每秒一次的频率对每个 Redis 节点发送PING命令,并通过 Redis 节点的回复来判断其运行状态。
  • 第二:当哨兵监测到主服务器发生故障时,会自动在从节点中选择一台将机器,并其提升为主服务器,然后使用 PubSub 发布订阅模式,通知其他的从节点,修改配置文件,跟随新的主服务器。


在实际生产情况中,Redis Sentinel 是集群的高可用的保障,为避免 Sentinel 发生意外,它一般是由 3~5 个节点组成,这样就算挂了个别节点,该集群仍然可以正常运转。其结构图如下所示:

 

 在上图过程中,哨兵主要有两个重要作用:

  • 第一:哨兵节点会以每秒一次的频率对每个 Redis 节点发送PING命令,并通过 Redis 节点的回复来判断其运行状态。
  • 第二:当哨兵监测到主服务器发生故障时,会自动在从节点中选择一台将机器,并其提升为主服务器,然后使用 PubSub 发布订阅模式,通知其他的从节点,修改配置文件,跟随新的主服务器。

 上图所示,多个哨兵之间也存在互相监控,这就形成了多哨兵模式,现在对该模式的工作过程进行讲解,介绍如下:

1) 主观下线

主观下线,适用于主服务器和从服务器。如果在规定的时间内(配置参数:down-after-milliseconds),Sentinel 节点没有收到目标服务器的有效回复,则判定该服务器为“主观下线”。比如 Sentinel1 向主服务发送了PING命令,在规定时间内没收到主服务器PONG回复,则 Sentinel1 判定主服务器为“主观下线”。

2) 客观下线

客观下线,只适用于主服务器。 Sentinel1 发现主服务器出现了故障,它会通过相应的命令,询问其它 Sentinel 节点对主服务器的状态判断。如果超过半数以上的  Sentinel 节点认为主服务器 down 掉,则 Sentinel1 节点判定主服务为“客观下线”。

3) 投票选举

投票选举,所有 Sentinel 节点会通过投票机制,按照谁发现谁去处理的原则,选举 Sentinel1 为领头节点去做 Failover(故障转移)操作。Sentinel1 节点则按照一定的规则在所有从节点中选择一个最优的作为主服务器,然后通过发布订功能通知其余的从节点(slave)更改配置文件,跟随新上任的主服务器(master)。至此就完成了主从切换的操作。

对上对述过程做简单总结:

Sentinel 负责监控主从节点的“健康”状态。当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接 Redis 集群时,会首先连接 Sentinel,通过 Sentinel 来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向 Sentinel 要地址,Sentinel 会将最新的主节点地址告诉客户端。因此应用程序无需重启即可自动完成主从节点切换。

哨兵模式应用

Redis Sentinel 哨兵模式适合于在 Linux 系统中使用,所以下面的应用都基于 Ubuntu 实现。

1) 安装sentinel

Sentinel 需要作为插件单独安装,安装方式如下:

sudo apt install redis-sentinel

2) 搭建主从模式

接下来,在本地环境使用主从模式搭建一个拥有三台服务器的 Redis 集群,命令如下所示:

启动6379的redis服务器作为master主机:
sudo /etc/init.d/redis-server start

启动6380的redis服务器,设置为6379的slave:
redis-server --port 6380
$ redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK

启动6381的redis服务器,设置为6379的salve
redis-server --port 6381
$ redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379

3) 配置sentinel哨兵

首先新建 sentinel.conf 文件,并对其进行配置,如下所示:

port 26379
Sentinel monitor biancheng 127.0.0.1 6379 1

配置文件说明如下:

port 26379 #sentinel监听端口,默认是26379,可以更改
sentinel monitor <master-name> <ip> <redis-port> <quorum>

第二个配置项表示:让 sentinel 去监控一个地址为 ip:port 的主服务器,这里的 master-name 可以自定义;<quorum> 是一个数字,表示当有多少个 sentinel 认为主服务器宕机时,它才算真正的宕机掉,通常数量为半数或半数以上才会认为主机已经宕机,<quorum> 需要根据 sentinel 的数量设置。

4) 启动sentienl哨兵

方式一: 
redis-sentinel sentinel.conf
方式二: 
redis-server sentinel.conf --sentinel

5) 停止主服务器服务

下面模拟主服务意外宕机的情况,首先直接将主服务器的 Redis 服务终止,然后查看从服务器是否被提升为了主服务器。执行以下命令:

#终止master的redis服务
sudo /etc/init.d/redis-server stop

执行完上述命令,您会发现 6381 称为了新的 master,而其余节点变成了它的从机,执行命令验证:

127.0.0.1:6381> set webname www.biancheng.net
OK

哨兵的配置文件 sentinel.conf 也发生了变化:

#port 26379
#sentinel myid 4c626b6ff25dca5e757afdae2bd26a881a61a2b2
# Generated by CONFIG REWRITE
dir "/home/biancheng"
maxclients 4064
sentinel myid 4c626b6ff25dca5e757afdae2bd26a881a61a2b2
sentinel monitor biancheng 127.0.0.1 6379 1
sentinel config-epoch biancheng 2
sentinel leader-epoch biancheng 2
sentinel known-slave biancheng 127.0.0.1 6379
sentinel known-slave biancheng 127.0.0.1 6380
sentinel known-slave biancheng 127.0.0.1 6381
port 26379
sentinel current-epoch 2

如果您想开启多个哨兵,只需配置要多个 sentinel.conf 文件即可,一个配置文件开启一个。

sentinel.conf配置项

下面对 Sentinel 配置文件的其他配置项做简单说明:


sentinel配置文件说明
配置项参数类型说明
dir 文件目录 哨兵进程服务的文件存放目录,默认为 /tmp。
port 端口号 启动哨兵的进程端口号,默认为 26379。
sentinel down-after-milliseconds <服务名称><毫秒数(整数)> 在指定的毫秒数内,若主节点没有应答哨兵的 PING 命令,此时哨兵认为服务器主观下线,默认时间为 30 秒。
sentinel parallel-syncs <服务名称><服务器数(整数)> 指定可以有多少个 Redis 服务同步新的主机,一般而言,这个数字越小同步时间越长,而越大,则对网络资源要求就越高。
sentinel failover-timeout <服务名称><毫秒数(整数)> 指定故障转移允许的毫秒数,若超过这个时间,就认为故障转移执行失败,默认为 3 分钟。
sentinel notification-script <服务名称><脚本路径> 脚本通知,配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
sentinel auth-pass <master-name> <password> <服务器名称><密码> 若主服务器设置了密码,则哨兵必须也配置密码,否则哨兵无法对主从服务器进行监控。该密码与主服务器密码相同。

Redis分布式锁应用(实现+原理)

Redis分布式锁命令

分布式锁的本质其实就是要在 Redis 里面占一个“坑”,当别的进程也要来占时,发现已经有人蹲了,就只好放弃或者稍做等待。这个“坑”同一时刻只允许被一个客户端占据,也就是本着“先来先占”的原则。

在分布式系统中,当不同进程或线程一起访问共享资源时,会造成资源争抢,如果不加以控制的话,就会引发程序错乱。此时使用分布式锁能够非常有效的解决这个问题,它采用了一种互斥机制来防止线程或进程间相互干扰,从而保证了数据的一致性。

提示:如果对分布式系统这一概念不清楚,可参考百度百科《分布式系统》,简而言之,它是一种架构、一种模式。

Redis分布式锁介绍

分布式锁并非是 Redis 独有,比如 MySQL 关系型数据库,以及 Zookeeper 分布式服务应用,它们都实现分布式锁,只不过 Redis 是基于缓存实现的。

Redis 分布式锁有很对应用场景,举个简单的例子,比如春运时,您需要在 12306 上抢购回家火车票,但 Redis 数据库中只剩一张票了,此时有多个用户来预订购买,那么这张票会被谁抢走呢?Redis 服务器又是如何处理这种情景的呢?在这个过程中就需要使用分布式锁。

Redis 分布式锁主要有以下特点:

  • 第一:互斥性是分布式锁的重要特点,在任意时刻,只有一个线程能够持有锁;
  • 第二:锁的超时时间,一个线程在持锁期间挂掉了而没主动释放锁,此时通过超时时间来保证该线程在超时后可以释放锁,这样其他线程才可以继续获取锁;
  • 第三:加锁和解锁必须是由同一个线程来设置;
  • 第四:Redis 是缓存型数据库,拥有很高的性能,因此加锁和释放锁开销较小,并且能够很轻易地实现分布式锁。

注意:一个线程代表一个客户端。

Redis分布式锁命令

分布式锁的本质其实就是要在 Redis 里面占一个“坑”,当别的进程也要来占时,发现已经有人蹲了,就只好放弃或者稍做等待。这个“坑”同一时刻只允许被一个客户端占据,也就是本着“先来先占”的原则。

1) 常用命令

Redis 分布式锁常用命令如下所示:

  • SETNX key val:仅当key不存在时,设置一个 key 为 value 的字符串,返回1;若 key 存在,设置失败,返回 0;
  • Expire key timeout:为 key 设置一个超时时间,以 second 秒为单位,超过这个时间锁会自动释放,避免死锁;
  • DEL key:删除 key。


上述 SETNX 命令相当于占“坑”操作,EXPIRE 是为避免出现意外用来设置锁的过期时间,也就是说到了指定的过期时间,该客户端必须让出锁,让其他客户端去持有。

但还有一种情况,如果在 SETNX 和 EXPIRE 之间服务器进程突然挂掉,也就是还未设置过期时间,这样就会导致 EXPIRE 执行不了,因此还是会造成“死锁”的问题。为了避免这个问题,Redis 作者在 2.6.12 版本后,对 SET 命令参数做了扩展,使它可以同时执行 SETNX 和 EXPIRE 命令,从而解决了死锁的问题。

直接使用 SET 命令实现,语法格式如下:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]  
  • EX second:设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond:设置键的过期时间为毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecondvalue 。
  • NX:只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
  • XX:只在键已经存在时,才对键进行设置操作。

2) 命令应用

下面进行简单的命令演示:

127.0.0.1:6379> SETNX WEBNAME www.biancheng.net
(integer) 1
127.0.0.1:6379> EXPIRE WEBNAME 60
(integer) 1
127.0.0.1:6379> GET WEBNAME
"www.biancheng.net"
127.0.0.1:6379> TTL WEBNAME
(integer) 33
127.0.0.1:6379> SET name www.biancheng.net EX 60 NX
OK

Redis缓存问题(图解:三种缓存问题)

在实际的业务场景中,Redis 一般和其他数据库搭配使用,用来减轻后端数据库的压力,比如和关系型数据库 MySQL 配合使用。

Redis 会把 MySQL 中经常被查询的数据缓存起来,比如热点数据,这样当用户来访问的时候,就不需要到 MySQL 中去查询了,而是直接获取 Redis 中的缓存数据,从而降低了后端数据库的读取压力。如果说用户查询的数据 Redis 没有,此时用户的查询请求就会转到 MySQL 数据库,当 MySQL 将数据返回给客户端时,同时会将数据缓存到 Redis 中,这样用户再次读取时,就可以直接从 Redis 中获取数据。流程图如下所示:

 

 


在使用 Redis 作为缓存数据库的过程中,有时也会遇到一些棘手问题,比如常见缓存穿透、缓存击穿和缓存雪崩等问题,本节将对这些问题做简单地说明,并且提供有效的解决方案。

缓存穿透

缓存穿透是指当用户查询某个数据时,Redis 中不存在该数据,也就是缓存没有命中,此时查询请求就会转向持久层数据库 MySQL,结果发现 MySQL 中也不存在该数据,MySQL 只能返回一个空对象,代表此次查询失败。如果这种类请求非常多,或者用户利用这种请求进行恶意攻击,就会给 MySQL 数据库造成很大压力,甚至于崩溃,这种现象就叫缓存穿透。

为了避免缓存穿透问题,下面介绍两种解决方案:

1) 缓存空对象

当 MySQL 返回空对象时, Redis 将该对象缓存起来,同时为其设置一个过期时间。当用户再次发起相同请求时,就会从缓存中拿到一个空对象,用户的请求被阻断在了缓存层,从而保护了后端数据库,但是这种做法也存在一些问题,虽然请求进不了 MSQL,但是这种策略会占用 Redis 的缓存空间。

2) 布隆过滤器

我们知道,布隆过滤器判定不存在的数据,那么该数据一定不存在,利用它的这一特点可以防止缓存穿透。

首先将用户可能会访问的热点数据存储在布隆过滤器中(也称缓存预热),当有一个用户请求到来时会先经过布隆过滤器,如果请求的数据,布隆过滤器中不存在,那么该请求将直接被拒绝,否则将继续执行查询。相较于第一种方法,用布隆过滤器方法更为高效、实用。其流程示意图如下:

缓存预热:是指系统启动时,提前将相关的数据加载到 Redis 缓存系统中。这样避免了用户请求的时再去加载数据。

缓存击穿

缓存击穿是指用户查询的数据缓存中不存在,但是后端数据库却存在,这种现象出现原因是一般是由缓存中 key 过期导致的。比如一个热点数据 key,它无时无刻都在接受大量的并发访问,如果某一时刻这个 key 突然失效了,就致使大量的并发请求进入后端数据库,导致其压力瞬间增大。这种现象被称为缓存击穿。

缓存击穿有两种解决方法:

1) 改变过期时间

设置热点数据永不过期。

2) 分布式锁

采用分布式锁的方法,重新设计缓存的使用方式,过程如下:

  • 上锁:当我们通过 key 去查询数据时,首先查询缓存,如果没有,就通过分布式锁进行加锁,第一个获取锁的进程进入后端数据库查询,并将查询结果缓到Redis 中。
  • 解锁:当其他进程发现锁被某个进程占用时,就进入等待状态,直至解锁后,其余进程再依次访问被缓存的 key。

缓存雪崩

缓存雪崩是指缓存中大批量的 key 同时过期,而此时数据访问量又非常大,从而导致后端数据库压力突然暴增,甚至会挂掉,这种现象被称为缓存雪崩。它和缓存击穿不同,缓存击穿是在并发量特别大时,某一个热点 key 突然过期,而缓存雪崩则是大量的 key 同时过期,因此它们根本不是一个量级。

​解决方案

缓存雪崩和缓存击穿有相似之处,所以也可以采用热点数据永不过期的方法,来减少大批量的 key 同时过期。再者就是为 key 设置随机过期时间,避免 key 集中过期。

Java使用Redis

安装Redis驱动

如果想在 Java 环境下操作 Redis ,您需要安装相应的 Redis 驱动程序,也就 jedis.jar 包(点击下载),然后将该驱动添加至 Java 的 classpath 中。

如果您的项目是基于 maven 构建的,那么您可以直接导入 maven 坐标,如下所示:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

连接Redis服务器

安装完 Redis 的驱动程序后,接下来就是连接 Redis 服务器。最简单的连接方式,就是通过 Jedis 对象连接。代码如下:

  1. //引入Redis驱动程序
  2. import redis.clients.jedis.Jedis;
  3. public class RedisJava {
  4. public static void main(String[] args) {
  5. //连接本地的 Redis 服务
  6. Jedis jedis = new Jedis("localhost");
  7. // 如果设置 Redis 服务的密码,需要进行验证,若没有则可以省去
  8. // jedis.auth("123456");
  9. System.out.println("连接成功");
  10. //查看服务是否运行
  11. System.out.println("服务正在运行: "+jedis.ping());
  12. }
  13. }

首先确保 Redis 驱动包引入路径正确的,然后编译并运行 Java 程序,输出结果如下:

连接成功
服务正在运行: PONG

Java Redis字符串

Redis String 类型操作,示例如下:

  1. import redis.clients.jedis.Jedis;
  2. public class RedisStringJava {
  3. public static void main(String[] args) {
  4. //连接本地的 Redis 服务
  5. Jedis jedis = new Jedis("localhost");
  6. System.out.println("服务器连接成功");
  7. //设置 redis 字符串数据
  8. jedis.set("webkey", "www.biancheng.net");
  9. // 获取存储的数据并输出
  10. System.out.println("redis 存储的字符串为: "+ jedis.get("webkey"));
  11. }
  12. }

编译并运行上述程序,输出结果如下:

服务器连接成功
redis 存储的字符串为: www.biancheng.net

Java Redis列表

Redis List 列表操作,示例如下:

  1. import java.util.List;
  2. import redis.clients.jedis.Jedis;
  3. public class RedisListJava {
  4. public static void main(String[] args) {
  5. //连接本地的 Redis 服务
  6. Jedis jedis = new Jedis("localhost");
  7. System.out.println("服务器连接成功");
  8. //存储数据到列表中
  9. jedis.lpush("website_list", "www.biancheng.net");
  10. jedis.lpush("website_list", "www.baidu.com");
  11. jedis.lpush("website_list", "c.biancheng.net");
  12. // 获取存储的数据并输出
  13. List<String> list = jedis.lrange("website_list", 0 ,2);
  14. for(int i=0; i<list.size(); i++) {
  15. System.out.println("列表元素为: "+list.get(i));
  16. }
  17. }
  18. }

编译并运行上述程序,输出结果如下:

服务器连接成功
列表元素为: c.biancheng.net
列表元素为: www.baidu.com
列表元素为: www.biancheng.net

Java Redis键

查看所有 key,示例如下:

  1. import java.util.Iterator;
  2. import java.util.Set;
  3. import redis.clients.jedis.Jedis;
  4. public class RedisKeyJava {
  5. public static void main(String[] args) {
  6. //连接本地的 Redis 服务
  7. Jedis jedis = new Jedis("localhost");
  8. System.out.println("服务器连接成功");
  9. // 获取数据并输出
  10. Set<String> keys = jedis.keys("*");
  11. Iterator<String> it=keys.iterator() ;
  12. while(it.hasNext()){
  13. String key = it.next();
  14. System.out.println(key);
  15. }
  16. }
  17. }

编译并运行上述程序。输出结果如下:

服务器连接成功
webkey
website_list

基本配置

port 6379  # 监听端口号,默认为6379,如果你设为 0 ,redis 将不在 socket 上监听任何客户端连接。
daemonize no #指定redis是否以守护线程的方式启动
databases 16 #创建database的数量,默认为0库

save 900 1 #刷新快照到硬盘中。必须满足下列三个要求之一才会触发,即900秒内至少有1个key发生变化。
save 300 10 #在300秒内至少10个key发生变化。
save 60 10000 #在60秒之内至少有10000个可以发生变化。

stop-writes-on-bgsave-error yes #后台存储错误并停止写入命令。
rdbcompression yes #使用LZF方式压缩rdb文件。如果你想节省一些CPU可设置成'no'
rdbchecksum yes #在存储、加载rdb文件时进行校验。
dbfilename dump.rdb #设置rdb文件名。
dir ./ #设置工作目录,rdb文件会自动存放在该目录。

主从服务配置

slaveof <masterip> <masterport> #将本机设为某台机器的从服务器
masterauth <master-password> #连接主服务器的密码
slave-serve-stale-data yes # 当主机和从机断开时或这正处于在复制过程中,是否让从服务器是应答请求
slave-read-only yes #设置从服务器为只读模式
repl-diskless-sync no  #是否同时向多个从服务器节点同时发数据
repl-diskless-sync-delay 5 #发送数据的延迟时间
repl-ping-slave-period 10 #主节点默认每隔 10 秒对从节点发送 ping 命令
repl-timeout 60 #主从服务器超时时间(超时认为断线了),要比period设置的时间大

#如果master不能再正常工作,那么会在多个slave中,选择优先值最小的一个slave提升为master,
#优先值为0表示不能提升为master,一般在哨兵sentinel环境中使用。
slave-priority 100 

#在slave和master同步后,后续的同步是否设置成TCP_NODELAY,设置成no,则redis master会立即发送同步数据,没有延迟
repl-disable-tcp-nodelay no 
min-slaves-to-write 3 #主节点仅允许当能够通信的从节点数量大于等于此处的值时,才允许接受写操作;
min-slaves-max-lag 10 #从节点延迟时长超出此处指定的时间时,主节点会拒绝写入操作;

安全配置

requirepass foobared # 用来配置密码
rename-command CONFIG b84 #在公共环境下重命名部分敏感命令 如config、flushall等

限制配置

maxclients 10000 #最大连接数
maxmemory <bytes> #最大使用内存
maxmemory-policy volatile-lru #内存到极限后的处理策略

#内存处理策略,用于在超出内存限制时,删除一些key
volatile-lru # LRU算法删除过期key
allkeys-lru # LRU算法删除key(不区分过不过期)
volatile-random # 随机删除过期key
allkeys-random # 随机删除key(不区分过不过期)
volatile-ttl # 删除快过期的key
noeviction # 禁止删除key,这如果内存不足,会直接返回错误。默认配置

#用于提高LRU/TTL算法的精准度,在自动清理内存时,指定的数字越大,CPU消耗就越多,默认为5。
maxmemory-samples 5

AOF日志模式

appendonly no #是否启用日志模式
appendfsync no # 有系统决定何时写,统一写,速度快
appendfsync always # 系统不缓冲,一直写,但是慢,这种方式几乎不丢失数据
appendfsync everysec #每秒写1次

no-appendfsync-on-rewrite no #相当于将appendfsync设置为no,不存在磁盘操作,只是将数据写入了缓冲区,写入速度非常快
auto-AOF-rewrite-percentage 100 #触发aof重写操作,要求本次文件大小比上次重写时要增加1(100%)倍
auto-AOF-rewrite-min-size 64mb #触发aof重写操作,至少要达到的aof文件大小

慢查询配置

Redis slowlog 是一个记录 Redis 执行查询命令时所耗费时间的日志系统,它仅记录执行一个查询命令所耗费的时间,不记录其他内容。

slowlog-log-slower-than 10000 #记录响应时间大于10000微秒的慢查询
slowlog-max-len 128 # 最多记录128条

服务端命令

time #返回时间戳+微秒
dbsize #返回key的数量
bgrewriteaof #重写aof
bgsave #后台开启子进程来执行数据持久化
save #以阻塞的方式对数据进行持久化
lastsave #返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示。

slaveof host port #设置为host:port的从服务器(数据清空,复制新的主服务器内容)
slaveof no one   #变成主服务器(原数据不丢失,一般用于主服失败后)

flushdb 清空当前数据库的所有数据
flushall 清空所有数据库的所有数据

shutdown [save/nosave] 关闭服务器,保存数据,修改AOF

slowlog get 获取慢查询日志
slowlog len 获取慢查询日志条数
slowlog reset 清空慢查询

客户端命令

#以易于理解和阅读的方式返回Redis服务器的各种信息、统计数值
info [server|clients|memory|stats|]
config get [配置项]    #获取配置文件选项
config set [配置项] [参数值] #重新设置配置文件选项和对应参数
config rewrite  #对启动Redis服务器时所指定的配置文件进行改写
config resetstat #重置info命令中的某些统计信息

debug object key #调试选项,看一个key的情况
debug segfault #该命令能够让服务器崩溃
object key (refcount|encoding|idletime)
monitor #调试用,打开控制台,观察命令
client list #列出所有连接
client kill #杀死某个连接 CLIENT KILL 127.0.0.1:6379
client getname #获取连接的名称 默认nil
client setname  #设置连接名称,便于调试

连接命令

auth 密码  #验证登录密码(如果设置了密码)
ping      #测试服务器是否可用
echo "hello www.biancheng.net" #测试服务器是否正常交互
select 0/1/2/3/4...  #选择数据库0-15
quit  #退出连接

 

posted @ 2022-03-08 14:26  hanease  阅读(107)  评论(0编辑  收藏  举报