普通视图

Received before yesterday

Redis数据结构之Bitfleid

2024年10月16日 00:00

1.概述

bitfield将一个字符串看作一个由二进制位构成的数组,并对这个数组中任何偏移进行访问,通过bitfield命令可以一次性操作多个比特位域(指的是连续的多个比特位),它会执行一系列操作并返回一个响应数组,这个数组中的元素对应参数列表中的相应操作的执行结果。

在实际应用中,bitfield并不是一种常用的数据结构。

Redis数据结构之Bitmap

2024年10月16日 00:00

1.概述

  • 由0和1状态表现的二进制位的bit数组(数组里每个元素只能是0或1)该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。
  • 基于String数据类型的按位的操作。
  • Bitmap支持的最大位数是2³²位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(2³²= 4294967296)

2.常见操作

2.1 SETBIT

设置0或1到Bitmap

SETBIT key offset value
  • key
  • offset 偏移位,从0开始计算
  • value 只能是0或1

例:

127.0.0.1:6379> setbit k1 1 1(integer) 1127.0.0.1:6379> setbit k1 2 1(integer) 1127.0.0.1:6379> setbit k1 3 1(integer) 1

验证:Bitmap基于String数据类型的

127.0.0.1:6379> type k1string

2.2 GETBIT

获取0或1,不是1就默认0

127.0.0.1:6379> getbit k1 1(integer) 1127.0.0.1:6379> getbit k1 2(integer) 1127.0.0.1:6379> getbit k1 3(integer) 1127.0.0.1:6379> getbit k1 4(integer) 0

2.3 STRLEN

不是字符串长度而是Bitmap占据几个字节,按照8位一组扩容,统计有多少组

127.0.0.1:6379> setbit k3 0 1(integer) 0127.0.0.1:6379> setbit k3 7 1(integer) 0127.0.0.1:6379> strlen k3(integer) 1127.0.0.1:6379> setbit k3 8 1(integer) 0127.0.0.1:6379> strlen k3(integer) 2

2.4 BITCOUNT

一个bitmap中从START到END有多少个1,不加START|END统计全部

BITCOUNT KEY [START|END]

例:

127.0.0.1:6379> bitcount k3(integer) 3

2.5 BITOP

对bitmap进行二进制运算(与AND、或OR、非NOT、异或XOR)保存结果到DESTKEY KEY

BITOP AND|OR|NOT|XOR DESTKEY KEY [KEY ...]

例:

准备数据

127.0.0.1:6379> setbit bin1 0 1(integer) 0127.0.0.1:6379> setbit bin1 1 1(integer) 0127.0.0.1:6379> setbit bin1 2 0(integer) 0127.0.0.1:6379> setbit bin1 3 1(integer) 0127.0.0.1:6379> setbit bin2 0 0(integer) 0127.0.0.1:6379> setbit bin2 1 1(integer) 0127.0.0.1:6379> setbit bin2 2 1(integer) 0127.0.0.1:6379> setbit bin2 3 0

测试:BITOP AND

127.0.0.1:6379> BITOP AND bintemp bin1 bin2(integer) 1

查看写入到bintemp中的结果

127.0.0.1:6379> getbit bintemp 0(integer) 0127.0.0.1:6379> getbit bintemp 1(integer) 1127.0.0.1:6379> getbit bintemp 2(integer) 0127.0.0.1:6379> getbit bintemp 3(integer) 0

3.总结

命令作用时间复杂度
setbit给指定key的值的第offset赋值valO(1)
getbit获取指定key的第offset位O(1)
bitcount返回指定key中[start,end]中为1的数量O(n)
bitop对不同的二进制存储数据进行位运算(AND、OR、NOT、XOR)O(n)

使用场景:

1.统计签到、登录、打卡等,例如:ID为10001的用户2025年5月的第12个工作日未打卡

setbit sign:uid_10001:202505 12 0

Redis数据结构之GEO

2024年10月16日 00:00

1.概述

移动互联网时代LBS应用越来越多,交友软件中附近的人、外卖软件中附近的美食店铺等,那这种附近各种形形色色的地址位置选择是如何实现的?

地球上的地理位置是使用二维的经纬度表示,经度范围(-180,180],纬度范围(-90,90],只要我们确定一个点的经纬度就可以取得它在地球上的位置。

例如滴滴打车,最直观的操作就是实时记录更新各个车的位置,然后当我们要找车时,在数据库中查找距离我们(x0, y0)附近r公里范围内部的车辆,使用如下SQL即可:

select taxi from position where x0 - r < x < x0 + r and y0 - r < y < y0 + r

但是这样会有查询性能问题,如果并发高数据量大,这种查询会影响数据库性能,而且这个查询到的是一个矩形范围,而不是以点为中心r公里为半径的圆形范围。

为了解决这一问题,Redis在3.2版本之后支持了GEO这一数据结构,GEO主要用于存储地理位置信息,并对存储的信息进行操作,包括:

  • 添加地理位置的坐标
  • 获取地理位置的坐标
  • 计算两个位置之间的距离
  • 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合

2.常用命令

2.1 GEOADD

多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的key中

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

经纬度可以通过百度地图坐标拾取获得:https://api.map.baidu.com/lbsapi/getpoint/index.html

例如:

127.0.0.1:6379> GEOADD city 116.515802 39.951893 "北京朝阳站" 116.385671 39.871141 "北京南站"(integer) 1

GEO的本质是Set的子类型:

127.0.0.1:6379> type cityzset127.0.0.1:6379> zrange city 0 -11) "\xe5\x8c\x97\xe4\xba\xac\xe5\x8d\x97\xe7\xab\x99"2) "\xe5\x8c\x97\xe4\xba\xac\xe7\xab\x99"3) "\xe5\x8c\x97\xe4\xba\xac\xe6\x9c\x9d\xe9\x98\xb3\xe7\xab\x99"127.0.0.1:6379> 

中文乱码的解决:修改客户端参数

127.0.0.1:6379> quit[root@localhost bin]# ./redis-cli --raw127.0.0.1:6379> auth lzjOK127.0.0.1:6379> zrange city 0 -1北京南站北京站北京朝阳站

2.2 GEOPOS

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

GEOPOS key member [member ...]

