目录
个人主页: 【⭐️个人主页】
需要您的【💖 点赞+关注】支持 💯
Redis系列-Redis数据类型【3】
字符串类型(String)
string
是 redis 最基本的类型
,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
应用场景:共享session、分布式锁,计数器、限流。
内部编码有3种,int
(8字节长整型)/embstr
(小于等于39字节字符串)/raw
(大于39个字节字符串)
命令列表
📌 set | get | mget | getrange | getset | getbit| setbit | setnx | setex | strlen | setrange| mset | msetnx | psetex | incr | incrby | decr | decrby | append
SDS (simple dynamic string)
Redis使用SDS(simple dynamic string) 封装,sds源码如下:
struct sdshdr{
unsigned int len; // 标记buf的长度
unsigned int free; //标记buf中未使用的元素个数
char buf[]; // 存放元素的坑
}
SDS 结构图如下:
Redis为什么选择SDS结构,而C语言原生的char[]
不香吗?
举例其中一点,SDS中,O(1)时间复杂度,就可以获取字符串长度;而C 字符串,需要遍历整个字符串,时间复杂度为O(n)
哈希类型(Hash)
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
每个 hash 可以存储 2^32 -1
键值对(40多亿)。
内部编码:ziplist
(压缩列表) 、hashtable
(哈希表)
应用场景:缓存用户信息等。
⚠️ hset | hmset | hdel | hmset | hexists | hget | hgetall | hincrby | hincrbyfloat | hkeys | hvals | hlen | hmget| hsetnx | hscan
列表类型(List)
Redis 列表是简单的字符串
列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
列表最多可存储 2^32 - 1 元素 (4294967295, 每个列表可存储40多亿)。
特点: 有序,不唯一性,
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
Redis3.2之前内部编码:ziplist(压缩列表)、linkedlist(链表)
ziplist是一种压缩链表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。当列表对象元素不大,每个元素也不大的时候,就采用ziplist存储。但当数据量过大时就ziplist就不是那么好用了。因为为了保证他存储内容在内存中的连续性,插入的复杂度是O(N),即每次插入都会重新进行realloc。如下图所示,redisObject对象结构中ptr所指向的就是一个ziplist。整个ziplist只需要malloc一次,它们在内存中是一块连续的区域。
结构
1、zlbytes:用于记录整个压缩列表占用的内存字节数
2、zltail:记录要列表尾节点距离压缩列表的起始地址有多少字节
3、zllen:记录了压缩列表包含的节点数量。
4、entryX:要说列表包含的各个节点
5、zlend:用于标记压缩列表的末端
Redis3.2及之后的底层实现方式:quicklist
快速列表是ziplist和linkedlist的混合体,是将linkedlist按段切分,每一段用ziplist来紧凑存储,多个ziplist之间使用双向指针链接。
应用场景:消息队列,文章列表,
lset | lpush | lpushx | rpush | linsert | lpop | rpop | llen | lindex | lrange | lrem | ltrim | rpushx | rpoplpush | brpoplpush | blpop | brpop
集合类型(Set)
Redis 的 Set
是 string
类型的无序
集合。
集合是通过哈希表
实现的,所以添加,删除,查找的复杂度都是 O(1)。
sadd 命令: 添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
注意 : 根据集合内元素的唯一性,第二次插入的元素将被忽略。
特点:无序
,唯一性
集合中最大的成员数为 2^32 - 1(4294967295, 每个集合可存储40多亿个成员)。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
。
内部编码:intset
(整数集合)、hashtable
(哈希表)
当存储的数据同时满足下面这样两个条件的时候,Redis 就采用整数集合intset来实现set这种数据类型:
- 存储的数据都是整数
- 存储的数据元素个数小于512个
intset 结构
intset是一个有序集合,查找元素的复杂度为O(logN)(采用二分法),但插入时不一定为O(logN),因为有可能涉及到升级操作。比如当集合里全是int16_t型的整数,这时要插入一个int32_t,那么为了维持集合中数据类型的一致,那么所有的数据都会被转换成int32_t类型,涉及到内存的重新分配,这时插入的复杂度就为O(N)了。是intset不支持降级操作。
inset是有序不要和我们zset搞混,zset是设置一个score来进行排序,而inset这里只是单纯的对整数进行升序而已
注意点:smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,可以使用sscan来完成。
应用场景:用户标签,生成随机数抽奖、社交需求。
sadd | scard 个数 | smembers | srem | sinter | sdiff | sunion | sinterstore | sdiffstore | sunionstore | spop | srandmember | smove | sismemeber |
有序集合类型(ZSet)
Redis zset
和 set 一样也是string
类型元素的集合,且不允许重复
的成员。
不同的是每个元素都会关联一个double类型
的分数
。redis正是通过分数来为集合中的成员进行从小到大
的排序。
zset的成员是唯一的,但分数(score)却可以重复。
底层内部编码:ziplist
(压缩列表)、skiplist
(跳跃表)
应用场景:排行榜,社交需求(如用户点赞)。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
。
集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。
zadd airline 1 飞机1号 2 飞机2号 3 飞机三号 5 飞机五号 6 飞机6号 4 飞机4号
zscore
zcard airline # 个数
zcount airline 1 3
zrem
zrange airline 0 100
zrevrange
zrank
zincrby
zlexcount
zinterstore
zunionstore
zpopmin
zpopmax
zrevrank
zrangebyscore
zrangebylex
zremrangebyscore
zremrangebyrank
zremrangebylex
zrevrangebyscore airline 100 0 # 按倒排
zlexcount chars [c [b
字符串类型(String)的特殊形式
geospatial(地理位置)
Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。
Redis GEO 操作方法有:
- geoadd:添加地理位置的坐标。
- geopos:获取地理位置的坐标。
- geodist:计算两个位置之间的距离。
- georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
- geohash:返回一个或多个位置对象的 geohash 值。
Hyperloglog(基数)
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
应用场景
查看附近的人
微信位置共享
地图上直线距离的展示
应用场景
网页统计UV (浏览用户数量,同一天同一个ip多次访问算一次访问,目的是计数,而不是保存用户)
传统的方式,set保存用户的id,可以统计set中元素数量作为标准判断。
但如果这种方式保存大量用户id,会占用大量内存,我们的目的是为了计数,而不是去保存id。
pfadd | pfcount | pfmerge
Bitmaps(位存储)
Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。
可以把Bitmaps想象成一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在bitmaps中叫做偏移量。单个bitmaps的最大长度是512MB,即2^32个比特位。
应用场景
两种状态的统计都可以使用bitmaps,例如:统计用户活跃与非活跃数量、登录与非登录、上班打卡等等。
参考学习:
https://www.zhihu.com/tardis/bd/art/487583440?source_id=1001