Redis②数据类型、发布/订阅
1、基本命令
Redis 命令中心:讲解 Redis 数据类型的常用命令。
1.1、key
- 查询
keys *:当前库的所有 key。exists key:判断指定 key 是否存在。type key:指定 key 的类型。
- 删除
del key:删除指定 key 的数据。unlink key:将 key 从 keyspace 元数据中删除,非阻塞删除(异步)。
- 过期时间
expire key:设置过期时间(秒)。ttl key:查看存活时间(time to live,秒),-1 永不过期,-2 已过期。
1.2、数据库
Redis 默认有 16 个数据库,默认使用 0 号库。
select:切换数据库。dbsize:查看当前库的 key 数量。flushdb:清空当前库。flushall:清空所有库。
2、数据类型
- key-value:Key 是字符串,Value 可以是不同的数据类型。
- 数据类型的操作具有原子性(由于单线程)。
1.1、String(字符串)
Redis 最基本的数据类型
- 二进制安全,可包含任何数据(如序列化对象)
- String 类型的 Value,最大值是 512M。
1.1.1、数据结构
简单动态字符串(Simple Dynamic String,SDS)
-
类似 Java 的 ArrayList
-
内存分配:预分配冗余空间(capacity),减少内存的频繁分配。
-
扩容:字符串长度(len)
-
len < 1M 则加倍,len > 1M 则扩容 1M。
-
最大长度是 512M。

-
1.1.2、常用命令
① 存取
-
set:添加键值对。
-
setex:添加键值对,并设置过期时间(秒,expire)。
-
setnx:添加键值对,前提是指定 Key 不存在(not exists)。
-
get:查询指定 Key 的 Value 值。
-
mset:添加多个键值对。
-
msetnx:添加多个键值对,前提是指定的所有 Key 都不存在。
-
mget:查询指定的多个 Key 的 Value 值。
setsetex <过期时间> setnx get # multi mset msetnx mget
② 范围
类似子串(subString),索引从 0 开始。
-
getrange:指定 Key,获取指定下标范围的值(左右包含)。
-
setrange:指定 Key,覆盖指定起始下标之后的值。
getrange<起始索引><结束索引> setrange <起始索引>
③ 数字增减
只能操作数字值,原子性。
-
incr:自增 1,若为空则赋值 1。
-
decr:自减 1,若空则赋值 -1。
-
incrby:自增指定步长。
-
decrby:自减指定步长。
incr/decrincrby/decrby <步长>
④ 其它
-
替换:查询指定 Key 值,并将 Value 设为指定值。
-
追加:将指定 Value 值,追加到指定 Key 的 Value 值之后。
-
长度
getsetappend strlen
1.1.3、应用场景
- 验证码、token(expire)
- 点赞或访问计数(incr / decr)
1.2、List(列表)
单键多值:简单的字符串列表
有序、有下标、可重复
底层是双向链表,
- 直接操作 List 的头部(左)和尾部(右)元素,性能高。
- 通过下标操作中间元素,性能较低。
1.2.1、数据结构
快速链表(quickList)
-
元素较少时,使用压缩列表存储(ziplist,一块连续的内存)
-
元素较多时,使用快速链表(链表和 ziplist 的结合)
-
ziplist 不利于增删操作。
-
普通链表的指针需要额外占用空间,浪费内存。
-
结合使用,满足增删的性能,减少内存冗余。

