Redis
# Redis 基础
Redis 是用 C 语言开发的一个开源的高性能键值对数据库
Remote Dictionary Server (远程字典服务) 是完全开源的,使用 ANSIC 语言编写遵守 BSD 协议,是一个高性能的 Key-Value 数据库提供了丰富的数据结构,例如 String、Hash、List、Set、SortedSet 等等。数据是存在内存中的,同时 Redis 支持事务、持久化、LUA 脚本、发布 / 订阅、缓存淘汰、流技术等多种功能特性提供了主从模式、Redis Sentinel 和 Redis Cluster 集群架构方案
Redis 与传统数据库关系 (mysql)

- Redis 是 key-value 数据库 (NoSQL 一种),mysql 是关系数据库
- Redis 数据操作主要在内存,而 mysql 主要存储在磁盘
- Redis 在某一些场景使用中要明显优于 mysql,比如计数器、排行榜等方面
- Redis 通常用于一些特定场景,需要与 Mysql 一起配合使用
- 两者并不是相互替换和竞争关系,而是共用和配合使用
Reids 特征:
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作
- 高性能,性能极高 – Redis 能读的速度是 110000 次 / 秒,写的速度是 81000 次 / 秒
- 数据类型丰富,不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储
- 字符串类型 string
- 列表类型 list
- 双列类型 hash
- 集合类型 set
- 有序集合类型 zset/sorted_set
- 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
- 支持数据的备份,即 master-slave 模式的数据备份

# 安装
yum -y install gcc-c++
wget https://download.redis.io/releases/redis-6.2.5.tar.gz
tar -xvf redis-6.2.5.tar.gz
cd redis-6.2.5
make
make install
redis-server
# redis-server --port 6380 指定端口 默认为6379
#客户端
redis-cli
# redis-cli -p 6380
#创建存放配置和数据目录
mkdir conf
mkdir data
cp redis.conf ./conf
firewall-cmd --zone=public --add-port=6379/tcp --permanent
# 关闭redis服务器
redis-cli -a 123456 -p 6379 shutdown
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 配置文件
redis.conf
bind 192.168.130.128 #绑定对外访问的ip 建议为本机ip 也可注释掉任何主机都可访问
protected-mode no #关闭主机保护模式 yes为开启
requirepass 123456 #设置密码
port 6379
timeout 0 #客户端闲置等待时间 到时间关闭
daemonize yes #后台运行
logfile "log-6379.log" #日志文件名
dir root/redis-6.2.5/data
maxclients 0 #服务器允许最大连接数 默认为0无限
loglevel verbose #debug verbose notice waring 四个级别 开发期间为verbose 生产环境配置为notice 降低写日志IO的频度
redis-server /root/redis-6.2.5/conf/redis.conf
auth 123456
2
3
4
5
6
7
8
9
10
11
12
13
客户端连接
#连接
redis-cli
# redis-cli -a 123456 -p 6379 # 如果带密码则需要带 -a参数 或 在cli中使用 athu 123456 命令
auth 123456
2
3
4
# 数据类型指令

redis 自身是一个 MAP 所有的数据类型都是 键值对形式存储
命令参考文档:http://doc.redisfans.com/
官方命令大全文档:http://www.redis.cn/commands.html
命令不区分大小写,而 key 是区分大小写的
而数据类型指的 value 部分的类型 key 永远是字符串