127.0.0.1:6379> GEOPOS city 北京站116.4341434836387634339.90890963654599233127.0.0.1:6379> GEOPOS city  北京朝阳站116.5158006548881530839.95189343796607062

2.3 GEODIST

返回两个给定位置之间的距离

  • m
  • km千米
  • ft英尺
  • mi英里
GEODIST key memberl member2 [m|km|ft|mi]

例:高铁站之间的距离

127.0.0.1:6379> GEODIST city 北京站 北京朝阳站 km8.4477127.0.0.1:6379> GEODIST city 北京南站 北京朝阳站 km14.2804127.0.0.1:6379> GEOADD city 117.978057 40.893571 "承德南站"1127.0.0.1:6379> GEODIST city 承德南站 北京朝阳站 km162.1702

2.4 GEORADIUS

以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有位置元素,说白了就是根据半径检索附近的POI(兴趣点)

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
  • key: 存储地理位置的有序集合键名
  • longitude latitude: 中心点的经度和纬度
  • radius: 半径距离
  • m|km|ft|mi: 距离单位(米、千米、英尺、英里)
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHDIST: 在返回位置元素的同时,将位置元素与中心之间的距离也一并返回, 距离的单位和用户给定的范围单位保持一致
  • WITHHASH: 以52位有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值,这个选项主要用于底层应用或者调试,实际中的作用并不大
  • COUNT count: 限制返回结果数量
  • ASC|DESC: 按距离排序(升序/降序)
  • STORE key: 将结果存储为有序集合(存储 geohash)
  • STOREDIST key: 将结果存储为有序集合(存储距离)

例:以朝阳公园(116.486817,39.953201)为圆心,10千米为半径,搜索city中满足条件的地点

127.0.0.1:6379> GEORADIUS city 116.486817 39.953201 10 km WITHCOORD WITHDIST北京站6.6672116.4341434836387634339.90890963654599233北京朝阳站2.4755116.5158006548881530839.95189343796607062

2.5 GEORADIUSBYMEMBER

跟GEORADIUS类似

2.6 GEOHASH

返回一个或多个位置元素的GEOHASH表示,比位数众多的小数更好处理

GEOHASH算法生成的base32编码值,主要分为三步:
1.将三维的地球变为二维的坐标
2.将二维的坐标转换为一维的点块
3.最后将一维的点块转换为二进制再通过base32编码

GEOHASH key member [member ...]

127.0.0.1:6379> GEOHASH city 北京站 北京南站 北京朝阳站wx4g190y0p0wx4fb6m6nx0wx4g73h0wu0

Redis数据结构之Hash

2024年10月16日 00:00

1.概述

  • Hash是一个String类型的field(字段)和value(值)的映射表,而且value是一个键值对集合,类似Map<String, Map<Object, Object>>,Hash特别适合用于存储对象。
  • 每个Hash可以存储2³²-1个键值对 (40多亿)。

2.常见操作

2.1 H(M)SET/H(M)GET

HSET/HGET,设置和获取hash的键值对

语法:

hset key field value [field value ......] 

例:

127.0.0.1:6379> hset user:01 name liming(integer) 1hset user:01 id 1 name liming age 30

语法:

hget key field [field ......] 

例:

127.0.0.1:6379> hget user:01 name"liming"127.0.0.1:6379> hget user:01 age"30"127.0.0.1:6379> hget user:01 id"1"

HMSET,一次批量设置hash的多个值

127.0.0.1:6379> HMSET user:02 id 02 name lisiOK

从 Redis 4.0.0 开始,HSET 也支持批量设置,HMSET 被视为已弃用,但仍可使用。

HMGET,一次获取某个hash的多个值

127.0.0.1:6379> hmget user:02 id name 1) "02"2) "lisi"

2.2 HGETALL

获取一个hash中的所有键值

127.0.0.1:6379> hgetall user:011) "name"2) "liming"3) "id"4) "1"5) "age"6) "30"

2.3 HDEL

删除hash中的某个键值对

127.0.0.1:6379> hdel user:01 age(integer) 1127.0.0.1:6379> hgetall user:011) "name"2) "liming"3) "id"4) "1"

2.4 HLEN

hash中键值对数量

127.0.0.1:6379> hlen user:01(integer) 2

2.5 HEXISTS

hash中某个键是否存在

127.0.0.1:6379> HEXISTS user:01 age(integer) 0127.0.0.1:6379> HEXISTS user:01 name(integer) 1

2.6 HKEYS/HVALS

获取一个hash中所有的键/值

127.0.0.1:6379> HKEYS user:011) "name"2) "id"
127.0.0.1:6379> HVALS user:011) "liming"2) "1"

2.7 HINCRBY

对hash中某个键的值进行自增

127.0.0.1:6379> hmset user:03 age 13OK127.0.0.1:6379> hincrby user:03 age 1(integer) 14127.0.0.1:6379> hincrby user:03 age 2(integer) 16

2.8 HSETNX

不存在就赋值,如已存在则无效

127.0.0.1:6379> hgetall user:031) "age"2) "16"127.0.0.1:6379> HSETNX user:03 name liming(integer) 1127.0.0.1:6379> HSETNX user:03 age 3(integer) 0

3.总结

KV键值对的结构,适合早期的购物车等场景

Redis数据结构之HyperLogLog

2024年10月16日 00:00

1.概述

基数统计是一种去重复统计功能的基数估计算法,HyperLogLog是用来做基数统计的数据结构,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定且是很小的。

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

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

去重类似Java的HashSet,只是不能存储数据

2.常用命令

2.1 添加元素

PFADD key element [element ..]

127.0.0.1:6379> pfadd pf1 1 2 3 4 5 6 5 4 5 6 7 34 2 5 6 4(integer) 1127.0.0.1:6379> pfadd pf2 1 2 3 4 5 6 5 4 43 4 21 65 32 54 (integer) 1

hyperloglog本质上是string

127.0.0.1:6379> type pf1string

2.2 返回基数估算值

PFCOUNT key [key....]

例:去重后只有8个元素

127.0.0.1:6379> PFCOUNT pf1(integer) 8

2.3 合并hyperloglog

合并到新的destkey中

PFMERGE destkey sourcekey [sourcekey...]

例:合并pf1和pf2为pfm

127.0.0.1:6379> PFMERGE pfm pf1 pf2OK127.0.0.1:6379> pfcount pfm(integer) 13

