Redis基础总结

midoll 264 2022-05-31

数据结构

string

  • 字符串类型的内部编码有三种:
    1、int,存储8 个字节的长整型(long,2^63-1)。
    2、embstr, 代表embstr 格式的SDS(Simple Dynamic String 简单动态字符串),
    存储小于44 个字节的字符串。
    3、raw,存储大于44 个字节的字符串(3.2 版本之前是39 字节)

  • SDS 的特点:
    1、不用担心内存溢出问题,如果需要会对SDS 进行扩容。
    2、获取字符串长度时间复杂度为O(1),因为定义了len 属性。
    3、通过“空间预分配”( sdsMakeRoomFor)和“惰性空间释放”,防止多
    次重分配内存。
    4、判断是否结束的标志是len 属性(它同样以’\0’结尾是因为这样就可以使用C语言中函数库操作字符串的函数了),可以包含’\0’。

  • 应用场景
    缓存:热点数据
    数据共享:分布式session
    分布式锁:setnx
    全局id,计数器:int类型,incrby,原子性
    布隆过滤器

hash

clipboard(5)

  • Hash 不适合的场景:
    1、Field 不能单独设置过期时间
    2、没有bit 操作
    3、需要考虑数据量分布的问题(value 值非常大的时候,无法分布到多个节点)

  • 存储原理
    Redis 的Hash 本身也是一个KV 的结构,类似于Java 中的HashMap。
    外层的哈希(Redis KV 的实现)只用到了hashtable。当存储hash 数据类型时,
    我们把它叫做内层的哈希。内层的哈希底层可以使用两种数据结构实现:
    ziplist:OBJ_ENCODING_ZIPLIST(压缩列表)
    hashtable:OBJ_ENCODING_HT(哈希表)

  • ziplist 是一个经过特殊编码的双向链表,它不存储指向上一个链表节点和指向下一
    个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能,
    来换取高效的内存空间利用率,是一种时间换空间的思想。只用在字段个数少,字段值
    小的场景里面。

  • 问题:什么时候使用ziplist 存储?
    当hash 对象同时满足以下两个条件的时候,使用ziplist 编码:
    1)所有的键值对的健和值的字符串长度都小于等于64byte(一个英文字母
    一个字节);
    2)哈希对象保存的键值对数量小于512 个。

  • hashtable
    clipboard(6)

  • 为什么要定义两个哈希表呢?ht[2]
    redis 的hash 默认使用的是ht[0],ht[1]不会初始化和分配空间。
    哈希表dictht 是用链地址法来解决碰撞问题的。在这种情况下,哈希表的性能取决
    于它的大小(size 属性)和它所保存的节点的数量(used 属性)之间的比率:
     比率在1:1 时(一个哈希表ht 只存储一个节点entry),哈希表的性能最好;
     如果节点数量比哈希表的大小要大很多的话(这个比例用ratio 表示,5 表示平均
    一个ht 存储5 个entry),那么哈希表就会退化成多个链表,哈希表本身的性能优势就不再存在。
    在这种情况下需要扩容。Redis 里面的这种操作叫做rehash。

  • rehash 的步骤:
    1、为字符ht[1]哈希表分配空间,这个哈希表的空间大小取决于要执行的操作,以
    及ht[0]当前包含的键值对的数量。
    扩展:ht[1]的大小为第一个大于等于ht[0].used*2。
    2、将所有的ht[0]上的节点rehash 到ht[1]上,重新计算hash 值和索引,然后放
    入指定的位置。
    3、当ht[0]全部迁移到了ht[1]之后,释放ht[0]的空间,将ht[1]设置为ht[0]表,
    并创建新的ht[1],为下次rehash 做准备。
    这个有点像jmm里面的年轻代中的s0,s1

  • 应用场景
    存储对象类型的数据,比如一个对象或者一张表的数据

list

存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色
clipboard(4)

  • 存储原理
    早期ziplist,linkedlist;3.2 版本之后,统一用quicklist 来存储。quicklist 存储了一个双向链表,每个节点都是一个ziplist。
  • 应用场景
    用户消息时间线:有序的
    消息队列:List 提供了两个阻塞的弹出操作:BLPOP/BRPOP,可以设置超时时间
    队列:先进先出:rpush blpop,左头右尾,右边进入队列,左边出队列。
    栈:先进后出:rpush brpop

set

String 类型的无序集合,最大存储数量2^32-1(40 亿左右)。

  • 存储(实现)原理
    Redis 用intset 或hashtable 存储set。如果元素都是整数类型,就用inset 存储。
    如果不是整数类型,就用hashtable(数组+链表的存来储结构)。
    问题:KV 怎么存储set 的元素?key 就是元素的值,value 为null。
    如果元素个数超过512 个,也会用hashtable 存储。
  • 应用场景
    抽奖:随机获取元素
    是否点赞,打卡,签到:
    这条微博的ID 是t1001,用户ID 是u3001。
    用like:t1001 来维护t1001 这条微博的所有点赞用户。
    点赞了这条微博:sadd like:t1001 u3001
    取消点赞:srem like:t1001 u3001
    是否点赞:sismember like:t1001 u3001
    点赞的所有用户:smembers like:t1001
    点赞数:scard like:t1001
    比关系型数据库简单许多。

zset有序集合

sorted set,有序的set,每个元素有个score。
score 相同时,按照key 的ASCII 码排序。
clipboard(1)

  • 数据结构对比:
数据结构 是否允许重复元素 是否有序 有序实现方式
列表list 索引下标
集合set
有序集合zset 分值score
  • 存储(实现)原理
    同时满足以下条件时使用ziplist 编码:
     元素数量小于128 个
     所有member 的长度都小于64 字节

在ziplist 的内部,按照score 排序递增来存储。插入的时候要移动之后的数据。
超过阈值之后,使用skiplist+dict 存储。

  • 应用场景
    排行榜
    id 为6001 的新闻点击数加1:zincrby hotNews:20190926 1 n6001
    获取今天点击最多的15 条:zrevrange hotNews:20190926 0 15 withscores

BitMaps

Bitmaps 是在字符串类型上面定义的位操作。一个字节由8 个二进制位组成。
Hyperloglogs
Hyperloglogs:提供了一种不太准确的基数统计方法,比如统计网站的UV,存在
一定的误差

Streams

5.0 推出的数据类型。支持多播的可持久化的消息队列,用于实现发布订阅功能,借
鉴了kafka 的设计。

clipboard(2)


# redis