# String(字符串)
string 是 redis 最基本的类型,一个 key 对应一个 value。
string 类型是二进制安全的,意思是 redis 的 string 可以包含任何数据,比如 jpg 图片或者序列化的对象 。
string 类型是 Redis 最基本的数据类型,一个 redis 中字符串 value 最多可以是 512M
一个存储空间保存一个数据,如果是数字也可以作为数字操作
# 添加数据
set key value # 添加/修改数据
setnx key value # 判断性添加数据,只有在 key 不存在时设置其值
setbit key offset value # 对其 key 所存储的字符串值,设置或清除指定偏移量上的位(bit)
setex key seconds value # 设置值并指定过期时间
mset key1 value1 key2 value2 [...] # m是Multiple缩写
msetnx key1 value1 key2 value2 [...] # 设置多个键值对,当所给顶 key 都不存在
setrange key offset value # 用value 参数覆盖给定 key 所存储的字符串值,从偏移量 offset 开始
psetex key milliseconds value # 以毫秒设置 key 的生存时间
# 获取数据
get key # 获取数据
getrange key start end # 返回key中字符串值的子字符,类似between......and的关系,从0到-1则代表全部范围
getset key value # 给指定key设置 value,并返回旧 value 的值,先get再set
getbit key offset # 获取指定key所存的字符串值偏移量的位(bit)
strlen key # 获取数据字符长度
mget key1 key2 [...] # 获取多个数据
# 删除数据
del key 删除数据
# 修改数据
incr key # 设置数值+1 如果key不存在 则从0开始并新建 只有数字字符串可以
incrby key increment # 设置数值+n
incrbyfloat key increment # 设置小数增加+n
decr key # 设置数值-1
decrby key increment #设置数值减少指定数值-n
append key value # 追加信息到原始信息后面 (如存在则追加 否则新建)
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
SET 命令有 EX、PX、NX、XX 以及 KEEPTTL 五个可选参数,其中 KEEPTT 工为 6.0 版本添加的可选参数,其它为 2.6.12 版本添加的可选参数。
- EX seconds:以秒为单位设置过期时间
- Px milliseconds:以毫秒为单位设置过期时间
- EXAT timestamp:设置以秒为单位的 UNIX 时间戳所对应的时间为过期时间
- PXAT milliseconds-timestamp:设置以毫秒为单位的 UNIX 时间戳所对应的时间为过期时间
- nx:键不存在的时候设置键值
- xx:键存在的时候设置键值
- KEEPTTL:保留设置前指定键的生存时间
- GET:返回指定键原本的值,若键不存在时返回
nil
注意事项:
- (integer) 0 为 false 1 为 true 即成功 也可能为运行的结果值
- 数据为获取到是 对应为 (nil) === null
- 数据最大的存储量为 512MB
- string 在内部存储就是一个字符串 当遇到增减类操作 incr,decr 时会转成数值类型进行计算
- 在操作数值时,如果原始数据不能转成数值或超出了 redis 数值的范围 将报错 java.long 的 MAX_VALUE
- redis 所有操作都是原子性,采用单线程处理所有业务,命令都是一个一个执行的,因此无需考虑并发带来的数据影响