3.总结

使用场景:

1.网站UV统计,文章阅读数UV统计

Redis数据结构之List

2024年10月16日 00:00

1.概述

  • List是简单的字符串列表,单key多个value,按照插入顺序排序。

  • 支持添加一个元素到列表的头部(左边)或者尾部(右边)

  • 它的底层实际是个双端链表,主要功能有push/pop等,用在栈,队列,消息队列等场景,left/right都可以插入添加,如果键不存在创建新的链表,键已存在,则新增内容,如果值全被移除了,对应的键也就消失了。

    双端链表两端操作的效率很高,通过索引下标的操作性能略有下降

  • 最多可以包含2³²-1个元素 (4294967295, 每个列表超过40亿个元素)。

2.常见操作

2.1 LPUSH/RPUSH/LRANGE

LPUSH将一个或多个值插入头部(左边),RPUSH是将一个或多个值插入尾部(右边)

案例:

127.0.0.1:6379> lpush list1 1 2 3 4 5(integer) 5127.0.0.1:6379> rpush list2 1 2 3 4 5(integer) 5

LRANGE从头部开始遍历,获取元素,下标从0开始,0到-1是全部遍历

案例:

127.0.0.1:6379> LRANGE list1 0 31) "5"2) "4"3) "3"4) "2"127.0.0.1:6379> LRANGE list2 0 -11) "1"2) "2"3) "3"4) "4"5) "5"127.0.0.1:6379> LRANGE list1 0 -11) "5"2) "4"3) "3"4) "2"5) "1"

不存在RRANGE命令

2.2 LPOP/RPOP

LPOP,从左侧弹出(移除)元素,RPOP从右侧弹出元素,被弹出的元素会被返回。

127.0.0.1:6379> lrange list1 0 -11) "5"2) "4"3) "3"4) "2"5) "1"127.0.0.1:6379> lpop list1 "5"127.0.0.1:6379> lpop list1 "4"127.0.0.1:6379> lpop list1 "3"127.0.0.1:6379> lpop list1 "2"127.0.0.1:6379> lpop list1 "1"
127.0.0.1:6379> lrange list2 0 -11) "1"2) "2"3) "3"4) "4"5) "5"127.0.0.1:6379> rpop list2"5"127.0.0.1:6379> rpop list2"4"127.0.0.1:6379> rpop list2"3"127.0.0.1:6379> rpop list2"2"127.0.0.1:6379> rpop list2"1"

2.3 LINDEX

根据下标获取元素

127.0.0.1:6379> rpush list1 1 2 3 4 5(integer) 5127.0.0.1:6379> lindex list1 0"1"127.0.0.1:6379> lindex list1 2"3"

2.4 LLEN

元素个数,list.size();

127.0.0.1:6379> lrange list1 0 -11) "1"2) "2"3) "3"4) "4"5) "5"127.0.0.1:6379> llen list1(integer) 5

2.5 LREM

删除num个值是value的元素

lrem key num value

例:

127.0.0.1:6379> lpush list3 1 2 3 4 5 5 5 5 5 6 7 8(integer) 12127.0.0.1:6379> lrange list3 0 -1 1) "8" 2) "7" 3) "6" 4) "5" 5) "5" 6) "5" 7) "5" 8) "5" 9) "4"10) "3"11) "2"12) "1"127.0.0.1:6379> lrem list3 2 5(integer) 2127.0.0.1:6379> lrange list3 0 -1 1) "8" 2) "7" 3) "6" 4) "5" 5) "5" 6) "5" 7) "4" 8) "3" 9) "2"10) "1"

2.6 LTRIM

截取指定范围的值后再赋给key

LTRIM key start end

例:

127.0.0.1:6379> rpush list1 1 2 3 4 5 6 (integer) 6127.0.0.1:6379> lrange list1 0 -11) "1"2) "2"3) "3"4) "4"5) "5"6) "6"127.0.0.1:6379> LTRIM list1 3 5OK127.0.0.1:6379> lrange list1 0 -11) "4"2) "5"3) "6"

2.7 RPOPLPUSH

移除列表的最后一个元素,并将该元素添加到另一个列表并返回

RPOPLPUSH key source target

例:

127.0.0.1:6379> lrange list1 0 -11) "1"2) "2"3) "3"4) "4"127.0.0.1:6379> lrange list2 0 -11) "5"2) "6"3) "7"4) "8"127.0.0.1:6379> rpoplpush list1 list2"4"127.0.0.1:6379> lrange list1 0 -11) "1"2) "2"3) "3"127.0.0.1:6379> lrange list2 0 -11) "4"2) "5"3) "6"4) "7"5) "8"

2.8 LSET

设置某个下标的值

LSET key index value

例:

127.0.0.1:6379> lrange list2 0 -11) "4"2) "5"3) "6"4) "7"5) "8"127.0.0.1:6379> lset list2  3 abcOK127.0.0.1:6379> lrange list2 0 -11) "4"2) "5"3) "6"4) "abc"5) "8"

2.9 LINSERT

在某个已有值existValue前或后加个新的值newValue

LINSERT key before|after existValue newValue

例:

127.0.0.1:6379> lrange list2 0 -11) "4"2) "5"3) "6"4) "abc"5) "8"127.0.0.1:6379> LINSERT list2 before abc def(integer) 6127.0.0.1:6379> lrange list2 0 -11) "4"2) "5"3) "6"4) "def"5) "abc"6) "8"

Redis数据结构之Set

2024年10月16日 00:00

1.概述

  • Set是String类型的无序集合,集合成员是唯一的,这就意味着集合中不能出现重复的数据,集合对象的编码可以是intset或者hashtable。
  • Set是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
  • Set中最大的成员数为2³²-1 (4294967295,每个集合可存储40多亿个成员)。

2.常见操作

2.1 SADD

添加元素到set中,不能重复添加

127.0.0.1:6379> sadd set1 a b c d e f g(integer) 7127.0.0.1:6379> sadd set2 a a a b b b c c c(integer) 3

2.2 SMEMBERS

查看set中所有元素

127.0.0.1:6379> SMEMBERS set11) "a"2) "g"3) "c"4) "f"5) "d"6) "e"7) "b"127.0.0.1:6379> SMEMBERS set21) "a"2) "c"3) "b"

