0 Redis 常见命令
# 在Linux终端使用 redis-cli 命令进入redis
parallels@ubuntu-linux-22-04-02-desktop:~$ redis-cli
127.0.0.1:6379>
# 解决中文乱码 `redis-cli -a --raw` 只要有--raw就可以显示中文
parallels@ubuntu-linux-22-04-02-desktop:~$ redis-cli -a 11 --raw
127.0.0.1:6379>
KEYS pattern
EXISTS key [key ...]
TYPE key
DEL key [key ...]
UNLINK key [key ...]
不同的是若key很大在高并发情况下del删除会导致阻塞,unlink是非阻塞删除,将key从keyspace元数据中删除,真正的删除会在后续移步中执行
EXPIRE key seconds [NX | XX | GT | LT]
TTL key # -1表示永不过期 -2表示已过期
MOVE key db # 将key移动到数据库(Redis默认有16个数据库)
SELECT index
FLUSHDB [ASYNC | SYNC]
FLUSHALL [ASYNC | SYNC]
具体命令:
# set key value 设置一个key(区分大小写)
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
# get key 获取 value
127.0.0.1:6379> get k1
"v1"
# keys * 查看当前库中所有的 key
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
# exists key 判断某个key是否存在(返回的是1或0,因为Redis是使用C语言编写,1表示true,0表示false)
127.0.0.1:6379> EXISTS k1
(integer) 1
127.0.0.1:6379> EXISTS k11
(integer) 0
127.0.0.1:6379> EXISTS k1 k2 k33
(integer) 2
# type key 查看key的数据类型
127.0.0.1:6379> type k1
string
# lpush key [element...] 创建一个列表
127.0.0.1:6379> lpush l1 1 2 3 4
(integer) 4
# lrange key start stop 查看列表
127.0.0.1:6379> lrange l1 0 3
1) "4"
2) "3"
3) "2"
4) "1"
# 查看l1的数据类型
127.0.0.1:6379> type l1
list
# del key 和 unlink key 删除key,不同的是若key很大在高并发情况下del删除会导致阻塞,unlink是非阻塞删除,将key从keyspace元数据中删除,真正的删除会在后续移步中执行
127.0.0.1:6379> del l1
(integer) 1
127.0.0.1:6379> unlink k3
(integer) 1
# expire key seconds 给key设置过期时间 过期的key会删除
127.0.0.1:6379> expire k2 30
(integer) 1
# ttl key 查看还有多少秒过期 -1表示永不过期 -2表示已过期
127.0.0.1:6379> ttl k2
(integer) 18
127.0.0.1:6379> ttl k2
(integer) -2
127.0.0.1:6379> ttl k1
(integer) -1
# k2已过期 删除
127.0.0.1:6379> keys *
1) "k1"
# move key dbindex 将key移动到数据库(Redis默认有16个数据库)
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> move k1 10 # 将k1移动到第10个数据库
(integer) 1
127.0.0.1:6379> keys * # 此时db0为空
(empty array)
# select dbindex 切换到第10个数据库
127.0.0.1:6379> select 10
OK
127.0.0.1:6379[10]> keys * # 此时db10有一个key
1) "k1"
# 查看当前数据库 key 的数量
127.0.0.1:6379[10]> dbsize
(integer) 1
# flushdb 清空当前数据库
127.0.0.1:6379[10]> flushdb
OK
127.0.0.1:6379[10]> dbsize
(integer) 0
# flushall 删除全部数据
127.0.0.1:6379[10]> flushall
OK
1 String 字符串
Redis strings store sequences of bytes, including text, serialized objects, and binary arrays. As such, strings are the simplest type of value you can associate with a Redis key. They’re often used for caching, but they support additional functionality that lets you implement counters and perform bitwise operations, too.
常用操作:
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
# 方括号内'[]'表示可选的项,竖杠'|'表示或
GET key
MSET key value [key value ...]
MGET key [key ...]
MSETNX key value [key value ...]
GETRANGE key start end # 类似 between...and 的关系
SETRANGE key offset value # offset和value可选,offset表示从第几个开始更改,value表示值
INCR key [increment]
DECR key [decrement]
STRLEN key
APPEND key value
GETSET key value # 返回key的值之后再将value赋值给key
具体实操:
# 最常用 get set
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
# SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
# set key value nx (nx: key不存在添加)
127.0.0.1:6379> set k1 v11 nx
(nil)
127.0.0.1:6379> get k1
"v1"
# set key value xx (xx: key不存在则创建,存在则更改,默认为xx)
127.0.0.1:6379> set k1 v11
OK
127.0.0.1:6379> get k1
"v11"
# mset / mget 同时设置/获取多个key
127.0.0.1:6379> mset k2 v2 k3 v3 k4 v4
OK
127.0.0.1:6379> mset k1 v1 k5 v5
OK
127.0.0.1:6379> mget k1 k2 k3 k4 k5
1) "v11"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
# msetnx 当都不存在时创建,当有一个存在则都不创建
127.0.0.1:6379> msetnx k6 v6 k7 v7
(integer) 1
127.0.0.1:6379> msetnx k1 v1 k8 v8
(integer) 0
127.0.0.1:6379> keys *
1) "k4"
2) "k5"
3) "k6"
4) "k2"
5) "k3"
6) "k7"
7) "k1"
# 获取指定区间范围内的值
# GETRANGE key start end: 获取指定区间范围内的值,类似 between...and 的关系
127.0.0.1:6379> set k8 abcdefghij
OK
127.0.0.1:6379> getrange k8 0 -1
"abcdefghij"
127.0.0.1:6379> getrange k8 1 4
"bcde"
# SETRANGE key offset value: 设置指定区间范围内的值,格式是setrange key 值 具体值
127.0.0.1:6379> setrange k8 7 7777
(integer) 11
127.0.0.1:6379> get k8
"abcdefg7777"
# 数值增减
# incr key: 递增数字
127.0.0.1:6379> set k10 1
OK
127.0.0.1:6379> incr k10
(integer) 2
127.0.0.1:6379> incr k10
(integer) 3
127.0.0.1:6379> incr k10
(integer) 4
127.0.0.1:6379> incr k10
(integer) 5
# incr key increment: 增加指定的整数
127.0.0.1:6379> incrby k10 5
(integer) 10
127.0.0.1:6379> incrby k10 5
(integer) 15
127.0.0.1:6379> incrby k10 5
(integer) 20
# decr key: 递减数字
127.0.0.1:6379> decr k10
(integer) 19
127.0.0.1:6379> decr k10
(integer) 18
127.0.0.1:6379> decr k10
(integer) 17
# decrby key decrement: 减少指定的整数
127.0.0.1:6379> decrby k10 2
(integer) 15
127.0.0.1:6379> decrby k10 2
(integer) 13
# 获取字符串长度和内容追加
# strlen key: 获取字符串长度
# append key value: 在尾部追加
127.0.0.1:6379> get k8
"abcdefg7777"
127.0.0.1:6379> strlen k8
(integer) 11
127.0.0.1:6379> append k8 8888
(integer) 15
127.0.0.1:6379> get k8
"abcdefg77778888"
# getset
# getset:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。简单一句话,先get然后立即set
127.0.0.1:6379> get k1
"v11"
127.0.0.1:6379> getset k1 v1
"v11"
127.0.0.1:6379> get k1
"v1"
2 List 列表
Redis lists are linked lists of string values. Redis lists are frequently used to:
- Implement stacks and queues.
- Build queue management for background worker systems.
一个双端链表的结构,容量是2^32-1
个元素,大概40多亿,主要功能有push/pop等,一般用在栈、队列、消息队列等场景。
left、right都可以插入添加;
如果键不存在,创建新的链表;
如果键已存在,新增内容;
如果值全移除,对应的键也就消失了。
- 它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
常用操作:
LPUSH key element [element ...]
RPUSH key element [element ...]
RPUSH key element [element ...]
LPOP key [count]
RPOP key [count]
LINDEX key index
LLEN key
LREM key count element # 删除列表key中count个element
LTRIM key start stop # 将key中start到stop的元素赋值给key,相当于substring(start是从0开始)
RPOPLPUSH source destination # 将source的元素pop出去并push到destination中
LSET key index element # 将key中第index个元素设置成element
LINSERT key <BEFORE | AFTER> pivot element # 在key中第pivot个元素前|后插入element
具体操作:
# lpush / rpush / lrange
# lpush key [element...] 从左边添加
127.0.0.1:6379> lpush list1 1 2 3 4 5
(integer) 5
# rpush key [element...] 从右边添加
127.0.0.1:6379> rpush list2 11 12 13 14 15
(integer) 5
# lrange key start stop 从左到右读list(0 -1 是从头到尾)
127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> lrange list2 0 -1
1) "11"
2) "12"
3) "13"
4) "14"
5) "15"
127.0.0.1:6379> lrange list2 0 3
1) "11"
2) "12"
3) "13"
4) "14"
# lpop / rpop
# lpop key [count] 从左弹出
127.0.0.1:6379> lpop list1
"5"
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
# rpop key [count] 从右弹出
127.0.0.1:6379> rpop list1
"1"
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
# lindex key index 按照索引下标获得元素(从左到右)
127.0.0.1:6379> lindex list2 3
"14"
127.0.0.1:6379> lrange list2 0 -1
1) "11"
2) "12"
3) "13"
4) "14"
5) "15"
# llen key 获取列表中元素的个数
127.0.0.1:6379> llen list2
(integer) 5
# lrem key count element 删除列表key中count个element
127.0.0.1:6379> lpush list3 1 1 1 1 1 2 2 2 2 3 3 3 4 4 5
(integer) 15
# 一共有5个1,删除4个1
127.0.0.1:6379> lrem list3 4 1
(integer) 4
# 一共有4个2,删除4个2
127.0.0.1:6379> lrem list3 4 2
(integer) 4
# 一共3个3,删除4个3(实际上只删除了3个,不会报错)
127.0.0.1:6379> lrem list3 4 3
(integer) 3
127.0.0.1:6379> lrange list3 0 -1
1) "5"
2) "4"
3) "4"
4) "1"
# ltrim key start stop 将key中start到stop的元素赋值给key,相当于substring(start是从0开始)
127.0.0.1:6379> ltrim list3 1 3
OK
127.0.0.1:6379> lrange list3 0 -1
1) "4"
2) "4"
3) "1"
# ltrim list3 1 3 没有3元素,但也是可以
127.0.0.1:6379> ltrim list3 1 3
OK
127.0.0.1:6379> lrange list3 0 -1
1) "4"
2) "1"
# rpoplpush source destination 将source的元素pop出去并push到destination中
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
127.0.0.1:6379> lrange list2 0 -1
1) "11"
2) "12"
3) "13"
4) "14"
5) "15"
# list1中的2pop出去并push到list2中
127.0.0.1:6379> rpoplpush list1 list2
"2"
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
127.0.0.1:6379> lrange list2 0 -1
1) "2"
2) "11"
3) "12"
4) "13"
5) "14"
6) "15"
# lset key index element 将key中第index个元素set成element
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
127.0.0.1:6379> lset list1 0 java
OK
127.0.0.1:6379> lset list1 1 mysql
OK
127.0.0.1:6379> lrange list1 0 -1
1) "java"
2) "mysql"
# 超出index会报错
127.0.0.1:6379> lset list1 2 redis
(error) ERR index out of range
# linsert key BEFORE|AFTER pivot element 在key中第pivot个元素前|后插入element
127.0.0.1:6379> linsert list1 before java c++
(integer) 3
127.0.0.1:6379> lrange list1 0 -1
1) "c++"
2) "java"
3) "mysql"
127.0.0.1:6379> linsert list1 after mysql oracle
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "c++"
2) "java"
3) "mysql"
4) "oracle"
# pivot不存在则爆-1
127.0.0.1:6379> linsert list1 after redis spring
(integer) -1
3 Hash 哈希
Redis hashes are record types structured as collections of field-value pairs. You can use hashes to represent basic objects and to store groupings of counters, among other things.
熟悉编程语言的一定不陌生,Redis的Hash就相当于KV模式不变,只是V是一个KV对,相当于Map<String, Map<Object, Object>>
常用操作:
HSET key field value [field value ...] # 相当于设置一个key,后面是每一个KV对
HGET key field # 获取key的一个KV对(这里要是多个KV对会报错)
HMGET key field [field ...] # 获取多个KV对
HMSET key field value [field value ...]
HGETALL key # 获取key中所有KV对,显示时是一个key一个value
HDEL key field [field ...] # 删除key中的一个或几个KV对,不能删除key
HLEN key
HEXISTS key field # 判断key中是否有field字段,0为false,1为true
HVALS key
HINCRBY key field increment # 将key的field字段的value增加increment(int)
HINCRBYFLOAT key field increment # 将key的field字段的value增加increment(float)
HSETNX key field value
具体操作:
# hset key field value [field value ...] 相当于设置一个key,后面是每一个KV对
127.0.0.1:6379> hset user001 id 001 name Tom age 18
(integer) 3
# hget key field 获取key的一个KV对(这里要是多个KV对会报错)
127.0.0.1:6379> hget user001 id
"001"
127.0.0.1:6379> hget user001 name
"Tom"
127.0.0.1:6379> hget user001 name age
(error) ERR wrong number of arguments for 'hget' command
# hmget key field [field ...] 获取多个KV对
127.0.0.1:6379> hmget user001 name age
1) "Tom"
2) "18"
# hmset key field value [field value ...] 在官方文档中hmset不建议使用,建议使用hset代替
# It can be replaced by HSET with multiple field-value pairs when migrating or writing new code.
127.0.0.1:6379> hmset user002 id 002 name Jerry age 16
OK
# hgetall key 获取key中所有KV对,显示时是一个key一个value
127.0.0.1:6379> hgetall user001
1) "id"
2) "001"
3) "name"
4) "Tom"
5) "age"
6) "18"
# hdel key field [field ...] 删除key中的一个或几个KV对,不能删除key
127.0.0.1:6379> hdel user002 age name
(integer) 2
127.0.0.1:6379> hgetall user002
1) "id"
2) "002"
127.0.0.1:6379> hdel user002
(error) ERR wrong number of arguments for 'hdel' command
# hlen key 获取key的长度
127.0.0.1:6379> hlen user001
(integer) 3
127.0.0.1:6379> hlen user002
(integer) 1
# hexists key field 判断key中是否有field字段,0为false,1为true
127.0.0.1:6379> hexists user001 name
(integer) 1
127.0.0.1:6379> hexists user001 sex
(integer) 0
# hkeys key 获取key中的key
127.0.0.1:6379> hkeys user001
1) "id"
2) "name"
3) "age"
# hvals key 获取key中的value
127.0.0.1:6379> hvals user001
1) "001"
2) "Tom"
3) "18"
# hincrby key field increment 将key的field字段的value增加increment(int)
127.0.0.1:6379> hset user003 k1 1
(integer) 1
127.0.0.1:6379> hincrby user003 k1 2
(integer) 3
127.0.0.1:6379> hget user003 k1
"3"
# hincrbyfloat key field increment 将key的field字段的value增加increment(float)
127.0.0.1:6379> hincrbyfloat user003 k1 4.5
"7.5"
127.0.0.1:6379> hget user003 k1
"7.5"
# hsetnx key field value 若key中没有field字段则添加,有则取消
127.0.0.1:6379> hsetnx user003 name John
(integer) 1
127.0.0.1:6379> hsetnx user003 name Ross
(integer) 0
127.0.0.1:6379> hget user003 name
"John"
127.0.0.1:6379> hsetnx user003 name John
(integer) 1
127.0.0.1:6379> hsetnx user003 name Ross
(integer) 0
127.0.0.1:6379> hget user003 name
"John"
4 Set 集合
A Redis set is an unordered collection of unique strings (members). You can use Redis sets to efficiently:
- Track unique items (e.g., track all unique IP addresses accessing a given blog post).
- Represent relations (e.g., the set of all users with a given role).
- Perform common set operations such as intersection, unions, and differences.
简单来说就是单key多value,且不能重复。
常用操作:
SADD key member [member ...]
SMEMBERS key
SISMEMBER key member # 1为true 0为false
SREM key member [member ...] # 删除key集合中的member元素,未在集合中的元素被删除不受影响
SCARD key
SRANDMEMBER key [count] # 从key集合中随机显示count个元素,元素不删除,不写count时默认为1
SPOP key [count] # 从key集合中随机弹出count个元素,pop一个就少一个
SMOVE source destination member # 将source集合中的member元素移动到destination集合中
SDIFF key [key ...]
SUNION key [key ...]
SINTER key [key ...]
SINTERCARD numkeys key [key ...] [LIMIT limit]
具体操作:
# sadd key member [member ...] 添加元素,若重复只能添加一次
127.0.0.1:6379> sadd set1 1 2 3 4 5 6
(integer) 6
127.0.0.1:6379> sadd set2 1 1 1 2 2 2 3 4 5 6
(integer) 6
# smembers key 遍历key集合中所有元素
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
# sismember key member 判断member元素是否在key集合中(1为true 0为false)
127.0.0.1:6379> sismember set1 1
(integer) 1
127.0.0.1:6379> sismember set1 u
(integer) 0
# srem key member [member ...] 删除key集合中的member元素,未在集合中的元素被删除不受影响
127.0.0.1:6379> srem set2 6
(integer) 1
127.0.0.1:6379> srem set2 6 5 4 3
(integer) 3
127.0.0.1:6379> smembers set2
1) "1"
2) "2"
# scard key 获取key集合里面的元素个数
127.0.0.1:6379> scard set2
(integer) 2
# srandmember key [count] 从key集合中随机显示count个元素,元素不删除,不写count时默认为1
127.0.0.1:6379> srandmember set1 1
1) "2"
127.0.0.1:6379> srandmember set1 2
1) "5"
2) "6"
127.0.0.1:6379> srandmember set1
"6"
# spop key [count] 从key集合中随机弹出count个元素,pop一个就少一个
127.0.0.1:6379> spop set1
"2"
127.0.0.1:6379> spop set1 2
1) "3"
2) "1"
127.0.0.1:6379> smembers set1
1) "4"
2) "5"
3) "6"
# smove source destination member 将source集合中的member元素移动到destination集合中
127.0.0.1:6379> sadd set3 a b c
(integer) 3
127.0.0.1:6379> smove set1 set3 6
(integer) 1
127.0.0.1:6379> smembers set1
1) "4"
2) "5"
127.0.0.1:6379> smembers set3
1) "a"
2) "b"
3) "c"
4) "6"
# del key [key ...] 删除
127.0.0.1:6379> del set1 set2 set3
(integer) 3
# 集合运算
127.0.0.1:6379> sadd set1 a b c 1 2
(integer) 5
127.0.0.1:6379> sadd set2 1 2 3 a x
(integer) 5
# sdiff key [key ...] 差集运算
# e.g. sdiff key1 key2: key1-key2: key1中有的key2中没有的
127.0.0.1:6379> sdiff set1 set2
1) "b"
2) "c"
127.0.0.1:6379> sdiff set2 set1
1) "3"
2) "x"
# sunion key [key ...] 并集运算
# e.g. sunion key1 key2: ksy1 ∪ key2
127.0.0.1:6379> sunion set1 set2
1) "a"
2) "b"
3) "c"
4) "1"
5) "2"
6) "3"
7) "x"
# sinter key [key ...] 交集运算
# e.g. sinter key1 key2: key1 ∩ key2
127.0.0.1:6379> sinter set1 set2
1) "a"
2) "1"
3) "2"
# sintercard numkeys key [key ...] [LIMIT limit] 返回numkeys个集合的交集的个数
127.0.0.1:6379> sintercard 2 set1 set2 # 共有三个
(integer) 3
127.0.0.1:6379> sintercard 2 set1 set2 limit 1 # 显示1
(integer) 1
127.0.0.1:6379> sintercard 2 set1 set2 limit 2 # 显示2
(integer) 2
127.0.0.1:6379> sintercard 2 set1 set2 limit 3 # 显示3
(integer) 3
127.0.0.1:6379> sintercard 2 set1 set2 limit 4 # 显示3
(integer) 3
5 Zset 有序集合
A Redis sorted set is a collection of unique strings (members) ordered by an associated score. When more than one string has the same score, the strings are ordered lexicographically. Some use cases for sorted sets include:
- Leaderboards. For example, you can use sorted sets to easily maintain ordered lists of the highest scores in a massive online game.
- Rate limiters. In particular, you can use a sorted set to build a sliding-window rate limiter to prevent excessive API requests.
其实就是set集合上加一个分数,向有序集合加入一个元素和该元素的分数。
常用操作:
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member
...]
ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
ZREMRANGEBYSCORE key min max
ZSCORE key member
ZCARD key
ZREM key member [member ...]
ZINCRBY key increment member
ZCOUNT key min max
ZMPOP numkeys key [key ...] <MIN | MAX> [COUNT count] # 从键名列表中的第一个非空排序机制弹出一个或多个元素,他们是成员分数对
ZRANK key member [WITHSCORE]
ZREVRANK key member [WITHSCORE]
具体操作:
# zadd key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...] 添加元素
# https://redis.io/commands/zadd/
127.0.0.1:6379> zadd zset1 10 a 20 b 30 c 40 d 50 e 60 f
(integer) 6
127.0.0.1:6379> zadd zset2 60 f 50 e 20 b 10 a 30 c 40 d
(integer) 6
# zrange key start stop [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES] 根据score从小到大获取元素
127.0.0.1:6379> zrange zset1 0 3
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> zrange zset2 0 -1 # zset2是乱序的,还是可以按照score从小到大获取元素
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
127.0.0.1:6379> zrange zset1 0 -1 withscores # withscores 是显示分数
1) "a"
2) "10"
3) "b"
4) "20"
5) "c"
6) "30"
7) "d"
8) "40"
9) "e"
10) "50"
11) "f"
12) "60"
# zrevrange key start stop [WITHSCORES] 根据score从大到小获取元素
127.0.0.1:6379> zrevrange zset1 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> zrevrange zset1 0 2 withscores
1) "f"
2) "60"
3) "e"
4) "50"
5) "d"
6) "40"
# zrangebyscore key min max [WITHSCORES] [LIMIT offset count] 获取指定分数范围的元素
127.0.0.1:6379> zrangebyscore zset1 10 50 # 显示 score in [10,50]
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> zrangebyscore zset1 10 20 withscores # withscores 显示分数
1) "a"
2) "10"
3) "b"
4) "20"
127.0.0.1:6379> zrangebyscore zset1 10 (30 # (表示不包含, score in [10,30)
1) "a"
2) "b"
127.0.0.1:6379> zrangebyscore zset1 10 (50 limit 0 3 # limit 开始下标 多少步
1) "a"
2) "b"
3) "c"
# zscore key member 获取member元素的分数
127.0.0.1:6379> zscore zset1 a
"10"
127.0.0.1:6379> zscore zset1 b
"20"
# zcard key 获取key集合中元素的个数
127.0.0.1:6379> zcard zset1
(integer) 6
# zrem key member [member ...] 删除member元素
127.0.0.1:6379> zrem zset2 a
(integer) 1
127.0.0.1:6379> zrem zset2 b c
(integer) 2
127.0.0.1:6379> zcard zset2
(integer) 3
# zincrby key increment member 增加member的分数(原分数+increment)
127.0.0.1:6379> zrange zset1 0 0 withscores
1) "a"
2) "10"
127.0.0.1:6379> zincrby zset1 3 a
"13"
127.0.0.1:6379> zrange zset1 0 0 withscores
1) "a"
2) "13"
# zcount key min max 获取指定分数范围内的元素个数
127.0.0.1:6379> zcount zset1 0 20 # a, b 2个
(integer) 2
# zmpop numkeys key [key ...] MIN|MAX [COUNT count] 从键名列表中的第一个非空排序机制弹出一个或多个元素,他们是成员分数对
127.0.0.1:6379> zrange zset1 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
127.0.0.1:6379> zmpop 1 zset1 min count 1
1) "zset1"
2) 1) 1) "a"
2) "13"
127.0.0.1:6379> zrange zset1 0 -1
1) "b"
2) "c"
3) "d"
4) "e"
5) "f"
127.0.0.1:6379> zmpop 1 zset1 max count 1
1) "zset1"
2) 1) 1) "f"
2) "60"
127.0.0.1:6379> zmpop 1 zset1 max count 2
1) "zset1"
2) 1) 1) "e"
2) "50"
2) 1) "d"
2) "40"
127.0.0.1:6379> zrange zset1 0 -1
1) "b"
2) "c"
# zrank key member [WITHSCORE] 获取member下标值
127.0.0.1:6379> zrank zset1 b
(integer) 0
127.0.0.1:6379> zrank zset1 c withscore
1) (integer) 1
2) "30"
# zrevrank key member [WITHSCORE] 逆序获取下标值
127.0.0.1:6379> zrevrank zset1 b
(integer) 1
127.0.0.1:6379> zrevrank zset1 c withscore
1) (integer) 0
2) "30"
6 Bitmap 位图
Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type which is treated like a bit vector. Since strings are binary safe blobs and their maximum length is 512 MB, they are suitable to set up to 2^32 different bits.
You can perform bitwise operations on one or more strings. Some examples of bitmap use cases include:
- Efficient set representations for cases where the members of a set correspond to the integers 0-N.
- Object permissions, where each bit represents a particular permission, similar to the way that file systems store permissions.
用String类型作为底层数据结构实现的一种统计二值状态的数据类型。位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。
Bitmap支持的最大位数是232位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(232 = 4294967296)
简单说就是由0和1状态表现的二进制位的bit数组,该数据类型的底层是使用string实现的。
可以用在查看用户是否登陆,弹出的小广告是否被点击,上下班打卡签到,之类的状态统计的功能。
常用操作:
SETBIT key offset value # 设置key键中offset偏移位的value(只能是0或1), bitmap的偏移量是从0开始的
GETBIT key offset
STRLEN key # 这里每8位算一个字节
BITCOUNT key [start end [BYTE | BIT]]
BITOP <AND | OR | XOR | NOT> destkey key [key ...] # 用于统计,将统计结果存储为destkey
具体操作:
# setbit key offset value 设置key键中offset偏移位的value(只能是0或1), bitmap的偏移量是从0开始的
127.0.0.1:6379> setbit k1 1 1
(integer) 0
127.0.0.1:6379> setbit k1 2 1
(integer) 0
127.0.0.1:6379> setbit k1 3 1
(integer) 0
127.0.0.1:6379> setbit k1 3 7 # error 只能使用0或1表示
(error) ERR bit is not an integer or out of range
# type is string
127.0.0.1:6379> type k1
string
# getbit key offset 获取offset偏移量的位
127.0.0.1:6379> getbit k1 1
(integer) 1
127.0.0.1:6379> getbit k1 2
(integer) 1
127.0.0.1:6379> getbit k1 3
(integer) 1
127.0.0.1:6379> getbit k1 666
(integer) 0
# strlen key 统计字节数占用多少 (这里每8位算一个字节)
127.0.0.1:6379> setbit k2 0 1
(integer) 0
127.0.0.1:6379> setbit k2 7 1
(integer) 0
127.0.0.1:6379> strlen k2
(integer) 1
127.0.0.1:6379> setbit k2 8 1
(integer) 0
127.0.0.1:6379> strlen k2
(integer) 2
# bitcount key [start end [BYTE|BIT]] 获取键里含有1的有多少个
127.0.0.1:6379> setbit uid:12345 1 1
(integer) 0
127.0.0.1:6379> setbit uid:12345 2 1
(integer) 0
127.0.0.1:6379> setbit uid:12345 3 1
(integer) 0
127.0.0.1:6379> bitcount uid:12345
(integer) 3
# bitop AND|OR|XOR|NOT destkey key [key ...] 用于统计,将统计结果存储为destkey
# 用户登陆情况 20240101: 4个user;20240102: 2个user
127.0.0.1:6379> setbit 20240101 0 1
(integer) 0
127.0.0.1:6379> setbit 20240101 1 1
(integer) 0
127.0.0.1:6379> setbit 20240101 2 1
(integer) 0
127.0.0.1:6379> setbit 20240101 3 1
(integer) 0
127.0.0.1:6379> setbit 20240102 0 1
(integer) 0
127.0.0.1:6379> setbit 20240102 2 1
(integer) 0
# 统计20240101和20240102都登陆的人数并赋值给k1 (返回1表示true)
127.0.0.1:6379> bitop and k1 20240101 20240102
(integer) 1
# 显示k1,一共有两个用户在20240101和20240102都进行了登陆
127.0.0.1:6379> bitcount k1
(integer) 2
7 HyperLogLog 基数统计
HyperLogLog is a probabilistic data structure that estimates the cardinality of a set.
HyperLogLog is a probabilistic data structure that estimates the cardinality of a set. As a probabilistic data structure, HyperLogLog trades perfect accuracy for efficient space utilization.
The Redis HyperLogLog implementation uses up to 12 KB and provides a standard error of 0.81%.
想要了解基数统计首先要知道什么是基数:简单来说就是不重复的记录个数就是基数。所谓的基数统计就是统计不重复的元素的个数,他不具体记录一共有哪些元素,只是计算一共有几个元素。
HyperLogLog常被用来统计某个网站的UV(Unique Visiter,独立访客,一般理解为IP);用户搜索网站关键词的数量;统计用户每天搜索不同词条个数。举个例子:B站某个视频的观看量就可以使用基数统计进行计算。
需要注意,HyperLogLog有约0.81%的标准误差。
常用操作:
PFADD key [element [element ...]]
PFCOUNT key [key ...] # 统计key(不重复)
PFMERGE destkey [sourcekey [sourcekey ...]]
具体操作:
# pfadd key [element [element ...]] 添加指定元素
127.0.0.1:6379> pfadd k1 1 3 5 7 9
(integer) 1
127.0.0.1:6379> pfadd k2 1 2 4 4 4 6 6 7 8 9 10
(integer) 1
# pfcount key [key ...] 统计key(不重复)
127.0.0.1:6379> pfcount k1
(integer) 5
127.0.0.1:6379> pfcount k2 # k2中重复的不算
(integer) 8
# pfmerge destkey [sourcekey [sourcekey ...]] 将两个键合并为一个键
127.0.0.1:6379> pfmerge k3 k1 k2 # 将k1和k2合并为k3
OK
127.0.0.1:6379> pfcount k3 # k3经过k1 k2合并后去重,共有10个元素
(integer) 10
# HyperLogLog的类型是string
127.0.0.1:6379> type k1
string
8 Geospatial 地理空间
Redis geospatial indexes let you store coordinates and search for them. This data structure is useful for finding nearby points within a given radius or bounding box.
移动互联网时代LBS应用越来越多,交友软件中附近的小姐姐、外卖软件中附近的美食店铺、高德地图附近的核酸检查点等等,那这种附近各种形形色色的XXX地址位置选择是如何实现的?
地球上的地理位置是使用二维的经纬度表示,经度范围 (-180, 180],纬度范围 (-90, 90],只要我们确定一个点的经纬度就可以名取得他在地球的位置。
例如滴滴打车,最直观的操作就是实时记录更新各个车的位置,当我们要找车时,在数据库中查找距离我们(x0, y0)附近r公里范围内部的车辆
Geospatial 底层是使用zset数据类型存储的。
常用操作:
GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]
ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
GEOPOS key [member [member ...]]
GEOHASH key [member [member ...]] #返回坐标的geohash表示,就是返回经纬度的hash值
GEODIST key member1 member2 [M | KM | FT | MI] # 默认为米
- georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUS key longitude latitude radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key | STOREDIST key]
# WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
# WITHCOORD: 将位置元素的经度和维度也一并返回。
# WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
# COUNT 限定返回的记录数。
- georadiusbymember 找出位于指定范围内的元素,中心点是由给定的位置元素决定
GEORADIUSBYMEMBER key member radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key | STOREDIST key]
具体操作:
# geoadd key [NX|XX] [CH] longitude latitude member [longitude latitude member] 添加元素
127.0.0.1:6379> geoadd city 116.403963 39.915119 "天安门" 116.403414 39.924091 "故宫" 116.024067 40.362639 "长城"
(integer) 3
# geo类型的数据其实是zset
127.0.0.1:6379> type city
zset
# ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES] 显示
127.0.0.1:6379> zrange city 0 -1
1) "\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8"
2) "\xe6\x95\x85\xe5\xae\xab"
3) "\xe9\x95\xbf\xe5\x9f\x8e"
# 解决中文乱码 `redis-cli -a --raw` 只要有--raw就可以显示中文
127.0.0.1:6379> quit
parallels@ubuntu-linux-22-04-02-desktop:~$ redis-cli -a 11 --raw
# 显示
127.0.0.1:6379> zrange city 0 -1
天安门
故宫
长城
# geopos key [member [member ...]] 显示经纬度
127.0.0.1:6379> geopos city 天安门 故宫 长城
116.40396326780319214
39.91511970338638093
116.40341609716415405
39.92409008156927541
116.02406591176986694
40.36263993239462877
# geohash key [member [member ...]] 返回坐标的geohash表示,就是返回经纬度的hash值
# Return valid Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index (where elements were added using GEOADD).
127.0.0.1:6379> geohash city 天安门 故宫 长城
wx4g0f6f2v0
wx4g0gfqsj0
wx4t85y1kt0
# GEODIST key member1 member2 [M | KM | FT | MI] 返回两点间距离默认为米
127.0.0.1:6379> geodist city 天安门 长城
59338.9814
127.0.0.1:6379> geodist city 天安门 长城 km
59.3390
# GEORADIUS key longitude latitude radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key | STOREDIST key] 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
# WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
# WITHCOORD: 将位置元素的经度和维度也一并返回。
# WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
# COUNT 限定返回的记录数。
127.0.0.1:6379> georadius city 116.418017 39.914402 10 km withdist withcoord count 10
天安门
1.2016
116.40396326780319214
39.91511970338638093
故宫
1.6470
116.40341609716415405
39.92409008156927541
# GEORADIUSBYMEMBER key member radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key | STOREDIST key] 找出位于指定范围内的元素,中心点是由给定的位置元素决定
127.0.0.1:6379> georadiusbymember city 天安门 10 km withcoord withhash count 10 withdist
天安门
0.0000
4069885555089531
116.40396326780319214
39.91511970338638093
故宫
0.9988
4069885568908290
116.40341609716415405
39.92409008156927541
9 Stream 流
A Redis stream is a data structure that acts like an append-only log but also implements several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. You can use streams to record and simultaneously syndicate events in real time. Examples of Redis stream use cases include:
- Event sourcing (e.g., tracking user actions, clicks, etc.)
- Sensor monitoring (e.g., readings from devices in the field)
- Notifications (e.g., storing a record of each user’s notifications in a separate stream)
Redis generates a unique ID for each stream entry. You can use these IDs to retrieve their associated entries later or to read and process all subsequent entries in the stream. Note that because these IDs are related to time, the ones shown here may vary and will be different from the IDs you see in your own Redis instance.
就是redis版本的消息中间件MQ,需要知道的是消息队列的基本知识,不知道的话可以理解为一个队列。
常用操作(生产者):
XADD key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] threshold [LIMIT count]] <* | id> field value [field value ...]
使用该命令之后会返回一个消息ID,他的格式是毫秒级时间戳-自增ID
。消息ID必须要比上一个ID大。
默认用星号表示自动生成规矩,让系统自动生成ID。*
号表示服务器自动生成 MessageID(类似MySQL里面主键auto_increment),后面顺序跟着一堆 业务key/value
XRANGE key start end [COUNT count]
-
start
表示开始值,-
代表最小值 -
end
表示结束值,+
代表最大值 -
count
表示最多获取多少个值
XREVRANGE key end start [COUNT count]
与 xrange 的区别在于,获取消息列表元素的方向是相反的,end 在前,start 在后。
XDEL key id [id ...]
XLEN key
XTRIM key <MAXLEN | MINID> [= | ~] threshold [LIMIT count]
用于对stream的长度进行截取,如超长会进行截取。
-
maxlen 允许的最大长度,对流进行修剪限制长度
-
minid 允许的最小id,从某个id值开始比该id值小的将会被抛弃
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
-
Count 最多读区多少条消息
-
block 是否已阻塞的方式读取消息,默认不阻塞,如果milliseconds设置为0,表示永远阻塞
7.1 非阻塞:
-
$
代表特殊ID,表示以当前Stream已经存储的最大的ID作为最后一个ID,当前Stream中不存在大于当前最大ID的消息,因此此时返回nil -
0-0
代表从最小的ID开始获取Stream中的消息,当不指定count,将会返回Stream中的所有消息,注意也可以使用0(00/000也都是可以的……)
7.2 阻塞:
就是命令加上block,需要两个客户端
常用命令(消费者):
XGROUP CREATE key group <id | $> [MKSTREAM] [ENTRIESREAD entries-read]
注意这里创建的时候需要分组创建group
-
$
表示从Stream尾部开始消费 -
0
表示从Stream头部开始消费
创建消费者组的时候必须指定 ID, ID 为 0 表示从头开始消费,为 $ 表示只消费新的消息,队尾新来
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]
>
表示从第一条尚未被消费的消息开始读取- 消费组 groupA内的消费者consumer1从mystream消息队列中读取所有消息
但是不同消费组的消费者可以消费同一条消息(可以理解为MySQL中的游标)
count
表示一个消费者可以读取几条消息,同一组后面的消费者可以继续读取他读取后剩下的消息。让组内的多个消费者共同分担读取消息,所以,我们通常会让每个消费者读取部分消息,从而实现消息读取负载在多个消费者间是均衡分布的
需要注意的是:这里的命令只是读取了消息,并未确认(ACK),那么问题就来了:基于 Stream 实现的消息队列,如何保证消费者在发生故障或宕机再次重启后,仍然可以读取未处理完的消息?
2.1 Streams 会自动使用内部队列(也称为 PENDING List,意为悬而未决)留存消费组里每个消费者读取的消息保底措施,直到消费者使用 XACK 命令通知 Streams“消息已经处理完成”。
2.2 消费确认增加了消息的可靠性,一般在业务处理完成之后,需要执行 XACK 命令确认消息已经被消费完成。
XPENDING key group [[IDLE min-idle-time] start end count [consumer]]
这条要和下面一条命令结合理解
返回值演示:
127.0.0.1:6379> xpending mystream groupB
7 # 一共读取了几条数据
1704732329452-0 # 所有消费者读取的消息最小ID
1704735015186-0 # 所有消费者读取的消息最大ID
consumer1 # 这行和下行表示一口气读取7条消息
7
127.0.0.1:6379> xpending mystream groupC
7
1704732329452-0
1704735015186-0
# 表示有3个消费者分别读取几条消息
consumer1
3
consumer2
3
consumer3
1
# group C start是-表示最小值 end是+表示最大值 count是5表示显示用户读取的5条(此时一共只读取了3条)最后是用户consumer1
127.0.0.1:6379> xpending mystream groupC - + 5 consumer1
1704732329452-0 # 消息ID
consumer1 # 被谁消费了
2887414 # 距离该消息被推送到该消费者组多少时间 单位毫秒
1 # 该消息被推送几次
1704734213000-0
consumer1
2887414
1
1704734217924-0
consumer1
2887414
1
XACK key group id [id ...]
将xpending获取到的数据的ID进行确认
XINFO CONSUMERS key group
生产者命令演示:
# xadd 添加消息到队列末尾
127.0.0.1:6379> xadd mystream * id 11 cname zhangsan
"1705127290254-0" # 毫秒级时间戳-自增ID
127.0.0.1:6379> xadd mystream * id 12 cname lisi
"1705127296800-0"
127.0.0.1:6379> xadd mystream * k1 v1 k2 v2 k3 v3
"1705127303851-0"
# type
127.0.0.1:6379> type mystream
stream
# xrange 获取消息列表
127.0.0.1:6379> xrange mystream - +
1) 1) "1705127290254-0"
2) 1) "id"
2) "11"
3) "cname"
4) "zhangsan"
2) 1) "1705127296800-0"
2) 1) "id"
2) "12"
3) "cname"
4) "lisi"
3) 1) "1705127303851-0"
2) 1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"
127.0.0.1:6379> xrange mystream - + count 1
1) 1) "1705127290254-0"
2) 1) "id"
2) "11"
3) "cname"
4) "zhangsan"
# xrevrange 反转 xrange
127.0.0.1:6379> xrevrange mystream + -
1) 1) "1705127303851-0"
2) 1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"
2) 1) "1705127296800-0"
2) 1) "id"
2) "12"
3) "cname"
4) "lisi"
3) 1) "1705127290254-0"
2) 1) "id"
2) "11"
3) "cname"
4) "zhangsan"
127.0.0.1:6379> xrevrange mystream + - count 1
1) 1) "1705127303851-0"
2) 1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"
# xdel 删除元素
127.0.0.1:6379> xdel mystream 1705127303851-0
(integer) 1
# 删除后
127.0.0.1:6379> xrevrange mystream + -
1) 1) "1705127296800-0"
2) 1) "id"
2) "12"
3) "cname"
4) "lisi"
2) 1) "1705127290254-0"
2) 1) "id"
2) "11"
3) "cname"
4) "zhangsan"
# xlen 获取长度
127.0.0.1:6379> xlen mystream
(integer) 2
# xtrim 截取
127.0.0.1:6379> xadd mystream * k1 v1
"1705127602368-0"
127.0.0.1:6379> xadd mystream * k2 v2
"1705127612996-0"
# 显示一共有四个元素
127.0.0.1:6379> xrange mystream - +
1) 1) "1705127290254-0"
2) 1) "id"
2) "11"
3) "cname"
4) "zhangsan"
2) 1) "1705127296800-0"
2) 1) "id"
2) "12"
3) "cname"
4) "lisi"
3) 1) "1705127602368-0"
2) 1) "k1"
2) "v1"
4) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
# 从后往前截取2个
127.0.0.1:6379> xtrim mystream maxlen 2
(integer) 2
# 截取后的元素(2个)
127.0.0.1:6379> xrange mystream - +
1) 1) "1705127602368-0"
2) 1) "k1"
2) "v1"
2) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
# 截取最小ID,没有比1705127602368-0更小的(失败)
127.0.0.1:6379> xtrim mystream minid 1705127602368-0
(integer) 0
# 截取最小ID,只有一个比1705127612996-0更小的
127.0.0.1:6379> xtrim mystream minid 1705127612996-0
(integer) 1
# 截取后的元素(1个)
127.0.0.1:6379> xrange mystream - +
1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
# xread
127.0.0.1:6379> xadd mystream * k3 v3
"1705127841480-0"
127.0.0.1:6379> xadd mystream * k4 v4
"1705127848113-0"
127.0.0.1:6379> xadd mystream * k5 v5
"1705127853003-0"
127.0.0.1:6379> xadd mystream * k6 v6
"1705127857601-0"
127.0.0.1:6379> xadd mystream * k7 v7
"1705127862316-0"
127.0.0.1:6379> xrange mystream - +
1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
3) 1) "1705127848113-0"
2) 1) "k4"
2) "v4"
4) 1) "1705127853003-0"
2) 1) "k5"
2) "v5"
5) 1) "1705127857601-0"
2) 1) "k6"
2) "v6"
6) 1) "1705127862316-0"
2) 1) "k7"
2) "v7"
# 非阻塞 显示前2个(消息队列的前2个)
127.0.0.1:6379> xread count 2 streams mystream 0-0
1) 1) "mystream"
2) 1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
# 非阻塞 显示前10个(消息队列的前10个)
127.0.0.1:6379> xread count 10 streams mystream 0-0
1) 1) "mystream"
2) 1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
3) 1) "1705127848113-0"
2) 1) "k4"
2) "v4"
4) 1) "1705127853003-0"
2) 1) "k5"
2) "v5"
5) 1) "1705127857601-0"
2) 1) "k6"
2) "v6"
6) 1) "1705127862316-0"
2) 1) "k7"
2) "v7"
# 非阻塞 显示所有(不写count就是显示所有)
127.0.0.1:6379> xread streams mystream 0-0
1) 1) "mystream"
2) 1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
3) 1) "1705127848113-0"
2) 1) "k4"
2) "v4"
4) 1) "1705127853003-0"
2) 1) "k5"
2) "v5"
5) 1) "1705127857601-0"
2) 1) "k6"
2) "v6"
6) 1) "1705127862316-0"
2) 1) "k7"
2) "v7"
阻塞演示:
客户端a(输入以下命令,然后卡住):
127.0.0.1:6379> xread count 1 block 0 streams mystream $
客户端b(输入以下命令,增加一条消息):
127.0.0.1:6379> xadd mystream * k8 v8
"1705128005812-0"
客户端a(在客户端b新增之后将显示如下):
127.0.0.1:6379> xread count 1 block 0 streams mystream $
1) 1) "mystream"
2) 1) 1) "1705128005812-0"
2) 1) "k8"
2) "v8"
消费者命令演示:
# xgroup create 创建消费者组
# $表示从stream尾部开始消费
# 0表示从stream头部开始消费
127.0.0.1:6379> xgroup create mystream groupA $
OK
127.0.0.1:6379> xgroup create mystream groupB 0
OK
127.0.0.1:6379> xgroup create mystream groupC 0
OK
# xreadgroup group 读取消费组消息
127.0.0.1:6379> xreadgroup group groupB consumer1 streams mystream >
1) 1) "mystream"
2) 1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
3) 1) "1705127848113-0"
2) 1) "k4"
2) "v4"
4) 1) "1705127853003-0"
2) 1) "k5"
2) "v5"
5) 1) "1705127857601-0"
2) 1) "k6"
2) "v6"
6) 1) "1705127862316-0"
2) 1) "k7"
2) "v7"
7) 1) "1705128005812-0"
2) 1) "k8"
2) "v8"
# 同一个消费组若全部消费之后则不会继续读取(可以理解为MySQL中的游标)
127.0.0.1:6379> xreadgroup group groupB consumer2 streams mystream >
(nil)
# 若要多个consumer消费者消费这个消费组中的消息,可以使用count
# consumer1读取3条消息
127.0.0.1:6379> xreadgroup group groupC consumer1 count 3 streams mystream >
1) 1) "mystream"
2) 1) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
2) 1) "1705127841480-0"
2) 1) "k3"
2) "v3"
3) 1) "1705127848113-0"
2) 1) "k4"
2) "v4"
# consumer2继续读取consumer1读取后的3条消息
127.0.0.1:6379> xreadgroup group groupC consumer2 count 3 streams mystream >
1) 1) "mystream"
2) 1) 1) "1705127853003-0"
2) 1) "k5"
2) "v5"
2) 1) "1705127857601-0"
2) 1) "k6"
2) "v6"
3) 1) "1705127862316-0"
2) 1) "k7"
2) "v7"
# consumer3继续读取consumer2读取后的3条消息(这里之后1条消息)
127.0.0.1:6379> xreadgroup group groupC consumer3 count 3 streams mystream >
1) 1) "mystream"
2) 1) 1) "1705128005812-0"
2) 1) "k8"
2) "v8"
# xpending 查询每个消费组内所有消费者已读取未确认的消息
127.0.0.1:6379> xpending mystream groupB
1) (integer) 7 # 一共读取了几条数据
2) "1705127612996-0" # 所有消费者读取的消息最小ID
3) "1705128005812-0" # 所有消费者读取的消息最大ID
4) 1) 1) "consumer1" # 这行和下行表示一口气读取7条消息
2) "7"
127.0.0.1:6379> xpending mystream groupC
1) (integer) 7
2) "1705127612996-0"
3) "1705128005812-0"
# 表示有3个消费者分别读取几条消息
4) 1) 1) "consumer1"
2) "3"
2) 1) "consumer2"
2) "3"
3) 1) "consumer3"
2) "1"
# xack确认消息处理已完成
# 被确认前有几条消息未被处理(3)
127.0.0.1:6379> xpending mystream groupC - + 5 consumer1
1) 1) "1705127612996-0" # 消息ID
2) "consumer1" # 被谁消费了
3) (integer) 171683 # 距离该消息被推送到该消费者组多少时间 单位毫秒
4) (integer) 1 # 该消息被推送几次
2) 1) "1705127841480-0"
2) "consumer1"
3) (integer) 171683
4) (integer) 1
3) 1) "1705127848113-0"
2) "consumer1"
3) (integer) 171683
4) (integer) 1
# 确认ID为1705127612996-0的消息被处理
127.0.0.1:6379> xack mystream groupC 1705127612996-0
(integer) 1
# 被处理后还有几条消息没被处理(2)
127.0.0.1:6379> xpending mystream groupC - + 5 consumer1
1) 1) "1705127841480-0"
2) "consumer1"
3) (integer) 282931
4) (integer) 1
2) 1) "1705127848113-0"
2) "consumer1"
3) (integer) 282931
4) (integer) 1
# xinfo 打印
127.0.0.1:6379> xinfo stream mystream
1) "length"
2) (integer) 7
3) "radix-tree-keys"
4) (integer) 1
5) "radix-tree-nodes"
6) (integer) 2
7) "last-generated-id"
8) "1705128005812-0"
9) "max-deleted-entry-id"
10) "1705127303851-0"
11) "entries-added"
12) (integer) 11
13) "recorded-first-entry-id"
14) "1705127612996-0"
15) "groups"
16) (integer) 3
17) "first-entry"
18) 1) "1705127612996-0"
2) 1) "k2"
2) "v2"
19) "last-entry"
20) 1) "1705128005812-0"
2) 1) "k8"
2) "v8"
10 bitField 位域
Redis bitfields let you set, increment, and get integer values of arbitrary bit length. For example, you can operate on anything from unsigned 1-bit integers to signed 63-bit integers.
These values are stored using binary-encoded Redis strings. Bitfields support atomic read, write and increment operations, making them a good choice for managing counters and similar numerical values.
BitFiled命令可以将一个Redis字符串看作是一个由二进制位组成的数组,并对这个数组中任意偏移进行访问。可以使用该命令对一个有符号的5位整形数的第1234位设置指定值,也可以对一个31位无符号整型数的第456位进行取值。类似地,本命令可以对指定的整数进行自增和自减操作,可配置的上溢和下溢处理操作。
BitField
命令可以再一次调用中同时对多个位范围进行操作:它接受一系列执行的操作作为参数,并返回一个数组,数组中的每个元素就是对应操作的执行结果。
主要用来进行位域修改和溢出控制。
简单来说就是将一个Redis字符串看作是一个由二进制位组成的数组,并能对变长位宽和任意没有字节对齐的指定整型位域进行寻址和修改。其实就是在二进制条件下进行改动。
这个数据类型实在太小众了,具体工作中见都没见过。