# 哈希表(Hash)
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
Redis 中每个 hash 可以存储
一个存储空间保存多个键值对数据 hash 空间里面的 key 我们通常称为 field
如果 field 数比较少,存储结构会优化为数组,较多时为 HashMap 结构
# 添加数据
hmset key field1 value1 [field2 value2] # 设置多个filed
hset key field value # 添加/修改数据
hsetnx key field value # 设置field, 如果field存在则不做任何操作
# 删除数据
hdel key field1 [field2] # 删除hash指定的field
# 获取数据
hexists key field # 判断哈希表是否存在指定的field
hget key field # 获取数据
hgetall key # 获取整个hash
hvals key # 获取哈希所有的字段值
hkeys key # 获取哈希所有的字段名
hlen key # 获取哈希表中field的数量
hmget key field1 [field2] # 获取多个数据
hscan key cursor [match pattern] [count count] # 迭代哈希表的键值对
# 修改数据
hincrby key field increment # 设置指定字段的整数数值增加指定数值 可以为负数
hincrbyfloat key field increment # 设置指定字段的数值增加指定小数数值
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
注意事项:
- hash 类型中的 key 只能存储字符串 不允许其他数据类型
Map<String,Map<Object,Object>> - 每个 hash 可以存储 2 的 32 次方 - 1 个键值对
- hash 设计初衷不是为了存储大量对象而设计的 不可以将 hash 转为对象列表使用
- hgetall 操作可以获取全部属性 如果 field 过多 遍历整体数效率就会很低 造成数据访问瓶颈
# List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际是个双端链表,最多可以包含
一个存储空间保存多个数据 并且根据存储顺序一致 底层使用了双向链表存储结构实现
# 添加数据
lpush key value1 [value2] ... # 从列表头部添加数据 可以存储多个值
rpush key value1 [value2] ... # 从列表尾部添加数据
linsert key before|after pivot value # 在列表的元素前或后插入元素
rpushx key value # 为已存在的列表添加值
# 删除数据
blpop key [key2] timeout # 移除并获取列表中第一个元素,如果列表没有元素则会阻塞列表直到超时或有可弹元素为止,如果有多key则按顺序获取并移除 只有前面为nil后面的key才会执行 每次执行一次
brpop key [key2] timeout # 移除并获取列表中最后一个元素,如果列表没有元素则会阻塞列表直到超时或有可弹元素为止
brpoplpulsh source destination timeout # 从列表中弹出一个元素,并插入到另外一个列表中返回它,如果列表没有元素则会阻塞列表直到超时或有可弹元素为止
rpoplpush source destination # 移除列表最后一个元素,并添加到另外一个列表并返回
lpop key # 从列表获取第一个元素并移除数据
rpop key # 从列表获取最后一个元素并移除数据
lrem key count value # 移除指定个数的指定数据 如删除个数超出总个数或为0 则删除全部指定数据
ltrim key start stop # 对列表进行修剪,只保留指定区间的元素,其他元素则删除
# 获取数据
lrange key start stop # 获取指定范围的数据 下标从0开 -1为最后一个元素或list长度-1
lindex key index # 获取索引的数据 如索引越界则查询为nil
llen key # 获取list长度
# 修改元素
lset key index value # 通过索引设置元素的值
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意事项:
- list 数据都是 string 类型 最多 2 的 32 次方 - 1 个元素
- list 有索引的概念,但操作数据通常以队列形式入队出队 或以栈的形式
- 获取全部数据的操作结束索引为 - 1
- list 可以对数据进行分页操作 第一页数据来源 list 而第二页后的通常以数据库形式加载
一个双端链表的结构,容量是 2 的 32 次方减 1 个元素,大概 40 多亿,主要功能有 push/pop 等,一般用在栈、队列、消息队列等场景。 left、right 都可以插入添加; 如果键不存在,创建新的链表; 如果键已存在,新增内容; 如果值全移除,对应的键也就消失了。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

