Redis 支持的五种存储数据的类型
字符串(String)类型
字符串是Redis支持的最简单的数据结构,内部就是一组字符数组,使用字符串存储数据结构的时候使用的是KV结构的存储方式
- Redis的字符串是内部使用的是动态字符串,内部结构类似与Java的ArrayList
- Redis的字符串空间分配采用预分配的冗余空间的方式,减少内存的频繁操作
- 使用的内存空间如果小于1MB,则扩容空间加倍
- 使用的空间大于1MB,则一次性多扩容1MB(最大长度512MB)
- 如果使用的value是一个整数,还可以对他使用incr进行自增操作,范围在signed long之间,超出报错
使用场景:可以使用redis中incr进行统计网页的PV:针对每个网页的地址为key,value进行页面的incr
列表(list)类型
Redis列表相当于Java中的LinkedList,所以是更新快,查询慢。在实际场景中Redis的列表结构尝尝用于作为异步队列来使用
- 使用rpush 和 rpop来对列表进行插入和读取操作
- lindex相当于Java中get(int index)方法,需要对列表进行遍历,随着index的增大效率变差
- ltrim 可以设置区间,保留start_index 和end_index之间的值,其余删除
内部原理:redis内部不是一个简单的linkedList,而是(quickList的结构)
- 在列表元素较少的时候,使用一个连续内存空间zipList
- 在列表元素较多的时候,考虑到链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率,便是用quicklist
字典(hash)类型
Redis的字典相当于Java中的HashMap,也是基于数组加链表的二维结构实现的
- Redis的字典值只能是字符串
- 在rehash的时候,为了不堵塞服务,会保留两个版本的hash结构(类似于Java的CopyOnWriteArraylist)
- 查询的时候会轮序的查询两个hash表结构
- 后期的定时任务中,循序渐进的将旧的hash迁移到新的上来
- hash结构中单个key也可以进行计数,使用hincrby 和incr的使用方法基本一样
集合(set)类型
Redis的集合相当于Java中的HashSet,它的内部键值对是无序,唯一的:
- 字典中所有的value都默认是一个NULL
- 当集合最后一个元素被移除之后,数据结构删除,内存收回
使用场景:
- 因为数据是唯一的,可以用来存储中奖用户的ID,防止重复中奖
- 可以使用统计UV,使用请求的用户ID为key(该场景适用于用户量不大的场景)
有序列表(zset)
Redis的zset 相当于Java中的SortedSet 和HashMap 的结合,一方面它是一个set,另一方面它为每个value赋了一个score的值,代表这个value的排序权重
- zset中可以用来存储学生成绩,value值是学生ID,score是考试成绩
通用规则
容器型数据结构(list,set,hash,zset)都共享一下两条规则
- 如果容器不存在,则使用例如rpush这种操作命令时,会直接创建
- 如果容器中没有数据了,则立即删除容器,释放内存空间
过期时间
- hash结构的过期是整个对象的过期时间,而不是某个key的过期时间
- 使用set命令的时候,会覆盖上一次的过期时间