目录
1. Redis的底层数据结构
Redis的底层数据结构一共有6种,分别为:简单动态字符串(SDS)、链表、字典、跳跃表、整数集合和压缩列表。
-
- 简单动态字符串(SDS):这是Redis自己编写的一个字符串,其结构包含一个len字段和一个buf字段,len记录了buf数组中已存储的字节长度,buf数组是一个char类型的数据,记录具体存储的字符串,并且以‘\0’(空字符)作为结束标识符。
- 链表list:Redis的链表是双向链表,每个节点有一个指向前一个和后一个节点的指针。双向链表的每一个节点都占用独立的一块内存,会导致内存碎片,且链表节点的前后指针会占用过多的额外内存,因此ziplist横空出世。
- 压缩列表ziplist:类似数组的紧凑型链表格式,会申请一整块内存,Redis的压缩列表是一种可以用于存储重复元素的、内存占用更少的数据结构。Redis的zset,hash,list都直接或者间接使用了ziplist,当zset/hash的元素的个数比较少的时候,且元素都是短字符串时,Redis便使用ziplist作为底层的数据存储结构,而list则使用的是quicklist数据结构存储
- quicklist=双向链表( LinkedList )+ziplist,将一个长ziplist拆分为多个短ziplist。避免插入或删除元素时导致大量的内存拷贝。
- 字典(散列表):Redis的字典是哈希表,其节点是哈希表的一个键值对。
- 跳跃表(skiplist):Redis的跳跃表是一种可以用于在一定范围内进行折半查找的数据结构。应用于zset
- 整数集合(intset):Redis的整数集合是一种可以用于存储整数并且可以进行数学运算的数据结构。应用于set都是整型并且不多时。
2. Redis的数据类型
Redis支持五种数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)及zset(sorted set:有序集合)。
- string(字符串)是Redis最基本的类型,可以理解成与Memcached一样的类型,一个key对应一个value。string类型是二进制安全的,意思是redis可以包含任何数据,比如jpg图片或者序列化的对象。string类型是Redis最基本的数据类型,一个键最大能存储512M。
String 的常见命令有:
SET:添加或者修改已经存在的一个 String 类型的键值对
GET:根据 key 获取 String 类型的 value
MSET:批量添加多个 String 类型的键值对
MGET:根据多个 key 获取多个 String 类型的 value
INCR:让一个整型的 key 自增 1
INCRBY:让一个整型的 key 自增并指定步长,例如:incrby num 2 让 num 值自增 2
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
SETNX:添加一个 String 类型的键值对,前提是这个 key 不存在,否则不执行
SETEX:添加一个 String 类型的键值对,并且指定有效期
- hash(哈希/散列)是键值对的集合,在Redis中,哈希是字符串字段和字符串值之间的映射,因此,它们适合表示对象。
Hash 的常见命令有:
HSET key field value:添加或者修改 hash 类型 key 的 field 的值
HGET key field:获取一个 hash 类型 key 的 field 的值
HMSET:批量添加多个 hash 类型 key 的 field 的值
HMGET:批量获取多个 hash 类型 key 的 field 的值
HGETALL:获取一个 hash 类型的 key 中的所有的 field 和 value
HKEYS:获取一个 hash 类型的 key 中的所有的 field
HVALS:获取一个 hash 类型的 key 中的所有的 value
HINCRBY:让一个 hash 类型的 key 的字段值自增并指定步长
HSETNX:添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执行
- list(列表)是Redis的一种双端队列结构,可以支持对数据的任意一端进行添加和删除操作。 常用来存储一个有序数据,例如:朋友圈点赞列表、用户的消息列表、网站的公告列表、活动列表、博客的文章列表、评论列表等,通过 LRANGE 取出一页,按顺序显示。 等。
List 的常见命令有:
LPUSH key element … :向列表左侧插入一个或多个元素
LPOP key:移除并返回列表左侧的第一个元素,没有则返回 nil
RPUSH key element … :向列表右侧插入一个或多个元素
RPOP key:移除并返回列表右侧的第一个元素
LRANGE key start end:返回一段角标范围内的所有元素
BLPOP 和 BRPOP:与 LPOP 和 RPOP 类似,只不过在没有元素时等待指定时间,而不是直接返回 nil
- set(集合)是一种无序的、不重复的数据集合,每个元素都会管理一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。抽奖 spop set,随机返回元素。点赞,签到,打卡。
我们以微博举例子,假设这条微博的ID是t1001,用户ID是u6001,
用dianzan:t1001来维护t1001这条微博的所有点赞用户。
点赞了这条微博:sadd dianzan:t1001 u6001
取消点赞:srem dianzan:t1001 u6001
是否点赞:sismember dianzan:t1001 u6001
点赞的所有用户:smembers dianzan:t1001
点赞数:scard dianzan:t1001
Set 常见命令:
SADD key member … :向 set 中添加一个或多个元素
SREM key member … :移除 set 中的指定元素
SCARD key … :返回 set 中元素的个数
SISMEMBER key member:判断一个元素是否存在于 set 中
SMEMBERS:获取 set 中的所有元素
SINTER key1 key2 … :求 key1 与 key2 的交集
SDIFF key1 key2 … :求 key1 与 key2 的差集
SUNION key1 key2 … :求 key1 与 key2 的并集
- zset(sorted set:有序集合)与set相似,也是一个无序的、不重复的数据集合。但不同的是,zset中的每个元素都有一个分数,redis通过分数来为zset中的成员进行从小到大的排序。实现方式是跳跃表或者压缩列表
热搜榜:
今天是2021年5月23号,建一个 key 为 hotSearch:20210523 的 zset。
放羊大叔这条新闻的id是n1234,每点击一下:zincrby hotSearch:20210523 1 n1234
获取热搜排行榜前十条:zrevrange hotSearch:20210523 0 10 withscores
SortedSet 类型的常见命令有:
ZADD key score member:添加一个或多个元素到 SortedSet,如果已经存在则更新其 score 值
ZREM key member:删除 SortedSet 中的一个指定元素
ZSCORE key member:获取 SortedSet 中的指定元素的 score 值
ZRANK key member:获取 SortedSet 中的指定元素的排名
ZCARD key:获取 SortedSet 中的元素个数
ZCOUNT key min max:统计 score 值在给定范围内的所有元素的个数
ZINCRBY key increment member:让 SortedSet 中的指定元素自增,步长为指定的 increment 值
ZRANGE key min max:按照 score 排序后,获取指定排名范围内的元素
ZRANGEBYSCORE key min max:按照 score 排序后,获取指定 score 范围内的元素
ZDIFF、ZINTER、ZUNION:求差集、交集、并集
- 地理空间Geospatial
- 基数统计HyperLogLogs
统计网站的UV,存在一定误差。
- 位图Bitmap
可以做用户连续登录
BITOP AND destkey key [key ...],对一个或多个key求逻辑并,并将结果保存到 destkey。
BITOP OR destkey key [key ...],对一个或多个key求逻辑或,并将结果保存到 destkey。
BITOP XOR destkey key [key ...],对一个或多个key求逻辑异或,并将结果保存到 destkey。
BITOP NOT destkey key,对给定key求逻辑非,并将结果保存到 destkey。
3. 数据的过期策略
redis数据过期策略-惰性删除
惰性删除:设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key
优点:对cpu友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查。
缺点:对内存不友好,如果一个key已经过期。但是一直没有使用,那么该key就会一直存在内存永远不会释放。
redis数据过期策略-定期删除
定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key).
定期清理有两种模式:
slow模式是定时任务,执行频率款认为10hz,每次不超过25ms,以通过修改配置文件redis.conf的nz选项来调
整这个次数
fast模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms
优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。
缺点:难以确定删除操作执行的时长和频率。
4. 数据的淘汰策略
数据的淘汰策略:当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。
Redis支持8种不同策略来选择要删除的key:
-
- noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。
- volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰
- allkeys-random:对全体key ,随机进行淘汰。
- volatile-random:对设置了TTL的key ,随机进行淘汰。
- allkeys-lru: 对全体key,基于LRU算法进行淘汰
- volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰
- allkeys-lfu: 对全体key,基于LFU算法进行淘汰
- volatile-lfu: 对设置了TTL的key,基于LFU算法进行淘汰
LRU(Least Recently Used)最近最少使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
LFU(Least Frequently Used)最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。
数据淘汰策略-使用建议
- 优先使用 allkeys-lru 策略。充分利用 LRU 算法的优势,把最近最常访问的数据留在缓存中。如果业务有明显的冷热数据区分,建议使用。
- 如果业务中数据访问频率差别不大,没有明显冷热数据区分,建议使用 allkeys-random,随机选择淘汰。
- 如果业务中有置顶的需求,可以使用 volatile-lru 策略,同时置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他设置过期时间的数据。
- 如果业务中有短时高频访问的数据,可以使用 allkeys-lfu 或 volatile-lfu 策略。