# Set(集合)
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,集合对象的编码可以是 intset 或者 hashtable。
Redis 中 Set 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O (1)。集合中最大的成员数为
set 与 hash 存储结构完全相同,但 set 只存储键,不存储值 值为 nil 并且值是不允许重复的
# 添加数据
sadd key member1 [member2] # 添加数据
# 删除数据
smove source destination member # 将指定数据从A集合移动到B集合
spop key [count] # 移除并返回集合中随机一个元素或多个元素
srem key member1 [member2] # 删除指定数据
# 获取数据
scard key # 获取集合数据总量
sdiff key1 [key2 ...] # 求两个集合的差集
sdiffstore destination key [key2 ...] # 求两个集合的差集并存储到指定集合中
sinter key1 [key2 ...] # 求两个集合的交集
sinterstore destination key [key2 ...] # 求两个集合的交集并存储到指定集合中
sintercard numkeys key [key2 ..] [LIMIT limit] # 求两集合的交集只返回结果集合的基数
sismember key member # 判断集合中是否包含指定数据
smembers key # 获取全部数据
srandmember key [count] # 随机获取集合中指定数量的数据,不删除元素
sunion key1 [key2 ...] # 求两个集合的并集
sunionstore destination key [key2 ...] # 求两个集合的并集并存储到指定集合中
sscan key cursor [MATCH pattern] [COUNT count] # 迭代集合中的元素
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
注意事项:
- set 不允许数据重复
- set 虽然和 hash 的存储结构相同,但无法使用存储值的空间
# 有序集合(ZSet)
Redis zset 和 set 一样也是 string 类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个 double 类型的分数,redis 正是通过分数来为集合中的成员进行从小到大的排序。
zset 的成员是唯一的,但分数 (score) 却可以重复。
zset 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O (1)。 集合中最大的成员数为
在 set 基础上,每个 val 值前加一个 score 分数值。
# 添加数据
zadd key score1 member1 [score2 member2] # 添加一个或多个成员,如已存在则修改其score
zinterstore destination numkeys key [key ...] # 计算一个或多个有序集合的交集并存储到新的有序集合key中
# 删除数据
zerm key member [member ...] # 移除一个或多个成员
zremrangebylex key min max # 移除给定的字典区间的所有成员
zermrangebyrank key start stop # 移除给定排名区间的所有成员
zremrangebyscore key min max # 移除给定分数区间的所有成员
# 获取数据
zcard key # 获取有序集合的成员数
zcount key min max # 计算指定区间分数的成员数
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 # 返回指定成员的索引
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] # 迭代有序集合的元素,包含元素成员和元素分值
zmpop numkeys key [key ...] <MIN | MAX> [COUNT count] # 从键名列表中的第一个非空排序集中弹出一个或多个元素,它们是成员分数对。当使用MIN修饰符时,弹出的元素是第一个非空排序集中得分最低的元素。MAX修改器会弹出得分最高的元素,numkeys 表示 key 的数量。
# 修改数据
zincrby key increment member # 对指定成员的分数增量 increment
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
# 地理空间(GEO)
Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,包括:
- 添加地理位置的坐标。
- 获取地理位置的坐标。
- 计算两个位置之间的距离。
- 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合
核心思想就是将球体转换为平面,区块转换为一点

主要分为三步:将三维的地球变为二维的坐标,在将二维的坐标转换为一维的点块,最后将一维的点块转换为二进制再通过 base32 编码。
geoadd key longitude latitude member [longitude latitude member ...] #添加一个或多经度、维度、位置名称到指定key中 注:如包含中文会出现乱码 需要使用 redis-cli --raw 命令登录客户端
geopos key member [member ...] # 返回指定名称的位置,不存在返回 nil
geohash key member [member ...] # 获取一个或多个元素的 geohash 值,geohash为算法生成的base32编码值
geodist key member1 member2 [m|km|ft|mi] # 返回两个给定位置的距离,m 米、km 千米、ft 英尺、mi 英里
2
3
4
查找范围内的元素
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] # 找出位于指定范围的元素,中心点是由给定的元素决定的
2
- WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
- WITHCOORD: 将位置元素的经度和维度也一并返回。
- WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
- COUNT 限定返回的记录数。
- ASC: 查找结果根据距离从近到远排序。
- DESC: 查找结果根据从远到近排序。
# 基数统计(HyperLogLog)
HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
去重复统计功能的基数估计算法 - 就是 HyperLogLog,是一种数据集,去重复后的真实个数
用于统计一个集合中不重复的元素个数,就是对集合去重复后剩余元素的计算,一般用于统计某个网站的 UV、统计某个文章的 UV。

pfadd key element [element] # 添加指定元素到 hyperloglog
pfcount key [key ...] # 返回给定 hyperloglog 的基数估算值
pfmerge destkey sourcekey [sourcekey ...] # 将多个 hyperloglog 合并为一个
2
3
# 位图(bitmap)