2.3 SISMEMBER

判断set中是否有某个元素

127.0.0.1:6379> SISMEMBER set2 a(integer) 1127.0.0.1:6379> SISMEMBER set2 d(integer) 0

2.4 SREM

从set 中移除元素

127.0.0.1:6379> SMEMBERS set11) "a"2) "g"3) "c"4) "f"5) "d"6) "e"7) "b"127.0.0.1:6379> srem set1 g(integer) 1127.0.0.1:6379> SMEMBERS set11) "a"2) "c"3) "f"4) "d"5) "e"6) "b"

2.5 SCARD

set中元素个数

127.0.0.1:6379> SCARD set1(integer) 6

2.6 SRANDMEMBER

从set中随机选择n个元素(不会删除)

SRANDMEMBER key n

例:

127.0.0.1:6379> SMEMBERS set11) "a"2) "c"3) "f"4) "d"5) "e"6) "b"127.0.0.1:6379> SRANDMEMBER set1 21) "f"2) "e"127.0.0.1:6379> SRANDMEMBER set1 21) "a"2) "e"

2.7 SPOP

从set中随机弹出(删除)n个元素

SPOP key n

例:

127.0.0.1:6379> SMEMBERS set11) "a"2) "c"3) "f"4) "d"5) "e"6) "b"127.0.0.1:6379> SPOP set1 21) "c"2) "a"127.0.0.1:6379> SPOP set1 21) "b"2) "f"127.0.0.1:6379> SPOP set1 21) "d"2) "e"127.0.0.1:6379> SPOP set1 2(empty list or set)

2.8 SMOVE

将set1中的v移动到set2中去

smove key key value

例:

127.0.0.1:6379> sadd set1 1 2 3(integer) 3127.0.0.1:6379> sadd set2 a b c(integer) 3127.0.0.1:6379> smove set1 set2 2(integer) 1127.0.0.1:6379> SMEMBERS  set11) "1"2) "3"127.0.0.1:6379> SMEMBERS  set21) "a"2) "2"3) "c"4) "b"

2.9 集合运算

127.0.0.1:6379> smembers set31) "1"2) "c"3) "b"4) "a"5) "2"6) "3"127.0.0.1:6379> smembers set41) "c"2) "b"3) "2"4) "5"5) "4"6) "d"7) "3"

1.差集运算

set3-set4:set3有set4没有

127.0.0.1:6379> sdiff  1) "a"2) "1"

2.并集运算

语法

sunion key key [key ......]  

例:

127.0.0.1:6379> sunion set3 set41) "c"2) "4"3) "5"4) "1"5) "3"6) "b"7) "a"8) "2"9) "d"

3.交集运算

sinter,同时属于几个集合的公共部分

sinter key key [key ...]  

例:

127.0.0.1:6379> sinter set3 set41) "c"2) "b"3) "2"4) "3"

SINTERCARD,redis7新命令,不返回结果集,只返回结果的基数,返回由所有给定集合的交集产生的集合的基数

SINTERCARD numkeys key [key ...] [LIMIT limit]

例:2个集合,set3和set4,交集中共有4个元素,可以限制返回的个数,但是不能超过元素的总个数

127.0.0.1:6379> SINTERCARD  2 set3 set4(integer) 4127.0.0.1:6379> SINTERCARD  2 set3 set4 limit 1(integer) 1127.0.0.1:6379> SINTERCARD  2 set3 set4 limit 2(integer) 2127.0.0.1:6379> SINTERCARD  2 set3 set4 limit 3(integer) 3127.0.0.1:6379> SINTERCARD  2 set3 set4 limit 4(integer) 4127.0.0.1:6379> SINTERCARD  2 set3 set4 limit 5(integer) 4

3.总结

Set集合的使用场景很多,例如:

  1. 可能认识的人或共同感兴趣的话题,商品
    sdiff a b
    sdiff b a

  2. 年会抽奖活动
    sadd 活动key 用户ID:参与抽奖
    scard 活动key:统计参加总人数
    SRANDMEMBER 活动key n:抽取n个幸运的人,这几个人还能继续抽奖
    spop 活动key n:抽取n个幸运的人,这几个人不能继续抽奖

Redis数据结构之Stream

2024年10月16日 00:00

1.概述

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

Redis Stream主要用于消息队列(MQ,Message Queue),Redis本身是有一个Redis发布订阅(pub/sub)来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis宕机等,消息就会被丢弃,而且没有ACK机制来保证数据的可靠性,假设一个消费者都没有,那消息就直接被丢弃了,简单来说发布订阅(pub/sub)可以分发消息,但无法记录历史消息。

而Redis Stream提供了消息的持久化和主备复制功能,支持自动生成全局唯一ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream是一个链表,会将所有加入的消息都串起来,每个消息都有一个唯一的ID和对应的内容

Redis Stream组成部分说明:

  • Message Content

    消息

  • Consumer group

    消费组,通过XGROUP CREATE命令创建,同一个消费组可以有多个消费者

  • Last_delivered_id

    游标,每个消费组会有个游标last_delivered_id,任意一个消费者读取了消息都会使游标last_delivered_id往前移动

  • Consumer

    消费者,包含在消费组当中

  • Pending_ids

    消费者会布一个状态变量,用于记录被当前消费者已读取但未ack的消息id,如果客户端没有ack,这个变量里面的消息ID会越来越多,一旦某个消息被ack,它就开始减少。这个pending_ids变量在Redis官方被称之为PEL(Pending Entries List),记录了当前已经被客户端读取的消息,但是还没有ack(Acknowledge character:确认字符),它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了没处理

2.队列(生产)相关命令

2.1 XADD

添加消息到队列末尾,如果队列不存在,则会先创建队列

  • key
  • *|id 消息的ID,格式必须是时间戳-序列号这样的方式,下一条的ID必须比上一条的要大,写成*号,系统将自动生成。ID比较大小时,先比较时间戳大小,若相同再比较序列号
  • field value 键值对
XADD <key> <*|id> <field value> [<field value ...>]

127.0.0.1:6379> XADD mystream * name lzj age 28"1758432825026-0"127.0.0.1:6379> XADD mystream * name xxn age 24"1758432832463-0"

