一:前言
redis中有几种常用的基础对象,如string、hash、list、set、zset等,下面我们就来介绍下他们的底层实现数据结构与常见应用场景和特点。
二:redisobject
源码位置位于server.h文件中605行开始
typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; int refcount; void *ptr; } robj;
2.1 type
redis中实际的对象类型,分为5种0-4声明。位于文件server.h中466行
#define OBJ_STRING 0 /* String object. */ #define OBJ_LIST 1 /* List object. */ #define OBJ_SET 2 /* Set object. */ #define OBJ_ZSET 3 /* Sorted set object. */ #define OBJ_HASH 4 /* Hash object. */
2.2 encoding
redis五种对象string、list、hash、set、zset会用到的八种编码格式,每一种编码都对应一个数据结构
#define OBJ_ENCODING_RAW 0 #define OBJ_ENCODING_INT 1 #define OBJ_ENCODING_HT 2 #define OBJ_ENCODING_ZIPLIST 5 #define OBJ_ENCODING_INTSET 6 #define OBJ_ENCODING_SKIPLIST 7 #define OBJ_ENCODING_EMBSTR 8 #define OBJ_ENCODING_QUICKLIST 9
2.3 refcount
redis中内存的回收采用了比较简单的引用计数法进行,每个对象引用就refcount + 1,当这个引用计数减少为0时内存就会被回收
三:string
3.1 常用场景
分布式锁:分布式锁的实现基础就是采用string的命令setnx用户信息:很多时候用户信息都会序列化后存到redis中缓存,但是这里可以考虑下hash。如果仅仅使用用户数据部分信息,毕竟序列化与反序列化也是一笔开销
3.2 编码格式
int:当字符串中全是数字时会采用int编码,这是真正的二进制数据存储embstr:内存地址连续,内存一次申请。字符串长度小于44raw:底层采用sds实现,相对于embstr差别在于sds的创建与redisobject的创建分两次实现
3.3 常用命令
# 存储 set key value # 互斥存储 # 已存在的key再次存入数据不会更改缓存 setnx key value # 过期存储,单位秒 # 设定key过期时间,到期自动删除 setex key seconds value # 过期存储,单位毫秒 psetex key milliseconds value # 批量存储 mset key value [key value ...] # 取值 get key # 批量取值 mget key [key ...] # 追加 append key value # 长度 strlen key # 自增,只能是int编码的字符串 incr key # 自定义步长自增 incrby key increment # 自减,只能是int编码的字符串 # 这个可以减到负数,秒杀扣减库存啥的想想能不能用这个命令 decr key # 自定义步长自减 decrby key increment
四:list
4.1 常用场景
消息队列:一般不怎么用,毕竟各种MQ、Kafka都已经很成熟了。而且redis实现消息队列并不保证数据的安全排行榜计算:这种仅仅适用于定时计算更新,不能用于实时更新排行。比如美团每天计算区域入驻商家排行点赞列表:比如微信中的点赞(不知道咋做的,猜一下)
4.2 编码格式
quicklist:快速列表,之前版本有使用linkedlist和ziplist。目前使用的quicklist为两者结合体,详情可以查看Redis(一) -- 浅谈Redis中的数据结构
4.3 相关参数配置
配置参数位置位于redis.con文件中1083行和1099行
list-max-ziplist-size:配置单个ziplist大小list-compress-depth:配置LZF压缩算法开始节点
4.4 常用命令
# 创建list并压入节点 # 压入节点位于链表头 lpush key value # 压入节点位于链表尾 rpush key value # 弹出list头节点 lpop key # 弹出list尾节点 rpop key # 删除节点 # count > 0 从左开始搜索删除count数量的value # count < 0 从右开始搜索删除|count|数量的value # count = 0 删除list中所有value lrem key count value # 范围保留 # -1 表示列表最后一个元素 # -2 表示倒数第二个,以此类推 ltrim key start stop # 计算长度 llen key # 索引查询节点 # index < 0 从右开始搜索 # index > 0 从左开始搜索 lindex key index # 范围查询 # stop = -1 表示所有 lrange key start stop # 阻塞弹出 # 队列中没有节点时会一直等待 # 多个key时表示挨着顺序依次检查,知道找到非空列表为止 # timeout可以设置等待时间,0表示一直等待 blpop key [key...] timeout brpop key [key...] timeout
五:Hash
5.1 常用场景
商品对象、用户对象。这个场景需要验证性对待,如果商品对象、用户对象信息每次都需要全量的话不妨存string,但是仅仅部分使用就可以考虑使用hash结构SKU等信息,这个场景下hash就比较合适了。一个hash结构中存储某个商品所有sku
5.2 编码格式
ziplist:使用ziplist存储hash结构时一个数据会使用相邻两个ziplistEntry存储field和valuehashtable:当数据存储超过参数限制后就会将其底层结构由ziplist转换为dict进行存储
5.3 相关参数配置
hash-max-ziplist-entries:默认512,即ziplist节点为1024。当节点数量超过该值限制后底层数据结构转为dicthash-max-ziplist-value:默认64,当hash中插入任意一个长度超过该限制的value后底层数据结构转换为dict
(学习视频分享:redis视频教程)
5.4 常用命令
# 存储 hset key field value # 不允许更改存储 # 若field值存在则本次存储不会覆盖原有value值 hsetnx key field value # 批量存储 hmset key field value [field value ...] # 查询 hget key field # 批量查询 hmget key field [field ...] # 全量查询 hgetall key # 全量查询field值 hkeys key # 全量查询value值 hvals key # 删除field hdel key field [field ...] # 计算键值对数量 hlen key # field存在判断 hexists key field # 增量式迭代 # cursor表示迭代开始的游标 # count 表示迭代返回数据数量 # pattern 表示正则匹配结果限制 hscan key cursor [Count count] [Match pattern]
六:Set
6.1 常用场景
推荐:通过sinter命令计算交集,比如美团给你推荐附近外卖时就可以根据你的外卖记录与附近商家计算交集推送安全提示:微信群成员保存在一个set中,用户好友也保存在set中。当用户加入群聊时可以提醒非好友用户注意安全
6.2 编码格式
intset:整数集合,用于存储set集合中所有value都是整数的数据hashtable:field用于存储set集合值
6.3 相关参数配置
set-max-inset-entries:默认512,表示当元素数量超过限定以后转换为hashtable编码
6.4 常用命令
# 存储 sadd member [member ...] # 弹出元素并返回 spop key count # 查询所有元素 smembers key [count] # 计算元素数量 scard key # 删除指定元素 srem key member [member ...] # 判断元素存在 sismember key member # 计算给定集合与后续集合差集 # 返回计算结果 sdiff key [key ...] # 计算给定集合与后续集合差集 # 存储结果到destination并返回 sdiffstore destination key [key ...] # 计算给定集合与后续集合交集 # 返回计算结果 sinter key [key ...] # 计算给定集合与后续集合差集 # 存储结果到destination并返回 sinterstore destination key [key ...] # 计算给定集合与后续集合差集 # 返回计算结果 sunion key [key ...] # 计算给定集合与后续集合差集 # 存储结果到destination并返回 sunionstore destination key [key ...]
七:Zset
7.1 常用场景
排行榜:美团要做一个销量排行榜,就可以使用店家的订单做score,这个查询出来的结果就是有序的权重队列:score作为优先级,这样取出来的数据权重都是最大优先执行的延时任务:score作为任务启动执行时间,取值时判断该值执行即可
7.2 编码格式
ziplist:与hash有异曲同工之妙,都是使用相邻两个节点存储score和memberskiplist:跳跃表结构,可以查看Redis(一) -- 浅谈Redis中的数据结构
7.3 相关参数配置
zset-max-ziplist-entries:默认值128,指定ziplist存储元素最多128个。超过转换为skiplistzset-max-ziplist-value:默认值64,存储数据值最大64字节,超过转换为skiplist
7.4 常用命令
# 存储 # xx 表示当zset中存在本次插入的member时才存储 # nx 表示当zset中不存在本次插入的member时才存储 zadd key [nx|xx] score member [score member ...] # 查询排序指定[start,stop]范围内元素 # withscores 查询结果顺带返回元素分数 zrange key start stop [withscores] # 查询指定元素分数 zscore key member # 元素数量统计 zcard key # 返回score位于[min,max]区间的元素数量 zcount key min max # 对指定元素分数增加incrment值 zincrby key incrment member # 返回指定分数区间范围内元素 # withscores 返回时携带分数一起返回 # limit offset count表示跳过offset数量结果再返回count数量结果 zrangebyscore key min max [withscores] [limit offset count] # 倒序返回指定分数区间范围内元素 # withscores 返回时携带分数一起返回 # limit offset count表示跳过offset数量结果再返回count数量结果 zrevrangebyscore key max min [withrescores] [limit offset count] # 删除指定分数范围[min,max]内元素 zremrangebyscore key min max # 移除指定元素 zrem key member