-
1.2.2、常用命令
① 存取
-
两侧
-
lpush/rpush:向指定 Key 的左/右侧,添加指定一个或多个值。
-
lpop/rpop:从指定 Key 的左/右侧取出一个值。
-
rpoplpush:从指定 Key 的右侧取出值,添加到另一个 Key 的左侧。
lpush/rpushlpop/rpop rpoplpush
-
-
下标:从左往右
-
lindex:获取指定 Key,指定下标对应的值。
-
linsert before/after:在指定 Key 的指定 Value 前/后,添加指定指定值。
-
lset:替换指定 Key 的指定下标的 Value 值。
-
lrem:指定 Key,删除左侧开始的 n 个 Value。
lindexlinsert before/after lrem lset
-
② 范围、长度
-
lrange:指定 Key,获取指定下标范围的值(左右包含)。
- 下标从 0 开始,负数表示倒数。
- 如
0 -1表示所有 Value。
-
llen:获取指定 Key 的列表长度。
lrangellen
1.2.3、应用
- 发布、订阅
- 消息队列
1.3、Hash(哈希)
键值对集合
- hash 是一个 String 类型的 field 和 value 的映射表。
- 适合存储对象,类似 Java 的 Map
。
1.3.1、数据结构
两种数据结构:ziplist(压缩列表)、hashtable(哈希表)
- field-value 长度短且个数少,使用 ziplist。
- 否则使用 hashtable。
1.3.2、常用命令
① 查询
-
hkeys:列出该 hash 集合的所有 field。
-
hvals:列出该 hash 集合的所有 value。
-
hexists:指定 Key 中,判断指定 field 是否存在。
hkeyshvals hexists
② 存取
-
hset:指定 Key,给指定 field 赋值。
-
hget:从指定 Key 中取出指定 field 的 value 值。
-
hsetnx:指定 Key,给指定 field 赋值。(前提是 field 不存在)
-
hmset: 指定 Key,批量设置多对 field-value 值。
hsethget hsetnx hmset .
③ 递增
指定 Key,将 field 的数值递增指定步长。
hincrby
1.3.3、应用
存储对象:Key 为对象名,Value 为 Hash。

为何不用 String 存储?
-
String-String:Key 为对象名,Value 为序列化的对象。
-
存储:序列化整个对象并存储。
-
问题:修改对象需要先反序列化,修改后再次序列化(开销大)

-
-
String-String:Key 为对象名+属性名,Value 为属性值。
-
存储:分别将属性值存储在不同 Key 下。
-
问题:存储需要使用多个 Key,获取对象时需查询多个 Key(数据冗余)

-
1.4、Set(集合)
单键多值、排序
无序、无下标、不可重复
- 底层是 value 为 null 的 hash 表。
- 增删查的时间复杂度 O(1)。
1.4.1、数据结构
dict 字典(由哈希表实现)
-
Java 的 HashSet:底层 HashMap,所有 value 指向同一个对象。
-
Redis 的 set:底层 hash,field-value 中的 value 为 null。

1.4.2、常用命令
① 查询
-
smembers:查询所有值。
-
srandmember:随机查出 n 个值。
-
sismember:判断是否存在。
-
scard:元素个数(称为基数,cardinality)。
-
spop:随机取出一个值(删除)
# 仅查询 smemberssrandmember sismember scard # 取出 spop
② 增删
-
sadd:将一个或多个值添加到集合 Key 中,已存在的值被忽略。
-
srem:删除集合中指定元素。
-
smove:将元素移动到另一个集合。
saddsrem smove value
③ 集合论
-
sinter:交集。
-
sunion:并集。
-
sdiff:差集。
sintersunion # 包含k1中的,不包含k2中的 sdiff
1.4.3、应用
去重
1.5、Zset(有序集合)
SortedSet(单键多值、排序)
无序、无下标、不可重复
- 相比 Set,Zset 的成员都关联评分(score),用于升序排序。
- 成员唯一,评分可重复。
- 可通过 score 的范围来获取元素。
- 访问 Zset 的中间元素效率比 Set 高。
1.5.1、数据结构
类似 Java 的 TreeSet,排序规则为 score
两个数据结构:hash、跳跃表。
-
hash:保证 field 唯一性,关联 field 和 score。

-
跳跃表:给元素 value 排序,根据 score 范围获取元素。