返回的1748835683065-01748835967616-0就是消息的ID,-前的数字为生成消息时的毫秒级时间戳,-后面的数字代表同一毫秒内产生的第几个序列号

在相同的毫秒下序列号从0开始递增,序列号是64位长度,理论上在同一毫秒内生成的数据量无法到达这个级别,因此不用担心序列号会不够用。毫秒数取的是Redis节点服务器的本地时间,如果存在当前的毫秒时间戳比以前已经存在的数据的时间戳小的话(本地时间钟后跳),那么系统将会采用以前相同的毫秒创建新的ID,也即redis在增加信息条目时会检査当前id与上一条目的id,自动纠正错误的情况,一定要保证后面的id比前面大,一个流中信息条目的ID必须是单调增的,这是stream的基础。

Stream的数据类型就是Stream

127.0.0.1:6379> type mystreamstream

2.2 XRANGE

获取消息列表(可以指定范围),忽略删除的消息

  • key 对应的stream
  • start 开始值,用-表示最小
  • end 结束值,用+表示最小
  • count 限制条数
XRANGE <key> <start> <end> [Count <count>]

127.0.0.1:6379> xrange mystream - + 1) 1) "1758432825026-0"   2) 1) "name"      2) "lzj"      3) "age"      4) "28"2) 1) "1758432832463-0"   2) 1) "name"      2) "xxn"      3) "age"      4) "24"

2.3 XREVRANGE

和XRANGE相比,区别在于反向获取,ID从大到小

127.0.0.1:6379> xrevrange mystream + - 1) 1) "1758432832463-0"   2) 1) "name"      2) "xxn"      3) "age"      4) "24"2) 1) "1758432825026-0"   2) 1) "name"      2) "lzj"      3) "age"      4) "28"

2.4 XDEL

删除消息,按照ID删除

XDEL <key> <id> [<id ...>]

XDEL mystream 1748835967616-0

2.5 XLEN

获取Stream中的消息长度

127.0.0.1:6379> XLEN mystream2

2.6 XTRIM

限制Stream的长度,如果已经超长会进行截取

  • MAXLEN 允许的最大长度,对流进行修剪限制长度
  • MINID 允许的最小id,从某个id值开始比该id值小的将会被抛弃
XTRIM <stream> MAXLEN|MINID <n>

127.0.0.1:6379> XTRIM mystream MAXLEN 24
127.0.0.1:6379> XTRIM mystream MINID 1748841640027-01

2.7 XREAD

获取消息(阻塞/非阻塞),返回大于指定ID的消息

  • COUNT 最多读取多少条
  • BLOCK 是否以阻塞的方式读取消息,默认不阻塞,如果miliseconds设置为0,表示永远阻塞
  • STREAMS 队列
  • ID 指定的ID,用$代表队列内现存最大的ID的后一个ID,用0-0(或0; 00)代表队列中最小的ID
XREAD [COUNT <count>] [BLOCK <milliseconds>] STREAMS <key> [<key ...>] ID [<id ...>]

例:用$代表队列内现存最大的ID的后一个ID,因为该ID并不存在所以会返回空

127.0.0.1:6379> Xrange mystream - +1) 1) "1758432825026-0"   2) 1) "name"      2) "lzj"      3) "age"      4) "28"2) 1) "1758432832463-0"   2) 1) "name"      2) "xxn"      3) "age"      4) "24"127.0.0.1:6379> XREAD  STREAMS mystream  $(nil)

例:用0-0代表队列中最小的ID,当指定为0-0的同时不指定count时,会返回队列中所有的元素

127.0.0.1:6379> Xrange mystream - +1) 1) "1758432825026-0"   2) 1) "name"      2) "lzj"      3) "age"      4) "28"2) 1) "1758432832463-0"   2) 1) "name"      2) "xxn"      3) "age"      4) "24"127.0.0.1:6379> XREAD  STREAMS mystream  0-01) 1) "mystream"   2) 1) 1) "1758432825026-0"         2) 1) "name"            2) "lzj"            3) "age"            4) "28"      2) 1) "1758432832463-0"         2) 1) "name"            2) "xxn"            3) "age"            4) "24"

例:阻塞:监听mystream中比最新的一条还靠后的一条,读取不到就会阻塞,一直监听

127.0.0.1:6379> XREAD COUNT 1 BLOCK 0  STREAMS mystream $

打开另一个命令窗口,生产消息

127.0.0.1:6379> xadd mystream * k1 v1"1758434052255-0"

XREAD停止阻塞,打印出新生产的一条消息和等待时间

127.0.0.1:6379> XREAD COUNT 1 BLOCK 0  STREAMS mystream $1) 1) "mystream"   2) 1) 1) "1758434052255-0"         2) 1) "k1"            2) "v1"(183.38s)

3.消费(组)相关命令

3.1 XGROUP CREATE

创建消费组

  • stresm 队列
  • group 消费组
  • id 创建消费组时必须指定ID,0代表从头消费,$代表从队尾消费(只消费最新消息)
XGROUP CREATE <stresm> <group> <id>

例:

127.0.0.1:6379> xgroup create mystream group1 $OK127.0.0.1:6379> xgroup create mystream group2 0OK

3.2 XREADGROUP GROUP

允许多个消费者作为一个组来合作消费同一个stream中的消息,同一个stream中的消息一旦被消费组里面的一个消费者读取了,同组的其他消费者就无法再次读取

  • group 消费组
  • consumer 消费者
  • stream 队列
  • id 指定从哪个ID开始读取,特殊写法:>代表获取组内未分发给其他消费者的新消息(未分发必然未ACK),0代表获取已分发但未被消费者ACK的消息
  • count 读取的数量,可以用于每个消费者读取一部分消息,实现消费的负载均衡
XREADGROUP GROUP <group> <consumer> [COUNT <count>] STREAMS <stream, ...> <id>

例:同组消费者不能重复消费消息

先建两个消费组

127.0.0.1:6379> xgroup create mystream groupA 0OK127.0.0.1:6379> xgroup create mystream groupB 0OK

groupA里面的新建消费者consumer1进行消费

127.0.0.1:6379> XREADGROUP GROUP groupA consumer1 STREAMS mystream >1) 1) "mystream"   2) 1) 1) "1758432825026-0"         2) 1) "name"            2) "lzj"            3) "age"            4) "28"      2) 1) "1758432832463-0"         2) 1) "name"            2) "xxn"            3) "age"            4) "24"      3) 1) "1758434052255-0"         2) 1) "k1"            2) "v1"

