《剑指Java面试-Offer直通车》--Redis

目录

一、Redis简介

缓存中间件--Memcache和Redis的区别

为什么Redis这么快?

多路IO复用模型

FD

传统的阻塞I/O模型

多路复用函数

二、Redis常用数据类型

常用数据类型

底层实现

三、Redis数据过期策略、缓存雪崩、缓存穿透、缓存击穿

数据过期策略

如何解决 Redis 缓存雪崩问题

如何解决 Redis 缓存穿透问题

如何解决 Redis 缓存击穿问题

四、Redis和MySQL的双写一致性

五、从海量Key里查询出某一固定前缀的Key

六、如何实现分布式锁

分布式锁需要解决的问题

如何通过Redis实现分布式锁?

如何解决SETNX长期有效的问题?

七、如何使用Redis做异步队列?

使用List作为队列,rpush生产消息,lpop消费消息

BLPOP key [key...] timeout

pub/sub,主题订阅者模式

八、Redis如何做持久化?

1)基于BGSave的RDB快照持久化方式

RDB的创建与载入

触发rdb持久化的方式

BGSave的原理

RDB持久化的缺点

2)AOF增量持久化方式

Redis数据的恢复

RDB和AOF的优缺点?

3)RDB-AOF混合持久化方式

九、Redis高可用

1)主从同步

pipeline

Redis的同步机制

Redis Sentinel

2)Redis集群


一、Redis简介

MySQL的数据都是存放在磁盘中的,虽然在数据库层也做了对应的缓存,但这种数据库层次的缓存一般针对查询的内容,而且粒度也比较小。一般只有表中数据没有发生变动时,数据库对应的Cache才会发挥作用,这不能减少业务系统对数据库产生的增删改查的IO压力。因此缓存数据库应运而生,该技术实现了对热点数据的高速缓存,提高应用的响应速度,极大缓解后端数据库的压力。

缓存中间件--Memcache和Redis的区别

Memcache对数据类型的支持简单,只支持简单的key-value;不支持数据持久化存储(数据全部存在内存之中,一旦服务器宕机数据没办法保存);不支持主从;不支持分片。

Redis数据类型丰富;有部分数据存在硬盘上,这样能保证数据的持久性;支持主从;支持分片。redis目前官方只支持LINUX 上去行,从而省去了对于其它系统的支持,这样的话可以更好的把精力用于本系统 环境上的优化。底层模型上,新版本的redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

为什么Redis这么快?

100000+QPS(QPS即query per second,每秒内查询次数)

1)完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高。Redis是采用单进程单线程模型的K-V数据库,由c语言编写,将数据存储到内存中,读写数据的时候都不会受到硬盘IO速度的限制。

2)数据结构简单,对数据操作也简单。Redis不使用表,它的数据库不会预定义或者强制要求用户对Redis存储的不同数据进行关联,因此性能相比关系型数据库要高出不止一个量级,其存储结构就是键值对,类似于hashMap。hashMap的优势就是查找和操作的时间复杂度都是O(1)的。

3)采用单线程,单线程也能处理高并发请求,想多核也可启动多实例。在面对高并发的请求的时候,首先想要的是多线程来进行处理,将IO线程和业务线程分开,业务线程使用线程池来避免频繁创建线程和销毁线程,即便是一次请求,阻塞了也不会影响到其它请求。Redis单线程结构是指主线程是单线程的,主线程包含IO事件的处理,以及IO对应的相关请求的业务处理。此外,主线程还负责过期键的处理、复制协调、集群协调等等。这些除了IO事件之外的逻辑会被封装成周期性的任务,由主线程周期性的处理。因为采用单线程的设计,对于客户端的所有读写请求,都由一个主线程串行的处理,因此多个客户端同时对一个键进行写操作的时候,就不会有并发的问题,避免了频繁的上下文切换和锁竞争,使得Redis执行起来效率更高。单线程是可以处理高并发的请求的,并发不是并行,并行性意味着服务器能够同时执行几个事情,具有多个计算单元,而并发性IO流意味着能够让一个计算单元来处理来自多个客户端的流请求。Redis使用单线程配合上IO多路复用,可以大幅度的提升性能。CPU不是制约redis的性能瓶颈,此外,可以在多核的服务器中启动多个Redis实例来利用多核的特性。

注意,这里的单线程只是在处理我们的网络请求的时候,只有一个单线程来处理,一个正式的Redis server,在运行的时候,肯定不止一个线程的。例如Redis在进行持久化的时候,会根据实际情况,以子进程或者子线程的方式执行。