1.5.2、常用命令
① 查询
-
zrange:查询指定次序范围的元素。
- WITHSCORES:附带 score 值。
-
zrangebyscore:查询指定 score 范围内的元素(左右包含),按 score 升序排序。
-
zrevrangebyscore:同上,但降序排序(reverse)。
-
zcount:查询指定 score 范围内的元素个数。
-
zrank:查询指定值在集合中的排名(从 0 开始)。
zrange[WITHSCORES] zrangebyscore key minmax [withscores] [limit offset count] zrevrangebyscore key maxmin [withscores] [limit offset count] zcount zrank
② 增删
-
zadd:添加一个或多个元素及 score。
-
zrem:删除指定元素。
zaddzrem
③ 递增
zincrby:指定元素的 score 递增指定步长。
zincrby
1.5.3、应用
排行榜
3、新数据类型
3.1、Bitmaps(位图)
充分使用字节的 8 位二进制数。
- 计算机中用 8 位二进制数编码表示数值信息(1 byte = 8 bit)
- Bitmaps 本质是字符串,但支持位操作。
- 可理解成以 bit 为单位的数组,数组下标称为偏移量。
- 充分利用操作位,可有效提高内存使用率和开发效率。
3.1.1、常用命令
-
setbit:设置指定偏移量的值(偏移量,offset 从 0 开始)。
-
getbit:获取指定偏移量的值。
-
bitcount:统计值为 1 的位数目,可指定字节范围。
-
bitop:复合操作(与或非、异或)
setbitgetbit bitcount [start end] bitop and/or/not/xor [key]
案例:某一天用户是否上线
- 设置:用户 ID作为偏移量,用户上线则设为 1。
- 通常,bitmaps 的 Key 为某一天的访问情况。
- 用户 ID 可能未必从 0 开始,需要经过一定处理。
- 获取:根据用户 ID(偏移量)查询,1 表示访问过。
- 数量:统计上线用户数。
- 复合:如 and,查看两天都有上线的用户。
3.1.2、应用
签到、用户在线状态、用户访问情况
3.2、HyperLogLog(基数统计)
3.2.1、基数问题
基数:集合中不重复元素的个数。
- 示例:
{1, 3, 3, 5, 7}的基数集为{1, 3, 5},基数为 3。 - 应用场景:
传统方案
特点:精度高,但随着数据的增加,空间占用过多。
- MySQL:查询 DISTINCT COUNT。
- Redis:hash、set、bitmaps 等数据结构。
HyperLogLog(HLL):基数统计算法
降低一定的精度来平衡存储空间
- 机制
- 根据输入元素来计算基数,而不会存储元素。
- 每个 HLL 的 Key 占用 12KB 内存,可计算接近 2^64 个不同元素的基数。
- 特点:
- 即使输入元素的数量或容量很大,计算基数所占空间固定且很小。
- 只计算基数,不存储元素,无法返回输入的元素。
3.2.2、常用命令
HyperLogLog,以下简称 HLL
-
pfadd:添加一个或多个元素。
-
pfcount:计算一个或多个 HLL 的基数。
-
pfmerge:将一个或多个 HLL 合并到另一个 HLL。
pfaddpfcount pfmerge
案例:记录网站 UV,多次访问只有一个 UV 记录
- 设置:用户 ID 作为 HLL 的元素。
- 统计
- 合并:如合并 7 天的 UV 得到一周的 UV。
3.2.3、应用
UV(UniqueVisitor,独立访客)、独立 IP 数。
3.3、Geospatial(地理)
- 二维坐标表示地图的经纬度。
- 提供经纬度设置、查询等操作。
命令
-
geoadd:添加一个或多个地理位置。
-
geopos:获取指一个或多个 Key 的坐标值。
-
geodist:计算两个位置的直线距离,可设置单位。
-
georadius:获取指定 Key 的半径之内的元素,可设置单位。
geoaddgeopos geodist [m|km|ft|mi ] georadius radius m|km|ft|mi
4、发布/订阅
类似
消息通信模式:发送者(pub)在某个频道中发布消息,订阅者( sub )接收消息。
-
客户端可以订阅任意数量的频道。
-
pub 在频道中发布消息后,sub 自动接收到订阅的消息。
# sub订阅频道 subscribe 频道名 # pub发布信息 publish channel 频道名