整合多篇博客,为了面试而生! 奥利给~~~
redis是单线程

持久化方式两种:
RDB AOF

RDB:是一次内存数据的全量备份,周期性的将当前内存数据写入到一个快照文件中。

redis使用操作系统的多进程COW机制(Copy On Write)机制来实现快照的持久化,在持久化过程中调用 glibc(Linux下的C函数库) 的函数fork()产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端的读写请求。子进程对当前内存中的数据进行持久化过程中,并不会修改当前的数据结构,如果父进程收到了读写请求,那么会把处理的那一部分数据复制一份到内存,在内存中对复制后的数据进行修改,所以即使对某个数据进行了修改,redis持久化到RDB中的数据也是未修改的数据,这也是把RDB文件称为"快照"文件的原因,子进程所看到的数据在它被创建的一瞬间就固定下来了,父进程修改的某个数据只是该数据在内存的复制品。
RDB有三种触发机制
1、save触发方式
2、bgsave触发方式
3、自动触发
redis重点

优点:
RDB产生的快照文件对应某个时刻redis中的所有数据,可以保存到其他存储介质,容灾性好;
使用RDB持久化时,对主进程处理读写请求的影响非常小,它是forke产生子进程去执行IO操作来进行RDB持久化;
RDB恢复速度比AOF快,因为RDB中存放的就是数据,直接加载到内存即可,AOF日志还需要去执行执行来恢复。
缺点:
redis故障时,会丢失较多数据,这点不如AOF日志;
RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,甚至数秒;
在持久化期间,对数据进行修改操作,不会体现在快照文件中。


AOF:AOF日志存储的是对数据进行增/删/改的指令记录,每次通过追加的方式写到AOF日志中。redis收到一条修改指令后,执行成功后,先把指令写到AOF文件缓存中,然后根据同步频率的策略再写到磁盘上。

redis在长期运行过程中,AOF日志会越来越大,如果redis服务重启后根据很大的AOF文件来顺序执行指令,将会非常耗时,导致redis服务长时间无法对外提供服务,所以需要对AOF文件进行"瘦身"。"瘦身"的过程称作AOF重写(rewrite)。
AOF重写:主进程fork产生一个子进程,对当前内存中的数据进行遍历,转换成一系列的redis操作指令,并序列化到一个新的AOF日志中,然后把序列化操作期间新收到的操作指令追加到新的AOF文件中,追加完毕后就立即替换旧的AOF文件,这样就完成了"瘦身"工作,即AOF Rewrite。
(redis把新收到的操作指令追加到AOF文件这个过程,并不是直接写到AOF文件中,而是先写到操作系统的内存缓存中,这个内存缓存是由操作系统内核分配的,然后操作系统内核会异步地把内存缓存中的redis操作指令刷写到AOF文件中。)
AOF有三种触发机制
(1)每修改同步always:同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
(2)每秒同步everysec:异步操作,每秒记录 如果一秒内宕机,有数据丢失
(3)不同no:从不同步
redis重点

优点:
redis宕机时最多丢失一秒钟的数据,比RDB少,因为AOF每隔一秒通过后台线程执行一次fsync操作,同步到磁盘文件;
AOF日志文件即使过大的时候,出现后台重写操作进行压缩,也不会影响客户端的读写;
AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复;
AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。

缺点:
同一份数据而言,AOF日志文件比RDB数据快照块大;
AOF日志写性能仍比RDB写性能低,因为AOF日志每秒会fsync一次;
基于AOF日志的恢复速度不如RDB恢复。

其实最佳方案应该是采用混合持久化方案:
开启混合持久化后,AOF重写日志时会将RDB持久化的内容写到AOF文件开头,于是在Redis重启时,可以先加载RDB的内容,再对增量的AOF日志进行重放,提升Redis重启的效率。

单线程模型每秒万级别处理能力的原因:

1.redis是纯内存访问。数据存放在内存中,内存的响应时间大约是100纳秒,这是Redis每秒万亿级别访问的重要基础。
2.非阻塞I/O,Redis采用epoll做为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为了事件,不在I/O上浪费过多的时间。
3.单线程避免了多线程切换和竞态产生的消耗。
4.Redis为了高效的处理客户端的事件,并没有将持久化文件放在主线程里面进行处理,而是Redis在适当的时机fork子进程来异步的处理这种任务,Redis会fork子进程进行处理持久化文件操作(将数据写到RDB 文件中)。Redis还有一组异步任务处理线程,用于处理不需要主线程同步处理的工作,即处理一些低级别的事件(AOF文件重写)。

IO多路复用

指的是多个请求能复用一个线程进行处理,而不是传统的一个线程处理一个请求(一个线程处理多个请求)。用户发起请求的时候,先将Socket注册到select中,阻塞登录select函数返回。当数据到达时,select被**,select函数返回,用户才正式发起请求。使用select之后,用户线程可以注册多个Socket的IO请求,然后不断调用selector执行被**的Socket请求,达到在一个线程里面执行多个IO请求的目的。之前同步阻塞模型中,需要多线程的方式才可以完成。
IO多路复用模型是建立在内核提供的多路分离函数select函数基础上的。
Redis里面使用Reactor模式实现网络文件事件处理器,包含四部分:多个套接字,IO多路复用,文件事件分派器,事件处理器。(由于文件事件分派器队列是单线程的,所以redis才叫单线程模型。)
Redis通过reactor的方式,用户线程轮询IO操作状态的工作交给handle_events来处理。用户线程注册事件处理器之后可以继续执行做其他的工作(异步),而reactor线程负责调用内核的select函数检查Socket的状态。当有Socket被**时,则通知用户线程执行handle_evnet进行数据读取、处理的工作。
redis是单线程的,收到的多个请求都放在文件事件分派器队列中,所有的操作都是线性执行,但是读写操作的涉及IO操作,会堵塞当前线程,最后导致整个redis服务暂停。IO多路复用就是为了解决这个问题而出现的。

相关文章:

  • 2021-09-12
  • 2022-02-01
  • 2022-12-23
  • 2021-09-17
  • 2022-12-23
  • 2021-10-04
  • 2021-11-10
  • 2021-07-15
猜你喜欢
  • 2022-12-23
  • 2021-08-14
  • 2021-11-06
  • 2021-07-06
  • 2021-06-29
  • 2021-04-06
  • 2022-01-20
相关资源
相似解决方案