4)使用多路I/O复用模型,非阻塞IO。Redis是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或者输出都是阻塞的,所以IO操作在一般情况下,往往不能直接返回,就会导致某一文件的IO阻塞,进而导致整个进程无法对其它客户端提供服务。而IO多路复用就是为了解决这个问题而出现的。

多路IO复用模型

  • FD

File Descriptor,文件描述符。在操作系统中,一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射,在Linux内核中,该描述符称为文件描述符即File Descriptor,文件描述符用一个整数来表示。

  • 传统的阻塞I/O模型

当使用read或者write对某一个文件描述符FD进行读写的时候,如果当前的FD不可读或者不可写,整个Redis服务就不会对其它的操作做出响应,导致整个服务不可用,这也就是传统意义上的阻塞模型,阻塞模型会影响其它FD对应的服务,所以在需要处理多个客户端任务的时候,往往都不会使用阻塞模型。此时,需要一种更高效的I/O模型来支持Redis的高并发处理,就是I/O多路复用模型。

I/O多路复用模型,最重要的函数调用就是Select系统调用。Select可以同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时,Select方法就会返回可读以及可写的文件描述符个数,也就是说,Selector是负责监听我们的文件是否可读或者可写的,监听的任务交给Selector之后,程序就可以做其它的事情,而不被阻塞。

  • 多路复用函数

与此同时,也有其它的I/O多路复用函数,Redis采用的I/O多路复用函数:epoll、kqueue、evport、select。epoll、kqueue、evport相比select的性能更加优秀的,同时也可以支撑更多的服务。

Redis采用的多路复用函数是因地制宜的。Redis需要在多个平台下运行,为了最大化的提高执行效率和性能,会根据编译平台的不同选择不同的IO多路复用函数作为子模块,提供给上层统一的接口。

Redis优先选择时间复杂度为O(1)的IO多路复用函数作为底层实现。

以时间复杂度为O(n)的select作为保底。如果没有epoll、kqueue、evport,就会使用select,select在使用时会扫描全部的文件描述符,性能较差,时间复杂度是O(n)。

基于react设计模式监听I/O事件。Redis服务采用react设计模式来实现文件处理器。文件事件处理器使用I/O多路复用模块,同时监听多个FD,当accept、read、write等文件事件产生的时候,文件事件处理器就会回调FD绑定的事件处理器,虽然整个文件事件处理器是在单线程运行的,但是通过I/O多路复用模块的引用,实现了同时对多个FD读写的监控,提高了网络通信模型的性能,同时来保证了整个Redis服务实现的简单。

 

二、Redis常用数据类型

常用数据类型

String:最基本的数据类型,二进制安全,Redis的String可以包含任何数据,比如jpg图片或者序列化的图像。常用在缓存、计数、共享Session、限速等。

Hash:hash类型是一个string类型的field和value的映射表,每个 hash 可以存储 2^32 - 1 键值对(40多亿),hash类型的结构(key, field, value),适合用于存储对象。哈希可以用来存放用户信息,比如实现购物车。

List:列表,按照String元素插入顺序排序,是简单的字符串列表。类似栈,先进后出的顺序。可以做简单的消息队列的功能。

Set:集合,String元素组成的无序集合,通过哈希表实现,不允许重复。添加、删除、查找的复杂度是O(1)。提供了并集、交集、叉集操作。

Sorted Set:通过分数来为集合中的成员进行从小到大的排序。Redis的zset和set集合一样,也是String集合组成的集合,且不允许重复的成员,不同的是有序集合每个元素都会关联一个double类型的分数,redis正是通过这个分数,来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但是分数却可以重复。分数越小越靠前。可以做排行榜应用,取 TOP N 操作。

用于计数的HyperLoglog,用于支持存储地理位置信息的Geo等等。

底层实现

参考:Redis的五大数据类型的底层实现Redis数据结构底层实现

 

三、Redis数据过期策略、缓存雪崩、缓存穿透、缓存击穿

数据过期策略

Redis 中数据过期策略采用定期删除+惰性删除策略

1)定期删除策略:Redis 启用一个定时器定时监视所有的 key,判断key是否过期,过期的话就删除。这种策略可以保证过期的 key 最终都会被删除,但是也存在严重的缺点:每次都遍历内存中所有的数据,非常消耗 CPU 资源,并且当 key 已过期,但是定时器还处于未唤起状态,这段时间内 key 仍然可以用。

2)惰性删除策略:在获取 key 时,先判断 key 是否过期,如果过期则删除。这种方式存在一个缺点:如果这个 key 一直未被使用,那么它一直在内存中

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值