groupA中再去新建消费者consumer2进行消费,无法再消费消息

127.0.0.1:6379> XREADGROUP GROUP groupA consumer2 STREAMS mystream >(nil)

但是,groupB中新建一个消费者取消费,可以读取到消息

127.0.0.1:6379> XREADGROUP GROUP groupB consumer1 STREAMS mystream >1) 1) "mystream"   2) 1) 1) "1758432825026-0"         2) 1) "name"            2) "lzj"            3) "age"            4) "28"      2) 1) "1758432832463-0"         2) 1) "name"            2) "xxn"            3) "age"            4) "24"      3) 1) "1758434052255-0"         2) 1) "k1"            2) "v1"

例:负载均衡的消费,新建消费组groupC,三个消费者每个消费一条消息

127.0.0.1:6379> xgroup create mystream groupC 0OK127.0.0.1:6379> XREADGROUP GROUP groupC consumer1 COUNT 1 STREAMS mystream >1) 1) "mystream"   2) 1) 1) "1758432825026-0"         2) 1) "name"            2) "lzj"            3) "age"            4) "28"127.0.0.1:6379> XREADGROUP GROUP groupC consumer2 COUNT 1 STREAMS mystream >1) 1) "mystream"   2) 1) 1) "1758432832463-0"         2) 1) "name"            2) "xxn"            3) "age"            4) "24"127.0.0.1:6379> XREADGROUP GROUP groupC consumer3 COUNT 1 STREAMS mystream >1) 1) "mystream"   2) 1) 1) "1758434052255-0"         2) 1) "k1"            2) "v1"

3.3 消息的ACK机制

基于Stream的消息,怎样保证消费者发生故障或宕机以后,仍然能读取未处理完的消息?Stream采用的是一个内部队列pending_list,记录消费组中消费者的读取记录,直到消费者使用xack命令来通知stream消息已经处理完成,这种消费确认机制增强了消息的可靠性。

刚刚的消费操作仅仅是对消息的读取,实际上并没有ACK“签收”

例:通过命令XPENDING查询groupC中已读取,但未确认的消息

127.0.0.1:6379> XPENDING mystream groupC1) (integer) 3 #总数2) "1758432825026-0" #起始ID3) "1758434052255-0" #结束ID4) 1) 1) "consumer1" #每个消费组消费的消息数量      2) "1"   2) 1) "consumer2"      2) "1"   3) 1) "consumer3"      2) "1"

例:通过命令XPENDING查询groupB中consumer1已读取,但未确认的消息,从小到大查询10个

127.0.0.1:6379> XPENDING mystream groupB - + 10  consumer11) 1) "1758432825026-0"   2) "consumer1"   3) (integer) 2848434   4) (integer) 12) 1) "1758432832463-0"   2) "consumer1"   3) (integer) 2848434   4) (integer) 13) 1) "1758434052255-0"   2) "consumer1"   3) (integer) 2848434   4) (integer) 1

例:使用XACK向消息队列确认groupB组的消息1758432825026-0已经处理完成

127.0.0.1:6379> XACK mystream groupB 1758432825026-0(integer) 1
127.0.0.1:6379> XPENDING mystream groupB - + 10  consumer11) 1) "1758432832463-0"   2) "consumer1"   3) (integer) 3301753   4) (integer) 12) 1) "1758434052255-0"   2) "consumer1"   3) (integer) 3301753   4) (integer) 1

4.XINFO

XINFO命令用于打印出一些stream结构相关的信息

例:XINFO stream打印出mystream队列的详细信息

127.0.0.1:6379> XINFO stream  mystream 1) "length" 2) (integer) 3 3) "radix-tree-keys" 4) (integer) 1 5) "radix-tree-nodes" 6) (integer) 2 7) "last-generated-id" 8) "1758434052255-0" 9) "max-deleted-entry-id"10) "0-0"11) "entries-added"12) (integer) 313) "recorded-first-entry-id"14) "1758432825026-0"15) "groups"16) (integer) 517) "first-entry"18) 1) "1758432825026-0"    2) 1) "name"       2) "lzj"       3) "age"       4) "28"19) "last-entry"20) 1) "1758434052255-0"    2) 1) "k1"       2) "v1"

例:XINFO groups打印出mystream队列队列上存在的消费组信息

127.0.0.1:6379> XINFO  groups mystream1)  1) "name"    2) "group1"    3) "consumers"    4) (integer) 0    5) "pending"    6) (integer) 0    7) "last-delivered-id"    8) "1758434052255-0"    9) "entries-read"   10) (nil)   11) "lag"   12) (integer) 02)  1) "name"    2) "group2"    3) "consumers"    4) (integer) 0    5) "pending"    6) (integer) 0    7) "last-delivered-id"    8) "0-0"    9) "entries-read"   10) (nil)   11) "lag"   12) (integer) 33)  1) "name"    2) "groupA"    3) "consumers"    4) (integer) 2    5) "pending"    6) (integer) 3    7) "last-delivered-id"    8) "1758434052255-0"    9) "entries-read"   10) (integer) 3   11) "lag"   12) (integer) 04)  1) "name"    2) "groupB"    3) "consumers"    4) (integer) 1    5) "pending"    6) (integer) 2    7) "last-delivered-id"    8) "1758434052255-0"    9) "entries-read"   10) (integer) 3   11) "lag"   12) (integer) 05)  1) "name"    2) "groupC"    3) "consumers"    4) (integer) 3    5) "pending"    6) (integer) 3    7) "last-delivered-id"    8) "1758434052255-0"    9) "entries-read"   10) (integer) 3   11) "lag"   12) (integer) 0

Redis数据结构之String

2024年10月16日 00:00

1.概述

  • String是最常用的数据类型,一个key对应一个value。
  • String是二进制安全的,可以包含任何数据(例如图片和序列化对象),支持序列化。
  • 单个Value最大512MB。

2.常见操作

2.1 SET/GET

语法:

[ ]是可选的参数

SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]