由 0 和 1 状态表现的二进制位的 bit 数组
用 String 类型作为底层数据结构实现的一种统计二值状态的数据类型
位图本质是数组,它是基于 String 数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量 (我们称之为一个索引)。
Bitmap 支持的最大位数是
| 命令 | 作用 | 时间复杂度 |
|---|---|---|
| setbit key offset val | 给指定 key 的值的第 offset 赋值 val,偏移位只能零或者 1 | 0(1) |
| getbit key offset | 获取指定 key 的第 offset 位 | 0(1) |
| bitcount key start end | 返回指定 key 中 [start,end] 中为 1 的数量 | O(n) |
| bitop operation destkey key | 对不同的二进制存储数据进行位运算 (AND、OR、NOT、XOR) | O(n) |
# 位域(bitfield)
通过 bitfield 命令可以一次性操作多个比特位域 (指的是连续的多个比特位),它会执行一系列操作并返回一个响应数组,这个数组中的元素对应参数列表中的相应操作的执行结果。
说白了就是通过 bitfield 命令我们可以一次性对多个比特位域进行操作。
BITFIELD 命令的作用在于它能够将很多小的整数储存到一个长度较大的位图中,又或者将一个非常庞大的键分割为多个较小的键来进行储存,从而非常高效地使用内存,使得 Redis 能够得到更多不同的应用一特别是在实时分析领域:BITFIELD 能够以指定的方式对计算谥出进行控制的能力,使得它可以被应用于这一领域。
BITFIELD 命令可以将一个 Rdis 字符串看作是一个由二进制位组成的数组,并对这个数组中任意偏移进行访问。可以使用该命令对一个有符号的 5 位整型数的第 1234 位设置指定值,也可以对一个 31 位无符号整型数的第 4567 位进行取值。类似地,本命令可以对指定的整数进行自增和自减操作,可配置的上谥和下溢处理操作。BITFIELD 命令可以在一次调用中同时对多个位范围进行操作:它接受一系列待执行的操作作为参数,并返回一个数组,数组中的每个元素就是对应操作的执行结果。
例如,对位于 5 位有符号整数的偏移量 100 执行自增操作,并获取位于偏移量 0 上的 4 位长无符号整数:
# SET
设置指定位域的值并返回它的值
BITFIELD key [SET type offset value]
案例
set fieldkey hello
BITFIELD fieldkey set i8 8 120 # 从第9个位开始。将接下来8个位用有符号数120(字母x)替换
2
# GET
返回指定的位域
BITFIELD key [GET type offset]
案例
set fieldkey hello
BITFIELD fieldkey get i8 0 # 104
BITFIELD fieldkey get i8 8 # 101
BITFIELD fieldkey get i8 16 # 108
BITFIELD fieldkey get i8 24 # 108
BITFIELD fieldkey get i8 32 # 111
2
3
4
5
6
当需要一个整型时,有符号整型需在位数前加 i, 无符号在位数前加 u。例如,u8 是一个 8 位的无符号整型,i16 是一个 16 位的有符号整型。
| 字母 | 数值 | 二进制 (高位 <- 低位) |
|---|---|---|
| h | 104 | 0110 1000 |
| e | 101 | 0110 0101 |
| l | 108 | 0110 1100 |
| l | 108 | 0110 1100 |
| o | 111 | 0110 1111 |
hello 等价于 0110100001100101011011000110110001101111
# INCRBY
自增或自减(如果 increment 为负数)指定位域的值并返回它的新值,默认情况下,INCRBY 使用 WRAP 参数
BITFIELD key [INCRBY type increment]
案例
set fieldkey hello
BITFIELD fieldkey INCRBY u4 2 1 # 11 对接下来的4位无符号数+1
BITFIELD fieldkey INCRBY u4 2 1 # 12
BITFIELD fieldkey INCRBY u4 2 1 # 13
BITFIELD fieldkey INCRBY u4 2 1 # 14
BITFIELD fieldkey INCRBY u4 2 1 # 15
BITFIELD fieldkey INCRBY u4 2 1 # 0 默认overflow为wrap,即循环溢出
2
3
4
5
6
7
# OVERFLOW
溢出控制
BITFIELD key OVERFLOW [WRAP|SAT|FAIL] [SET type offset value]
- WRAP: 使用回绕(wrap around)方法处理有符号整数和无符号整数的溢出情况
- SAT: 使用饱和计算(saturation arithmetic)方法处理溢出,下溢计算的结果为最小的整数值,而上溢计算的结果为最大的整数值
- FAIL: 命令将拒绝执行那些会导致上溢或者下溢情况出现的计算,并向用户返回空值表示计算未被执行
# 流(Stream)
Redis Stream 是 Redis 5.0 版本新增加的数据结构。
Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。
而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失
在 redis 5.0 之前我们常用 List 实现消息队列,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 所以常用来做异步队列使用,将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理。

