Redis的数据类型和底层数据结构
Redis的数据类型
Redis的String能表达3种值的类型:字符串、整数、浮点数
常见操作命令如下表:
命令名称 | 命令格式 | 命令描述 |
---|---|---|
set | set key value | 赋值 |
get | get key | 取值 |
getset | getset key value | 取值并赋值 |
setnx | setnx key value | 当value不存在时采用赋值set key value NX PX 3000 原子操作,px 设置毫秒数 |
append | append key value | 向尾部追加值 |
strlen | strlen key | 获取字符串长度 |
incr | incr key | 递增数字 |
incrby | incrby key increment | 增加指定的整数 |
decr | decr key | 递减数字 |
decrby | decrby key decrement | 减少指定的整数 |
应用场景: 1、key和命令是字符串 2、普通的赋值 3、incr用于乐观锁 incr:递增数字,可用于实现乐观锁 watch(事务) 4、setnx用于分布式锁 当value不存在时采用赋值,可用于实现分布式锁
list列表类型
list列表类型可以存储有序、可重复的元素 获取头部或尾部附近的记录是极快的 list的元素个数最多为2^32-1个(40亿) 常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
lpush | lpush key v1 v2 v3 ... | 从左侧插入列表 |
lpop | lpop key | 从列表左侧取出 |
rpush | rpush key v1 v2 v3 ... | 从右侧插入列表 |
rpop | rpop key | 从列表右侧取出 |
lpushx | lpushx key value | 将值插入到列表头部 |
rpushx | rpushx key value | 将值插入到列表尾部 |
blpop | blpop key timeout | 从列表左侧取出,当列表为空时阻塞,可以设置最大阻塞时 间,单位为秒 |
brpop | blpop key timeout | 从列表右侧取出,当列表为空时阻塞,可以设置最大阻塞时 间,单位为秒 |
llen | llen key | 获得列表中元素个数 |
lindex | lindex key index | 获得列表中下标为index的元素 index从0开始 |
lrange | lrange key start end | 返回列表中指定区间的元素,区间通过start和end指定 |
lrem | lrem key count value | 删除列表中与value相等的元素 当count>0时, lrem会从列表左边开始删除;当count<0时, lrem会从列表后边开始删除;当count=0时, lrem删除所有 值为value的元素 |
lset | lset key index value | 将列表index位置的元素设置成value的值 |
ltrim | ltrim key start end | 对列表进行修剪,只保留start到end区间 |
rpoplpush | rpoplpush key1 key2 | 从key1列表右侧弹出并插入到key2列表左侧 |
brpoplpush | brpoplpush key1 key2 | 从key1列表右侧弹出并插入到key2列表左侧,会阻塞 |
linsert | linsert key BEFORE/AFTER pivot value | 将value插入到列表,且位于值pivot之前或之后 |
应用场景: 1、作为栈或队列使用 列表有序可以作为栈和队列使用 2、可用于各种列表,比如用户列表、商品列表、评论列表等。
set集合类型
Set:无序、唯一元素 集合中最大的成员数为 2^32 - 1 常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
sadd | sadd key mem1 mem2 .... | 为集合添加新成员 |
srem | srem key mem1 mem2 .... | 删除集合中指定成员 |
smembers | smembers key | 获得集合中所有元素 |
spop | spop key | 返回集合中一个随机元素,并将该元素删除 |
srandmember | srandmember key | 返回集合中一个随机元素,不会删除该元素 |
scard | scard key | 获得集合中元素的数量 |
sismember | sismember key member | 判断元素是否在集合内 |
sinter | sinter key1 key2 key3 | 求多集合的交集 |
sdiff | sdiff key1 key2 key3 | 求多集合的差集 |
sunion | sunion key1 key2 key3 | 求多集合的并集 |
应用场景: 适用于不能重复的且不需要顺序的数据结构 比如:关注的用户,还可以通过spop进行随机抽奖
sortedset有序集合类型
SortedSet(ZSet) 有序集合: 元素本身是无序不重复的 每个元素关联一个分数(score) 可按分数排序,分数可重复 常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
zadd | zadd key score1 member1 score2 member2 ... | 为有序集合添加新成员 |
zrem | zrem key mem1 mem2 .... | 删除有序集合中指定成员 |
zcard | zcard key | 获得有序集合中的元素数量 |
zcount | zcount key min max | 返回集合中score值在[min,max]区间 的元素数量 |
zincrby | zincrby key increment member | 在集合的member分值上加increment |
zscore | zscore key member | 获得集合中member的分值 |
zrank | zrank key member | 获得集合中member的排名(按分值从 小到大) |
zrevrank | zrevrank key member | 获得集合中member的排名(按分值从 大到小) |
zrange | zrange key start end | 获得集合中指定区间成员,按分数递增 排序 |
zrevrange | zrevrange key start end | 获得集合中指定区间成员,按分数递减 排序 |
应用场景: 由于可以按照分值排序,所以适用于各种排行榜。比如:点击排行榜、销量排行榜、关注排行榜等。
hash类型(散列表)
Redis hash 是一个 string 类型的 field 和 value 的映射表,它提供了字段和字段值的映射。 每个 hash 可以存储 2^32 - 1 键值对(40多亿)。
常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
hset | hset key field value | 赋值,不区别新增或修改 |
hmset | hmset key field1 value1 field2 value2 | 批量赋值 |
hsetnx | hsetnx key field value | 赋值,如果filed存在则不操作 |
hexists | hexists key filed | 查看某个field是否存在 |
hget | hget key field | 获取一个字段值 |
hmget | hmget key field1 field2 ... | 获取多个字段值 |
hgetall | hgetall key | |
hdel | hdel key field1 field2... | 删除指定字段 |
hincrby | hincrby key field increment | 指定字段自增increment |
hlen | hlen key | 获得字段数量 |
应用场景: 对象的存储 ,表数据的映射
bitmap位图类型
bitmap是进行位操作的 通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。 bitmap本身会极大的节省储存空间。 常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
setbit | setbit key offset value | 设置key在offset处的bit值(只能是0或者 1)。 |
getbit | getbit key offset | 获得key在offset处的bit值 |
bitcount | bitcount key | 获得key的bit位为1的个数 |
bitpos | bitpos key value | 返回第一个被设置为bit值的索引值 |
bitop | bitop and[or/xor/not] destkey key [key …] | 对多个key 进行逻辑运算后存入destkey 中 |
应用场景: 1、用户每月签到,用户id为key , 日期作为偏移量 1表示签到
2、统计活跃用户, 日期为key,用户id为偏移量 1表示活跃
3、查询用户在线状态, 日期为key,用户id为偏移量 1表示在线
geo地理位置类型
geo是Redis用来处理位置信息的。在Redis3.2中正式使用。主要是利用了Z阶曲线、Base32编码和 geohash算法
常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
geoadd | geoadd key 经度 纬度 成员名称1 经度1 纬度1 成 员名称2 经度2 纬度 2 ... | 添加地理坐标 |
geohash | geohash key 成员名称1 成员名称2... | 返回标准的 geohash串 |
geopos | geopos key 成员名称1 成员名称2... | 返回成员经纬度 |
geodist | geodist key 成员1 成员2 单位 | 计算成员间距离 |
georadiusbymember | georadiusbymember key 成员 值单位 count 数 asc[desc] | 根据成员查找附近的成员 |
应用场景: 1、记录地理位置 2、计算距离 3、查找"附近的人"
stream数据流类型
stream是Redis5.0后新增的数据结构,用于可持久化的消息队列。 几乎满足了消息队列具备的全部内容,包括:
-
消息ID的序列化生成
-
消息遍历
-
消息的阻塞和非阻塞读取
-
消息的分组消费
-
未完成消息的处理
-
消息队列监控
每个Stream都有唯一的名称,它就是Redis的key,首次使用 xadd 指令追加消息时自动创建。 常见操作命令如下表:
命令名称 | 命令格式 | 描述 |
---|---|---|
xadd | xadd key id <*> field1 value1.... | 将指定消息数据追加到指定队列(key)中,表示最新生成的id(当前时间+序列号) |
xread | xread [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...] | 从消息队列中读取,COUNT:读取条数, BLOCK:阻塞读(默认不阻塞)key:队列 名称 id:消息id |
xrange | xrange key start end [COUNT] | 读取队列中给定ID范围的消息 COUNT:返 回消息条数(消息id从小到大) |
xrevrange | xrevrange key start end [COUNT] | 读取队列中给定ID范围的消息 COUNT:返 回消息条数(消息id从大到小) |
xdel | xdel key id | 删除队列的消息 |
xgroup | xgroup create key groupname id | 创建一个新的消费组 |
xgroup | xgroup destory key groupname | 删除指定消费组 |
xgroup | xgroup delconsumer key groupname cname | 删除指定消费组中的某个消费者 |
xgroup | xgroup setid key id | 修改指定消息的最大id |
xreadgroup | xreadgroup group groupname consumer COUNT streams key | 从队列中的消费组中创建消费者并消费数据 (consumer不存在则创建) |
应用场景:
消息队列的使用
底层数据结构
redis的所有数据类型底层存储都是以一种统一的格式(RedisObject结构)进行存储。
结构信息:
typedef struct redisObject {
unsigned type:4;//类型 五种对象类型
unsigned encoding:4;//编码
void *ptr;//指向底层实现数据结构的指针
//...
int refcount;//引用计数
//...
unsigned lru:LRU_BITS; //LRU_BITS为24bit 记录最后一次被命令程序访问的时间
//...
}robj;
4位type
type 字段表示对象的类型,占 4 位; REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有 序集合)。 当我们执行 type 命令时,便是通过读取 RedisObject 的 type 字段获得对象的类型。
4位encoding
encoding 表示对象的内部编码,占 4 位 每个对象有不同的实现编码 Redis 可以根据不同的使用场景来为对象设置不同的编码,大大提高了 Redis 的灵活性和效率。 通过 object encoding 命令,可以查看对象采用的编码方式
24位LRU
lru 记录的是对象最后一次被命令程序访问的时间,( 4.0 版本占 24 位,2.6 版本占 22 位)。 高16位存储一个分钟数级别的时间戳,低8位存储访问计数(lfu : 最近访问次数) lru----> 高16位: 最后被访问的时间 lfu----->低8位:最近访问次数
refcount
refcount 记录的是该对象被引用的次数,类型为整型。 refcount 的作用,主要在于对象的引用计数和内存回收。 当对象的refcount>1时,称为共享对象 Redis 为了节省内存,当有一些对象重复出现时,新的程序不会创建新的对象,而是仍然使用原来的对 象。
ptr
ptr 指针指向具体的数据,比如:set hello world,ptr 指向包含字符串 world 的 SDS