SET命令有EXPXNXXX以及KEEPTTL五个可选参数,其中KEEPTTL为6.0版本添加的可选参数,其它为2.6.12版本添加的可选参数。

  • EX seconds 以秒为单位设置过期时间
  • PX milliseconds 以毫秒为单位设置过期时间
  • EXAT timestamp 设置以秒为单位的UNIX时间戳所对应的时间为过期时间
  • PXAT milliseconds-timestamp 设置以毫秒为单位的UNIX时间戳所对应的时间为过期时间
  • NX 键不存在的时候设置键值
  • XX 键存在的时候设置键值
  • KEEPTTL 保留设置前指定键的生存时间
  • GET 返回指定键原本的值,若键不存在时返回nil

SET命令使用EXPXNX参数,其效果等同于SETEXPSETEXSETNX命令。根据官方文档的描述,未来版本中SETEXPSETEXSETNX命令可能会被淘汰。

EXNX可用于分布式锁。

案例:最常用的set/get

127.0.0.1:6379> set k1 v1OK127.0.0.1:6379> get k1"v1"

案例:NX,键不存在才能创建,否则不能创建

127.0.0.1:6379> set k1 v1 nxOK127.0.0.1:6379> set k1 v1 nx(nil)

案例:XX,已存在的才创建,否则不能创建

127.0.0.1:6379> set k1 v1 OK127.0.0.1:6379> set k1 v1 xxOK127.0.0.1:6379> get k2(nil)127.0.0.1:6379> set k2 v2 xx(nil)

案例:GET,设置新的值前先把旧的值返回

127.0.0.1:6379> set k1 v1OK127.0.0.1:6379> set k1 v2 get"v1"

案例:EX,10秒过期

127.0.0.1:6379> set k1 v1 ex 10OK127.0.0.1:6379> ttl k1(integer) 8127.0.0.1:6379> ttl k1(integer) 6127.0.0.1:6379> ttl k1(integer) 4

set ex是原子操作,和先set key value然后expire key是不同的,后者不是原子的

案例:PX,9000毫秒过期

127.0.0.1:6379> set k1 v1 px 9000OK127.0.0.1:6379> ttl k1(integer) 7127.0.0.1:6379> ttl k1(integer) 5127.0.0.1:6379> ttl k1(integer) 4

案例:KEEPTTL

同一个key如果设置了新的值,又没有追加过期时间,redis会令其立即过期

127.0.0.1:6379> set k1 v1 ex 40OK127.0.0.1:6379> ttl k1(integer) 37127.0.0.1:6379> set k1 v2OK127.0.0.1:6379> ttl k1(integer) -1

如果需要续接过期时间,就需要用到参数KEEPTTL,设置新值后,过期时间会被续接下来

127.0.0.1:6379> set k1 v1 ex 50  OK127.0.0.1:6379> ttl k1(integer) 46127.0.0.1:6379> set k1 v1 keepttlOK127.0.0.1:6379> ttl k1(integer) 33

2.2 MSET/MGET/MSETNX

案例:MSET同时设置和获取多个值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3OK127.0.0.1:6379> mget k1 k2 k31) "v1"2) "v2"3) "v3"

案例 MSETNX,同时设置多个key的值,且key不存在才设置,只会同时成功或同时失败

失败,因为k1已经存在,k1没有成功修改,k2也根本存不进去

127.0.0.1:6379> flushdbOK127.0.0.1:6379> set k1 v1OK127.0.0.1:6379> msetnx k1 a1 k2 v2(integer) 0127.0.0.1:6379> get k1"v1"127.0.0.1:6379> get k2(nil)

成功,k1,k2都不存在,全部添加成功

127.0.0.1:6379> flushdbOK127.0.0.1:6379> msetnx k1 v1 k2 v2(integer) 1127.0.0.1:6379> mget k1 k21) "v1"2) "v2"

2.3 GETRANGE/SETRANGE

GETRANGE,类似Java中的substring(),字符串截取, 0到-1代表不截取

案例:

127.0.0.1:6379> set k1 abcdefgOK127.0.0.1:6379> getrange k1 0 -1"abcdefg"127.0.0.1:6379> getrange k1 1 4"bcde"

SETRANGE,从第几个字符开始设置新的内容

案例:

127.0.0.1:6379> set k1 abcdefgOK127.0.0.1:6379> setrange k1 1 xxyy(integer) 7127.0.0.1:6379> get k1"axxyyfg"

2.4 INCR(BY)/DECR(BY)

数值的加减,值一定要是数字才能进行这个操作

案例:INCR,每次执行加1

127.0.0.1:6379> set k1 100OK127.0.0.1:6379> get k1"100"127.0.0.1:6379> incr k1(integer) 101127.0.0.1:6379> incr k1(integer) 102127.0.0.1:6379> incr k1(integer) 103127.0.0.1:6379> incr k1(integer) 104

案例:INCRBY,修改步长为5

127.0.0.1:6379> set k1 0OK127.0.0.1:6379> incrby k1 5(integer) 5127.0.0.1:6379> incrby k1 5(integer) 10127.0.0.1:6379> incrby k1 5

案例:DECR,递减1,DECRBY同理

127.0.0.1:6379> set k1 100OK127.0.0.1:6379> decr k1(integer) 99127.0.0.1:6379> decr k1(integer) 98127.0.0.1:6379> decr k1(integer) 97
127.0.0.1:6379> set k1 100OK127.0.0.1:6379> decrby k1 5(integer) 95127.0.0.1:6379> decrby k1 5(integer) 90127.0.0.1:6379> decrby k1 5(integer) 85

2.5 STRLEN

字符串长度

语法

strlen key

案例

127.0.0.1:6379> set k1 aaaOK127.0.0.1:6379> strlen k1(integer) 3

2.6 APPEND

字符串追加

语法

APPEND key value

案例

127.0.0.1:6379> set k1 aaaOK127.0.0.1:6379> append k1 bbb(integer) 6127.0.0.1:6379> get k1"aaabbb"

2.7 GETSET

getset,顾名思义,先取值在设置新的值进去,和set key value get命令相同

127.0.0.1:6379> set k1 v1OK127.0.0.1:6379> getset k1 v2"v1"127.0.0.1:6379> get k1"v2"

3.小结

字符串是一个最基本的数据结构,可用于分布式锁,点赞数量统计等场景。

Redis数据结构之ZSet