List 实现方式其实就是点对点的模式
而发布订阅 (pub/sub) 有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。而且也没有 Ack 机制来保证数据的可靠性,假设一个消费者都没有,那消息就直接被丢弃了。
而 5.0 新增加 Stream 数据结构,由官方实现的 Redis 版的 MQ 消息中间件 + 阻塞队列
该数据结构实现消息队列,它支持消息的持久化、支持自动生成全局唯一 ID、支持 ack 确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠
# 底层结构和原理
一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容

| 1 | Message Content | 消息内容 |
|---|---|---|
| 2 | Consumer group | 消费组,通过 XGROUP CREATE 命令创建,同一个消费组可以有多个消费者 |
| 3 | Last_delivered_id | 游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。 |
| 4 | Consumer | 消费者,消费组中的消费者 |
| 5 | Pending_ids | 消费者会有一个状态变量,用于记录被当前消费已读取但未 ack 的消息 Id,如果客户端没有 ack,这个变量里面的消息 ID 会越来越多,一旦某个消息被 ack 它就开始减少。这个 pending_ids 变量在 Redis 官方被称之为 PEL (Pending Entries List),记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符),它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了没处理 |
# XADD 命令
将指定的流条目添加到指定键的流中。如果键不存在,键将以流值创建。可以用 NOMKSTREAM 选项禁用流的键的创建。
一个条目是由 “字段 - 值” 对的列表组成的。“字段 - 值” 对的存储顺序与用户给出的顺序相同。读取数据流的命令,如 XRANGE 或 XREAD,保证完全按照 XADD 添加的顺序返回字段和值。
XADD key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] threshold [LIMIT count]] <* | id> field value [field value ...]
- NOMKSTREAM 当添加流时,流不存在,该选项用来禁用流的键的创建
- MAXLEN 只要流的长度超过指定的阈值,就驱逐条目,其中阈值是一个正整数。
- MINID 驱逐条目 ID 低于阈值的条目,其中阈值是一个流条目 ID。
- [= | ~] 指定裁剪的精度,= 表示精确裁剪,~ 表示近乎精确裁剪
- threshold 一个阈值,如果用于 MAXLEN 表示流最大条目数量,如果用于 MINID 表示一个条目 ID
- <* | id> 用来定义流条目 ID,* 号表示自动生成条目 ID,id 表示一个具体的条目 ID,注意如指定 id 需要比上一个 id 大才能添加
- field value 用来指定字段和值,它们是成对出现
XADD mystream 1526919030474-55 message "Hello,""1526919030474-55" # 向流 mystream 中添加一个 id 为 1526919030474-55 的条目
XADD mystream * message " World!" # 向流 mystream 中添加一个条目,id 自动生成
2
3
# XRANGE 命令
用来返回指定条目 ID 范围内的 count 个条目
XRANGE key start end [COUNT count]
- start 表示开始值,- 代表最小值
- end 表示结束值,+ 代表最大值
- count 表示最多获取多少个值,不传递则为全部
XRANGE mystream 1526919030474-3 1526919030474-6 COUNT 2 # 返回条目ID在 1526919030474-3 ~ 1526919030474-6 之间的两个条目
XRANGE mystream + - COUNT 1
XRANGE mystream - + COUNT 1
2
3
# XREVRANGE 命令
与 XRANGE 的区别在于,获取消息列表元素的方向是相反的,end 在前,start 在后
XREVRANGE key start end [COUNT count]
# XDEL 命令
从流中删除指定的条目,并返回已删除的条目数。在流中不存在某些指定 ID 的情况下,此数字可能小于传递给命令的 ID 的数量。
XDEL key id [id ...]
Redis 流以一种使其内存高效的方式表示:为了索引线性包装数十个流条目的宏节点,使用了基数树。通常情况下,当您从流中删除一个条目时,该条目并没有真正被删除,它只是被标记为已删除。通常情况下,当你从一个流中删除一个条目时,该条目不会被真正驱逐,它只是被标记为删除。
# XLEN 命令
用于获取 Stream 队列的消息的长度
XLEN key
# XTRIM 命令
用于对 Stream 的长度进行截取,如超长会进行截取
XTRIM key <MAXLEN | MINID> [= | ~] threshold [LIMIT count]
- MAXLEN: 允许的最大长度,对流进行修剪限制长度
- MINID: 允许的最小 id,从某个 id 值开始比该 id 值小的将会被抛弃
# XREAD 命令
该命令用来从一个或多个数据流中读取数据,只返回 ID 大于调用者指定的条目 ID。该命令还有一个 BLOCK 选项,如果条目不可用,则直接阻塞
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
- BLOCK 是否已阻塞的方式读取消息,默认不阻塞,如果 milliseconds 设置为 0,表示永远阻塞
实例
XREAD count 2 streams mystream $ # $代表特殊ID,表示以当前Stream已经存储的最大的ID作为最后一个ID,当前Stream中不存在大于当前最大ID的消息,因此此时返回nil
XREAD count 2 streams mystream 0-0 # 0-0代表从最小的ID开始获取Stream中的消息,当不指定count,将会返回Stream中的所有消息,注意也可以使用0(00/000也都是可以的……)
XREAD count 2 streams mystream 000 # 同上
XREAD count 2 block 0 streams mystream $
2
3
4
Stream 的基础方法,使用 xadd 存入消息和 xread 循环阻塞读取消息的方式可以实现简易版的消息队列,交互流如下

