Redis知识点总结

Redis知识点总结

0. 简单入门知识点

1.redis是key-value的数据结构
每条数据都是一个键值对
键的类型是字符串,并且不能重复
值的数据类型分为五种:stringhashlistsetzset

2.数据库没有名字,默认有16个库,通过0-15来标识连接redis数据库。默认选择第一个数据库,即0

1. 六大底层数据结构

可以使用OBJECT ENCODING key来查看某个数据类型的底层实现

1.1. SDS(simple dynamic string)简单动态字符串sdshdr

// 不以空字符’\0’作为字符串的结束标志
struct sdshdr{
    //等于 SDS 保存字符串的长度
    int len;
    //记录 buf 数组中未使用字节的数量
    int free;
    //字节数组,用于保存字符串
    char buf[];
}

SDS

1.2. 链表list

  1. 双端:链表具有前置节点和后置节点的引用
  2. 无环:表头节点的prev指针和表尾节点的next指针都指向NULL,对链表的访问都是以NULL结束;
  3. 带链表长度计数器:通过len属性获取链表长度的时间复杂度为O(1)
  4. 多态:链表节点使用void*指针来保存节点值,可以保存各种不同类型的值。

1.3. 哈希表dictht

typedef struct dictEntry{
    // 键
    void *key;
    // 值
    union{
        void *val;
        uint64_t u64;
        int64_t s64;
    }v;
    // 链地址法
    struct dictEntry *next;
}dictEntry

哈希算法如下:

// 1、使用字典设置的哈希函数,计算键 key 的哈希值
hash = dict->type->hashFunction(key);
// 2、使用哈希表的sizemask属性和第一步得到的哈希值,计算索引值
index = hash & dict->ht[x].sizemask;

1.4. 跳跃表zskiplist

跳跃表具有以下性质:

  1. 由很多层结构组成;
  2. 每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点;
  3. 最底层的链表包含了所有的元素;
  4. 如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);
  5. 链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;

跳跃表

1.5. 整数集合intset

typedef struct intset{
    //编码方式
    uint32_t encoding;
    //集合包含的元素数量
    uint32_t length;
    //保存元素的数组
    int8_t contents[];
}intset;

1.6. 压缩列表ziplist

压缩列表1

压缩列表的每个节点构成如下:
压缩列表2

previous_entry_length用于反向遍历
encoding保存的是节点的content的内容类型以及长度,encoding类型一共有两种,字节数组整数encoding区域长度为1字节2字节或者5字节

2. 五大数据类型的底层实现

stringhashlistsetzset

可以使用type key来查看对应value的类型

Redis中的每个对象都是由redisObject结构来表示
数据类型与底层实现

typedef struct redisObject{
    //类型(五大数据类型)
    unsigned type;
    //编码(底层实现的数据类型)
    unsigned encoding;
    //指向底层数据结构的指针
    void *ptr;
    //引用计数
    int refcount;
    //记录最后一次被程序访问的时间
    unsigned lru;
}robj

其中typeencoding的对应关系如下:

2.1. string的底层实现

字符串对象的编码可以是intraw或者embstr

  1. int编码:保存的是可以用long类型表示的整数值;
  2. raw编码:保存长度大于44字节的字符串(redis3.2版本之前是39字节,之后是44字节);
  3. embstr编码:保存长度小于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

raw编码

2.2. list的底层实现

当同时满足下面两个条件时,使用ziplist(压缩列表)编码:

  1. 列表保存元素个数小于512个;
  2. 每个元素长度小于64字节;
    不能满足这两个条件的时候使用linkedlist(双端链表)编码。
    上面两个条件可以在redis.conf配置文件中的list-max-ziplist-value选项和list-max-ziplist-entries选项进行配置。

2.3. hash的底层实现

哈希对象的编码可以是ziplist或者dictht,具体规则与list类似

2.4. set的底层实现

集合对象的编码可以是intset或者dictht

当集合同时满足以下两个条件时,使用intset编码:

  1. 集合对象中所有元素都是整数
  2. 集合对象所有元素数量不超过512
    不能满足这两个条件的就使用dictht编码。第二个条件可以通过配置文件的set-max-intset-entries进行配置。

2.5. zset的底层实现

有序集合的编码可以是ziplist或者skiplist

zset实现

一个zset结构同时包含一个字典和一个跳跃表,字典的键保存元素的值,字典的值则保存元素的分值;跳跃表节点的object属性保存元素的成员,跳跃表节点的score`属性保存元素的分值。这两种数据结构会通过指针来共享相同元素的成员和分值,所以不会产生重复成员和分值,造成内存的浪费。

当有序集合对象同时满足以下两个条件时,对象使用ziplist编码:

  1. 保存的元素数量小于128
  2. 保存的所有元素长度都小于64字节;
    不能满足上面两个条件的使用skiplist编码。以上两个条件也可以通过配置文件的zset-max-ziplist-entries选项和zset-max-ziplist-value进行修改

3. 持久化

3.1. RDB

优点:

  1. 直接二进制dump,文件紧凑,体积小;
  2. 恢复快;

缺点:

  1. 只能全量持久化,一次耗时较长;
  2. 二进制,基本没有可读性和可修改性。

3.2. AOF

优点:

  1. 记录所有更新日志,可读性和可修改性强;
  2. 支持持续无间断备份;

缺点:

  1. 文件体积大,恢复慢;
  2. 比较影响整体性能。

4. 缓存淘汰

当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap)。交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用。
在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数 maxmemory 来限制内存超出期望大小。
当实际内存超出 maxmemory 时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。

(volatile策略只会针对带过期时间的 key 进行淘汰,allkeys策略会对所有的 key 进行淘汰)
1.noeviction:不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
2.volatile-lru:尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
3.volatile-ttl:跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
4.volatile-random:跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
5.allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
6.allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。

5. 缓存穿透、缓存击穿、缓存雪崩

1.缓存穿透: 用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。一般通过布隆过滤器、缓存空对象来解决

2.缓存击穿:一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库。一般通过设置热点数据永远不过期、加互斥锁来解决

3.缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。一般通过过期时间设置随机、数据预热来解决

6.架构模式

  1. 单机版:①内存容量有限;②处理能力有限;③无法高可用。
  2. 主从复制:①降低master读压力在转交从库;②无法保证高可用;③没有解决master写的压力
  3. 哨兵:Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。①保证高可用;②主从模式,切换需要时间丢数据;③没有解决 master 写的压力
  4. 集群(proxy 型):增加了新的 proxy,需要维护其高可用。代表为Twemproxy、Codis
  5. 集群(直连型):增加了新的 proxy,需要维护其高可用。代表为Redis Cluster(redis3之后的官方方案)。分布算法使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽。采用客户端重定向的方式
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值