Redis常见数据类型命令

39 阅读11分钟

redis = Remote Dictionary Server,远程字典服务。redis是一个内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列(一般用消息列表都会使用Kafka)。它支持字符串,哈希表,列表,集合,有序结合等数据类型。

Strings (字符串)

最简单的类型,可以存储文本、数字(可进行自增/自减)或二进制数据。

字符数组,该字符串是动态字符串row,字符串长度小于1M时,加倍扩容;超过1M每次只多扩1M;字符串最大长度为512M;

注意:redis字符串是二进制安全字符串;可以存储图片,二进制协议等二进制数据;

基础命令

分类命令描述示例
基本操作SET key value设置键值对SET user:1 "Alice"
GET key获取键的值GET user:1
DEL key删除键DEL user:1
EXISTS key检查键是否存在EXISTS user:1
数字操作INCR key将键的整数值增加1INCR views
DECR key将键的整数值减少1DECR stock
INCRBY key increment将键的值增加指定的整数INCRBY score 5
DECRBY key decrement将键的值减少指定的整数DECRBY stock 3
高级操作MSET key1 value1 key2 value2同时设置多个键值对MSET a 1 b 2
MGET key1 key2同时获取多个键的值MGET a b
SETEX key seconds value设置键值对并指定过期时间(秒)SETEX session:abc 3600 "data"
SETNX key value仅当键不存在时才设置其值(用于实现锁)SETNX lock:resource true

存储结构

字符串长度小于等于20且能转成整数,则使用 int 存储;

字符串长度小于等于44,则使用 embstr 存储;

字符串长度大于44,则使用 raw存储;

应用

对象存储

set role::1001 '{["name"]:"zhangsan",["sex"]:"male",["age"]:30}'
set role::1001 '{["name"]:"xishi",["sex"]:"female",["age"]:21}'

get role:1001
    

累加器

#累计加1
incr books
#累计加100
incrby books 100

分布式锁

setnx lock 1 #不存在才能设置,定义加锁行为,占用锁

位运算

# 签到功能,用户id 101 202509 2025年9月1日签到
setbit sign:101:202509 1 1
# 计算2025年9月份的签到情况
bitcount sign:101:202509
#获取 2025年9月份第二天签到情况 1为已签到 2为未签到
gitbit sign:101202509 2

Hashes (哈希)

散列表,在很多高级语言中包含这种数据结构;c++ unordered_map 通过key快速索引value;

基础命令

适合存储对象,例如用户信息(用户ID、姓名、年龄等)。

分类命令描述示例
字段操作HSET key field value设置哈希表中字段的值HSET user:1000 name "Bob" age 30
HGET key field获取哈希表中字段的值HGET user:1000 name
HDEL key field删除哈希表中的一个或多个字段HDEL user:1000 age
HGETALL key获取哈希表中所有的字段和值HGETALL user:1000
批量操作HMGET key field1 field2同时获取哈希表中多个字段的值HMGET user:1000 name age
HMSET key field1 value1 field2 value2同时设置哈希表中多个字段的值(HSET现在也支持)HMSET user:1000 name "Bob" age 30
其他操作HKEYS key获取哈希表中的所有字段名HKEYS user:1000
HVALS key获取哈希表中的所有字段值HVALS user:1000
HINCRBY key field increment为哈希表中的整数字段值增加指定量HINCRBY user:1000 score 5

存储结构

节点数量大于512(hash-max-ziplist-entries)或所有字符串长度大于64(hash-max-ziplist-value),则使用dict 实现;节点数量小于等于512且有一个字符串长度小于64,则使用 ziplist 实现

应用

存储对象

hmset hash:1001 name zhangsan age 18 sex male
# 与string比较
set hash:1001 '{["name:]:"zhangsan",["sex"]:"male",["age"]:18}"
# 修改张三的年龄为19岁

# hash:
hset hash:1001 age 19
# string:
get hash:1001
# 将得到的字符串调用json解密,取出字段,修改age的值
# 再调用json加密
set hash:1001 '{["name"]:"zhangsan",["sex"]:"male",["age"]:19}'

购物车

# 用户id-key
# 商品id-field
# 商品数量-value
# 添加商品:

hmset MyCart:1001 40001 1 cost 5099 desc "笔记本电脑"
lpush MyItem:1001 40001
# 增加数量
hincrby MyCart:1001 40001 1
hincrby MyCart:1001 40001 -1
# 显示所有物品数量
hlen MyCart:1001
# 删除商品
hdel MyCart:1001 40001
lrem MyTtem:1001 1 40001
# 获取所有物品
lrange MyItem:1001
# 40001 40002 40003
heget MyCart:1001 40001
heget MyCart:1001 40002
heget MyCart:1001 40003

Lists (列表)

双向链表实现,列表首尾操作(增加和删除)时间复杂度为O(1);查找中间元素时间复杂度为O(n);列表中数据是否压缩的依据:

1.元素长度小于48,不压缩;

2.元素长度压缩前后长度不超过8,不压缩;

基础命令

字符串列表,按插入顺序排序,是双向链表实现。可作为栈、队列使用

分类命令描述数据结构类比
添加元素LPUSH key value将一个或多个值插入到列表头部(左边)左进
RPUSH key value将一个或多个值插入到列表尾部(右边)右进
移除元素LPOP key移除并获取列表的第一个元素(左边)左出
RPOP key移除并获取列表的最后一个元素(右边)右出
阻塞操作BLPOP key timeout移出并获取列表的第一个元素,如果列表没有元素会阻塞直到超时或有元素可用阻塞队列
BRPOP key timeout移出并获取列表的最后一个元素,阻塞版本阻塞队列
查询LRANGE key start stop获取列表指定范围内的元素(0 到 -1 表示所有)LRANGE mylist 0 -1
LLEN key获取列表长度LLEN mylist

存储结构

双向循环列表

应用

栈(先进后出FILO)

lpush + lpop
rpush + rpop

队列(先进先出FIFO)

lpush + rpop
rpush + lpop

阻塞队列(blocking queue)

lpush + brpop
rpush + blpop

异步消息队列

操作与队列一样,但是在不同系统间;生产者和消费者;


Sets (集合)

集合:用来存储唯一性字段,不要求有序;

存储不需要有序,操作(交并差集的时候)排序

基础命令

String 类型的无序集合元素唯一,不重复。适合存储唯一性数据和实现交集、并集等。

命令描述示例
SADD key member向集合添加一个或多个成员SADD tags redis db
SREM key member移除集合中一个或多个成员SREM tags db
SMEMBERS key获取集合中的所有成员SMEMBERS tags
SISMEMBER key member判断 member 元素是否是集合的成员SISMEMBER tags redis
SINTER key1 key2返回多个集合的交集SINTER group:A group:B
SUNION key1 key2返回多个集合的并集SUNION group:A group:B
SDIFF key1 key2返回第一个集合与其他集合之间的差集SDIFF group:A group:B
SCARD key获取集合的成员数SCARD tags

存储结构

元素都为整数且节点数量小于等于512(set-max-insert-entries),则使用整数数组存储;

元素当中有一个不是整数或者节点数量大于512,则使用字典存储;

应用

抽奖

# 添加抽奖用户
sadd Award:1 1001 1002 1003 1004 1005 1006
sadd Award:1 1008
# 查看所有抽奖用户
smembers Award:1
# 抽取多名幸运用户
srandmember Award:1 10

共同关注

sadd follow:A liubei sunquan caocao zhugeliang
sadd follow:B liubei zhugeliang 
sinter follow:A follow:B

推荐好友

sadd follow:A liubei sunquan caocao zhugeliang
sadd follow:B liubei zhugeliang 
# B可能认识的人:
sdiff follow:A follow:B

Sorted Sets (有序集合)

有序集合;用来实现排行榜;有序唯一;

基础命令

与 Set 类似,也是 String 类型元素的集合,且不允许重复成员。但每个元素都会关联一个 score(分数),用于按分数从小到大排序。非常适合排行榜、带优先级的队列。