# XGROUP CREATE 命令
用来为指定的流创建一个新的使用者组,在流中,每个组都有一个唯一的名字。当一个同名的消费组已经存在时,该命令会返回一个 BUSYGROUP 错误。
XGROUP CREATE key group <id | $> [MKSTREAM] [ENTRIESREAD entries-read]
- $ 表示从 Stream 尾部开始消费
- 0 表示从 Stream 头部开始消费
- 创建消费者组的时候必须指定 ID, ID 为 0 表示从头开始消费,为 $ 表示只消费新的消息,队尾新来
# XREADGROUP GROUP 命令
stream 中的消息一旦被消费组里的一个消费者读取了,就不能再被该消费组内的其他消费者读取了,即同一个消费组里的消费者不能消费同一条消息。刚才的 XREADGROUP 命令再执行一次,此时读到的就是空值。但是,不同消费组的消费者可以消费同一条消息。
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]
案例
xreadgroup group mygroup1 myconsumer1 count 1 streams mystream > # >表示从第一条尚未被消费的消息开始读取
xreadgroup group mygroup2 myconsumer1 count 1 streams mystream >
2
让组内的多个消费者共同分担读取消息,所以,我们通常会让每个消费者读取部分消息,从而实现消息读取负载在多个消费者间是均衡分布的
xreadgroup group mygroup1 myconsumer1 count 1 streams mystream >
xreadgroup group mygroup1 myconsumer2 count 1 streams mystream >
2
# XPENDING 命令
查询每个消费组内所有消费者「已读取、但尚未确认」的消息
XPENDING STREAMS group
# XACK 命令
向消息队列确认消息处理已完成
XPENDING STREAMS group id
# XINFO 命令
用于打印 Stream\Consumer\Group 的详细信息
# 常用指令
# key
- del key 删除指定 key
- unlink key 非阻塞删除,仅仅将 keys 从 keyspace 元数据中删除,真正的删除会在后续异步中操作。
- dump key 序列号给指定 key,并返回被序列号的值
- exists key 判断 key 是否存在
- type key 获取 key 的类型
- sort key 排序 默认对数字排序 如果要按自然排序则 需要指定 alpha 查询出来是排序 原数据不做改变 并且可以根据 ASC|DESC 指定升降序
- rename key new key 重命名
- renamenx key newkey 存在则修改 否则不做任何操作
- expire key seconds 为指定 key 设置有效期 秒
- pexpire key milliseconds 为指定 key 设置有效期 毫秒
- expireat key timestamp 时间戳
- pexpireat key milliseconds-timestamp 毫秒级时间戳
- ttl key 获取 key 的有效时间 秒 -1 为永久 -2 为不存在
- pttl key 获取 key 的有效时间 毫秒
- persist key 将此 key 转为永久性
- randomkey 随机返回一个 key
- keys pattern 表达式查询
# db
rdis 服务器默认提供 16 个数据库 从 0 到 15 默认为 0 每个数据库之间的数据相互独立
- select index 切换数据库
- ping 测试与服务器是否连同 发送消息
- move key db 数据移动
- dbsize 当前数据库 key 总量
- flushdb 当前数据库清除
- flushall 全部数据库清除
# Redis 7.0 新特征
# Redis Functions
Redis 函数,一种新的通过服务端脚本扩展 Redis 的方式,函数与数据本身一起存储。
简言之,redis 自己要去抢夺 Lua 脚本的饭碗