2024年10月16日 00:00

1.概述

  • ZSet和Set一样也是String类型元素的集合,且不允许重复的成员,不同的是ZSet每个元素都会关联一个double类型的分数,Redis正是通过分数来为集合中的成员进行从小到大的排序。
  • ZSet的成员是唯一的,但分数(score)却可以重复。
  • ZSet集合是通过哈希表实现的,所以添加,删除,査找的复杂度都是O(1)。
  • ZSet集合中最大的成员数为2³²-1。

2.常见操作

2.1 ZADD

向有序集合中添加元素和元素的分数

ZADD key score member [score member ...]

例:

127.0.0.1:6379> zadd zset1 10 v1 20 v2 30 v3 40 v4(integer) 4

2.2 ZRANGE

遍历,0到-1代表遍历所有,WITHSCORES结果带着分数

ZRANGE key start stop [WITHSCORES]

例:遍历

127.0.0.1:6379> zrange zset1 0 -11) "v1"2) "v2"3) "v3"4) "v4"

例:遍历,结果带着分数

127.0.0.1:6379> zrange zset1 0 -1 withscores1) "v1"2) "10"3) "v2"4) "20"5) "v3"6) "30"7) "v4"8) "40"

2.3 ZREVRANGE

根据分数反转

127.0.0.1:6379> ZREVRANGE zset1 0 -11) "v4"2) "v3"3) "v2"4) "v1"127.0.0.1:6379> ZREVRANGE zset1 0 -1 withscores1) "v4"2) "40"3) "v3"4) "30"5) "v2"6) "20"7) "v1"8) "10"

2.4 ZRANGEBYSCORE

获取指定分数范围的元素

ZRANGEBYSCORE key [(]min max [WITHSCORES] [LIMIT offset count]

(:不包含
min:分数from
max:分数to
offset:开始下标
count:数量

例:获取分数区间[20, 30]的元素

127.0.0.1:6379> ZRANGE zset1 0 -1 withscores1) "v1"2) "10"3) "v2"4) "20"5) "v3"6) "30"7) "v4"8) "40"127.0.0.1:6379> ZRANGEBYSCORE zset1 20 301) "v2"2) "v3"127.0.0.1:6379> ZRANGEBYSCORE zset1 20 30 withscores1) "v2"2) "20"3) "v3"4) "30"

例:获取分数区间(20, 40]的元素

127.0.0.1:6379> ZRANGE zset1 0 -1 withscores1) "v1"2) "10"3) "v2"4) "20"5) "v3"6) "30"7) "v4"8) "40"127.0.0.1:6379> ZRANGEBYSCORE zset1 (20 401) "v3"2) "v4"

例:limit限制返回的数量

127.0.0.1:6379> ZRANGE zset1 0 -1 withscores1) "v1"2) "10"3) "v2"4) "20"5) "v3"6) "30"7) "v4"8) "40"127.0.0.1:6379> ZRANGEBYSCORE zset1 10 40 limit 1 21) "v2"2) "v3"

2.5 ZSCORE

获取元素分数

127.0.0.1:6379> zscore zset1 v3"30"

2.6 ZCARD

元素个数

127.0.0.1:6379> zcard zset1 (integer) 4

2.6 ZREM

删除某个元素

127.0.0.1:6379> zrem zset1 v3 (integer) 1

2.7 ZINCRBY

为元素member增加分数increment

ZINCRBY key increment member

例:对元素v1加3分

127.0.0.1:6379> zrange zset1 0 -1 withscores1) "v1"2) "10"3) "v2"4) "20"5) "v4"6) "40"127.0.0.1:6379> zincrby zset1 3 v1"13"127.0.0.1:6379> zrange zset1 0 -1 withscores1) "v1"2) "13"3) "v2"4) "20"5) "v4"6) "40"

2.8 ZCOUNT

获得指定分数范围内的元素个数

min: 最小分数
max: 最大分数

ZCOUNT key min max

例:

127.0.0.1:6379> zrange zset1 0 -1 WITHSCORES 1) "v1" 2) "10" 3) "v2" 4) "20" 5) "v3" 6) "30" 7) "v4" 8) "40" 9) "v5"10) "50"11) "v6"12) "60"13) "v7"14) "70"127.0.0.1:6379> zcount zset1  30 50(integer) 3

2.9 ZMPOP

7.0新特性,在指定的numkeys个集合中,弹出分数最大(MAX)或最小(MIN)的count个元素(分数和值成对),可以实现在一个或多个集合中,取出最小或最大的几个元素

ZMPOP numkeys key [key ...] <MIN | MAX> [COUNT count]

例:在1个zset1集合中,弹出最小的1个元素

127.0.0.1:6379> zrange zset1 0 -1 WITHSCORES 1) "v1" 2) "10" 3) "v2" 4) "20" 5) "v3" 6) "30" 7) "v4" 8) "40" 9) "v5"10) "50"11) "v6"12) "60"13) "v7"14) "70"127.0.0.1:6379> ZMPOP 1 zset1 min count 11) "zset1"2) 1) 1) "v1"      2) "10"127.0.0.1:6379> 

2.10 ZRANK

正序下标,集合的某个元素,正序处于集合第几个

127.0.0.1:6379> zrange zset1 0 -11) "v2"2) "v3"3) "v4"4) "v5"5) "v6"6) "v7"127.0.0.1:6379> zrank zset1 v2(integer) 0127.0.0.1:6379> zrank zset1 v3(integer) 1127.0.0.1:6379> zrank zset1 v4(integer) 2127.0.0.1:6379> zrank zset1 v5(integer) 3

2.11 ZREVRANK

倒序下标,集合的某个元素,倒序处于集合第几个

127.0.0.1:6379> zrange zset1 0 -11) "v2"2) "v3"3) "v4"4) "v5"5) "v6"6) "v7"127.0.0.1:6379> zrevrank zset1 v2(integer) 5127.0.0.1:6379> zrevrank zset1 v3(integer) 4127.0.0.1:6379> zrevrank zset1 v4(integer) 3127.0.0.1:6379> zrevrank zset1 v5(integer) 2

3.总结

排序集合大量应用于项目,例如实时展示热销商品统计,打赏点赞数量排行榜统计。将销量和点赞打赏数作为分数绑定在值上面即可。

❌