命令描述示例
ZADD key score member向有序集合添加一个或多个成员,或更新其分数ZADD leaderboard 100 "Alice"
ZREM key member移除有序集合中的一个或多个成员ZREM leaderboard "Bob"
ZRANGE key start stop [WITHSCORES]按分数从低到高返回索引范围内的成员(WITHSCORES会同时返回分数)ZRANGE leaderboard 0 2 WITHSCORES
ZREVRANGE key start stop [WITHSCORES]按分数从高到低返回索引范围内的成员(用于查排行榜前N名)ZREVRANGE leaderboard 0 2
ZRANK key member返回成员在集合中的正序排名(从0开始)ZRANK leaderboard "Alice"
ZREVRANK key member返回成员在集合中的逆序排名ZREVRANK leaderboard "Alice"
ZSCORE key member返回成员的分数ZSCORE leaderboard "Alice"
ZCARD key获取有序集合的成员数ZCARD leaderboard

存储结构

节点数量大于128或者有一个字符串长度大于64,则使用跳表(skiplist);

节点数量小于等于128(zset-max-ziplist-entries)且所有字符串长度小于等于64(zset-max-ziplist-value),则使用ziplist存储;

数量少的时候,节省空间;O(n);

数量多的时候,访问性能;O(1) or O(logn);

应用

热榜

# 点击新闻:
zincrby hot:20250922 1 10001
zincrby hot:20250922 1 10002
zincrby hot:20250922 1 10003
zincrby hot:20250922 1 10004
zincrby hot:20250922 1 10005
zincrby hot:20250922 1 10006
zincrby hot:20250922 1 10007
zincrby hot:20250922 1 10008
zincrby hot:20250922 1 10009

#获取排行榜:
zrevrange hot:20250922 0 9 withscores

延时队列

将消息序列化成一个字符串作为zset的member;这个消息的到期处理时间作为score,然后用多个线程轮询zset获取到期的任务进行处理。

def delay(msg):
    msg.id= str(uuid.uuid4O) #保证member唯一
    value = json.dumps (msg)
    retry_ts=time.time()+5 # 5s后重试
    redis.zadd("delay-queue",retry_ts,value)

# 使用连接池
def loop ():
while True:
    values = redis.zrangebyscore("delay-queue",O, time.time(), start=O, num=1)
    if not values:
        time.sleep (1)
        continue
    value = values [O]
    success = redis.zrem("delay-queue", value)
    if success:
        msg = json.loads (value)
        handle_msg (msg)

#缺点:loop是多线程竞争,两个线程都从zrangebyscore获取到数据,但是zrem一个成功一个失败,
#优化:为了避免多余的操作,可以使用lua脚本原子执行这两个命令
# 解决:漏斗限流

分时式定时器

生产者将定时任务hash到不同的redis实体中,为每一个redis实体分配一个dispatcher进程,用来定时获取redis中超时事件并发布到不同的消费者中;

时间窗口限流

系统限定用户的某个行为在指定的时间范围内(动态)只能发生N次;

#指定用户user_id的某个行为action在特定时间内period只允许发生该行为做大次数max_count

local function is_action_allowed(red,userid,action,period,max_count)
    local key = tab_concat({"hist",userid,action},":")
    local now = zv.time()
    red:init_pipeline()
    -- 记录行为
    red:zadd(key,now,now)
    -- 移除时间窗口之前的行为记录,剩下的都是时问窗口内的记录
    red:zremrangebyscore(key,O,now - period *100)
    -- 获取时间窗口内的行为数量
    red:zcard(key)
    -- 设置过期时间,避免冷用户持续占用内存时间窗口的长度+1秒
    red:expire(key,period + 1)
    local res =red:commit_pipeline
    return res[3]< max_count
end

#维护一次时间窗口,将窗口外的记录全部清理掉,只保图窗口内的记录;
#缺点:记录了所有时间窗口内的数据,如果这个量很大,不适合做这样的限流;漏斗限流;
#注意:如果用key+expire操作也能实现,但是实现的是熔断限流,这里是时间窗口限流的功能;

通用键命令 (适用于所有类型)

命令描述
DEL key删除一个或多个key
EXISTS key检查某个key是否存在
EXPIRE key seconds为key设置过期时间(秒)
TTL key查看key剩余的生存时间(秒)
TYPE key返回key所存储的数据类型