# Client-eviction
限制客户端内存使用(Client-eviction)一旦 Redis 连接较多,再加上每个连接的内存占用都比较大的时候, Redis 总连接内存占用可能会达到 maxmemory 的上限,可以增加允许限制所有客户端的总内存使用量配置项, redis.config 中对应的配置项
# 两种配置形式:指定内存大小、基于 maxmemory 的百分比。
maxmemory-clients 1g
maxmemory-clients 10%
2
3

# Multi-part AOF
多 AOF 文件支持,7.0 版本中一个比较大的变化就是 aof 文件由一个变成了多个,主要分为两种类型:基本文件 (base files)、增量文件 (incr files),请注意这些文件名称是复数形式说明每一类文件不仅仅只有一个。在此之外还引入了一个清单文件 (manifest) 用于跟踪文件以及文件的创建和应用顺序(恢复)

# ACL V2
访问安全性增强 ACLV2,在 redis.conf 配置文件中, protected-mode 默认为 yes,只有当你希望你的客户端在没有授权的情况下可以连接到 Redis server 的时候可以将 protected-mode 设置为 no

# 新增命令
新增 ZMPOP,BZMPOP,LMPOP,BLMPOP 等新命令,对于 EXPIRE 和 SET 命令,新增了更多的命令参数选项。
例如,ZMPOP 的格式如下:ZMPOP numkeys key [key ...],MIN|MAX [COUNT count], 而 BZMPOP 是 ZMPOP 的阻塞版本。
- Zset (有序集合) 增加 ZMPOP、BZMPOP、ZINTERCARD 等命令
- Set (集合) 增加 SINTERCARD 命令
- LIST (列表) 增加 LMPOP、BLMPOP ,从提供的键名列表中的第一个非空列表键中弹出一个或多个元素。
对于 Config Set 和 Get 命令,支持在一次调用过程中传递多个配置参数。例如,现在我们可以在执行一次 Config Set 命令中更改多个参数:
config set maxmemory 10000001 maxmemory-clients 50% port 6399
# listpack 替代 ziplist
listpack 紧凑列表调整,listpack 是用来替代 ziplist 的新数据结构,在 7.0 版本已经没有 ziplist 的配置了(6.0 版本仅部分数据类型作为过渡阶段在使用)。listpack 已经替换了 ziplist 类似 hash-max-ziplist-entries 的配置

# 底层性能提升

