Redis —— 基本知识大全,面试看这一篇就够了。

32 篇文章 1 订阅
26 篇文章 0 订阅

目录

基本介绍

Redis的适用场景

Redis的缺点

Redis支持五种数据类型

八种底层数据结构

遵守BSD协议

Redis相比memcached有哪些优势?

为什么Redis需要把所有数据放到内存中?

Redis是单进程单线程的

Redis的删除过期键

Redis有哪几种数据淘汰策略?

Redis的更新

缓存【失效】

缓存【命中】

缓存【更新】

为什么不采取更新后删除缓存?

为什么不删除缓存后再更新数据库?

Redis能否将数据持久化,如何实现?

RDB持久化原理Redis DataBase

AOF持久化原理Append-only file

Redis的三种集群方式:主从复制,哨兵模式和集群

主从复制

哨兵模式:

Redis-Cluster集群

RESP

缓存穿透

解决办法

缓存雪崩

解决办法

缓存击穿

解决办法


基本介绍

redis是一个基于内存的高性能key-value数据库,是非关系型数据库,适用于存储缓存用的数据,也适合需要高速读/写的场合使用它快速读/写。

Redis的适用场景

1)会话缓存(Session Cache)

2)全页缓存(FPC)

3)队列

4)排行榜/计数器

5)发布/订阅

Redis的缺点

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

Redis支持五种数据类型

StringString是最常用的一种数据类型,普通的kv存储都可以归为此类。
hash适合存储对象类型信息,例如个人信息、商品信息等。
list应用场景可以有微博的关注列表、粉丝列表、消息列表等。
setset表示存储的一个元素不重合的集合,适合做共同好友等功能
zset有序列表

八种底层数据结构

long类型的整数、整数集合 、embstr编码的简单动态字符串 、简单动态字符串 、双向链表 、压缩列表 、字典 (保存键值对的一种数据结构)、跳跃表+字典。

遵守BSD协议

允许使用者修改和重新发布代码,也允许使用或在BSD代码基础上开发商业软件发布和销售,因此是适用于商业软件的。使用者使用时还必须做到满足三个条件:

1)如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。

2)如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的BSD协议。

3)不可以用开源代码的作者/机构名字和原来产品的名字做市场推广。

Redis相比memcached有哪些优势?

1)memcached所有的值均是简单的字符串,redis支持更为丰富的数据类型

2)redis的速度比memcached快很多 

3)redis可以持久化其数据

4)存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。

为什么Redis需要把所有数据放到内存中?

  Redis为了达到最快的读写速度,所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。

Redis是单进程单线程的

  redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销

Redis的删除过期键

redis采用的是定期删除+惰性删除策略。

定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。

于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

Redis有哪几种数据淘汰策略?

当前已用内存超过最大值时,触发主动清理策略。

主动清理策略主要有一下六种:

volatile-lru从已设置过期的数据集中挑选最近最少使用的淘汰
volatile-ttl从已设置过期的数据集中挑选将要过期的数据淘汰
volatile-random从已设置过期的数据集中任意挑选数据淘汰
allkeys-lru从数据集中挑选最近最少使用的数据淘汰
allkeys-random从数据集中任意挑选数据淘汰
noenviction禁止淘汰数据

Redis的更新

缓存【失效】

客户端请求数据先从缓存中查询,如果没有再查询数据库,最后将数据放入缓存

缓存【命中】

客户端从缓存中直接取到数据,返回结果

缓存【更新】

客户端写入数据到数据库,成功之后,让缓存失效(下次请求时从缓存中拿不到,则查询数据库,再放入缓存)

为什么不采取更新后删除缓存?

防止并发写操作导致脏数据。

为什么不删除缓存后再更新数据库?

两个并发请求,一个读操作,一个写操作,如果先删除缓存,读操作会将【旧数据】写入缓存,写操作【更新数据】后也不会更新缓存,导致脏数据一直存在。

Redis能否将数据持久化,如何实现?

能,将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和AOF。

RDB持久化原理Redis DataBase

指定的时间间隔内保存数据快照。实际操作过程是fork一个子进程出来,子进程将数据写入临时的rdb快照文件中,完成rdb快照文件的生成之后,就替换之前的旧的快照文件。是周期性的持久化

优点:Redis加载RDB恢复数据远远快于AOF的方式。

缺点:由于每次生成RDB开销较大,非实时持久化,有可能会丢失数据

AOF持久化原理Append-only file

以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。Redis通过rewrite的机制,让AOF文件不至于太庞大。就是大概是数据量多的时候,重写一个新的,把不需要的剔除。

优点:实时持久化。

缺点:所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积,加载慢。

Redis的三种集群方式:主从复制,哨兵模式和集群

主从复制

Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC命令。Master服务主节点收到同步命令后将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave从节点服务在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。

哨兵模式:

使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控,在主节点出现故障的情况下,能将从节点中的一个升级为主节点,进行故障转义,保证系统的可用性。

监控: 哨兵通过gossip 协议会不断地检查你的Master和Slave是否运作正常;

提醒:当被监控的某个Redis节点出现问题时, 哨兵可以通过 API 向管理员或者其他应用程序发送通知;

自动故障迁移:当一个Master不能正常工作时,哨兵通过投票协议会开始一次自动故障迁移操作,它会将其他一个Slave升级为新的Master,当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用现在的Master替换失效Master。Master和Slave服务器切换后,Master的配置文件的内容都会发生相应的改变,即,Master主服务器的redis.conf配置文件中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。

Redis-Cluster集群

redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。

Redis-Cluster采用无中心结构,它的特点如下:

所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。

节点的fail是通过集群中超过半数的节点检测失效时才生效。

客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

工作方式:

在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

RESP

RESP 是redis客户端和服务端之前使用的一种通讯协议;

RESP 的特点:实现简单、快速解析、可读性好。

缓存穿透

是指查询一个数据库一定不存在的数据。

程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key获取为null,则会从DB中查询,并设置到缓存中去。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决办法

  1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  2. BloomFilter。将可能出现的缓存key的组合方式的所有数值以hash形式存储在一个很大的bitmap中<布隆过滤器>

  3. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

缓存雪崩

指的是大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

解决办法

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
  3. 设置热点数据永远不过期。

缓存击穿

指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。

解决办法

与缓存雪崩的解决方法类似: 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB写入缓存。 

  1. 设置热点数据永远不过期。

还有一种比较好用的(针对缓存雪崩与缓存击穿):

物理上的缓存是不设置超时时间的(或者超时时间比较长), 但是在缓存的对象上增加一个属性来标识超时时间(此时间相对小)。 当获取到数据后,校验数据内部的标记时间,判定是否快超时了,如果是,异步发起一个线程(控制好并发)去主动更新该缓存。这种方式会导致一定时间内,有些请求获取缓存会拿到过期的值,看业务是否能接受而定。

Redis为什么速度快

        1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

        2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

        3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

        4、使用多路I/O复用模型,非阻塞IO;

        多路 I/O 复用模型进行简单的探讨:

(1)多路 I/O 复用模型

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

**这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。**采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇宙超级无敌程序媛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值