Redis(四)-日志

2020-11-28  本文已影响0人  进击的蚂蚁zzzliu

概述

本节主要分析下Redis日志持久化机制,包括RDB、AOF以及360开源的Pika

1. AOF

1.1 是什么?

AOF是写后日志,即先写内存再记录日志;日志中记录用户的操作命令(类似mysql的binlog)

举例:127.0.0.1:6379> set testkey testvalue

--AOF日志:
*3
$3
set
$7
testkey
$9
testvalue

1.2 写策略

由于Redis是单线程,如果主线程处理写AOF务必会影响用户请求,因此Redis提供了三种写策略

小结
Always可靠性高,数据基本不丢失,但是每个命令都要写磁盘,性能影响较大;
Everysec性能适中,宕机时最多丢失1秒数据,Redis的默认策略
No性能好,但是宕机时丢失数据较多

1.3 存在的问题

思考此时AOF日志机制存在什么问题?
写AOF日志的目的是为了给数据做持久化,以便宕机或重启时还原内存数据,要实现这个目标需要考虑几个问题:

  1. 文件系统本身对文件大小有限制,无法保存过大的文件;
  2. 如果文件太大,之后再往里面追加命令记录的话,效率也会变低;
  3. 如果发生宕机,AOF中记录的命令要一个个被重新执行,用于故障恢复,如果日志文件太大,整个恢复过程就会非常缓慢,这就会影响到Redis的正常使用
  4. 写AOF日志会影响主线程响应用户请求

1.4 reids如何解决?

  1. 采用重写机制:首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录该键值对的多个命令;
  2. 主线程fork一个后台子线程bgrewriteaof来进行重写,避免阻塞主线程;
  3. Redis增加了一个AOF重写缓存区用于记录重写过程中主进程接收到的命令;
    redis-AOF重写.png
    重写步骤解析
    1.:主进程接收客户端请求命令
    2.:触发AOF重写时,主进程fork一个bgrewriteaof子进程,该子进程指向与父进程相同的内存地址空间
    a. 子进程开始:AOF重写,把内存中的所有数据写入到新的AOF文件中,该过程可能耗时较长;但是主进程可以继续处理请求;
    3.:操作写入redis
    4.:日志写入AOF缓冲区
    5.:日志写入AOF重写缓冲区
    6.:AOF缓冲区日志继续写入原AOF文件
    -----分割线 子进程重写完之后向父进程发送完成信号,父进程继续处理-----
    7.:主进程将AOF重写缓冲区中的内容全部写入到新的AOF文件中;这个时候新的AOF文件所保存的数据库状态和服务器当前的数据库状态一致
    8.:对新的AOF文件进行改名,原子的覆盖原有的AOF文件;完成新旧两个AOF文件的替换

1.5 触发重写条件

触发写AOF有两种方式:

配置参数:
AOF增加百分比:auto-aof-rewrite-percentage默认100
AOF重写阈值: auto-aof-rewrite-min-size默认64mb

1.6 重写后还存在什么问题?

再来思考下:重写机制之后AOF日志用于重启或宕机恢复redis还存在什么问题?

  1. AOF日志虽然提供了三种写策略,但是无法同时实现即高效又不丢失数据;
  2. AOF日志记录的是命令,数据恢复时需要一条条重新执行,这个效率较低;

要想解决这两个问题就需要引入下面的RDB,gogogo...

2. RDB

2.1 是什么?

RDB即内存快照,就是指内存中的数据在某一个时刻的状态记录(类似thread dump),把这一时刻的状态以文件的形式写到磁盘文件上,用于数据恢复;

2.2 怎么做?

  1. 为了避免阻塞主线程,redis采用通过bgsave来fork子进程进行操作;
  2. 为了在快照时允许写请求继续执行,redis利用Linux写时复制技术;
    redis-RDB.png
    写RDB步骤解析
    1.:主进程接收客户端请求;
    2.:触发bgsave时,主进程fork出bgsave子进程,fork时会复制主进程页表,子进程就可以不用复制物理内存而直接访问主进程内存;
    a. 子进程:把内存快照数据写入RDB文件
    3.:读操作主进程通过页表找到物理页直接进行读取,不影响bgsave进程写RDB文件
    4.:写操作,假如主线程需要修改虚页7里的数据,那么,主线程就需要新分配一个物理页(假设是物理页55),然后把修改后的虚页7里的数据写到物理页55上,而虚页7里原来的数据仍然保存在物理页33上。这个时候,虚页7到物理页33的映射关系,仍然保留在bgsave子进程中。所以,bgsave子进程可以无误地把虚页7的原始数据写入RDB文件
    5.:bgsave进程写完通知主进程,主进程把临时RDB文件替换并删除原RDB文件

2.3 触发条件

触发RDB快照跟AOF一样,同样有两种方式:

--redis默认
# 900s内至少达到一条写命令
save 900 1
# 300s内至少达至10条写命令
save 300 10
# 60s内至少达到10000条写命令
save 60 10000

2.4 啥问题?

看完AOF和RDB的方案,再继续思考下要想实现即高效又完全不丢失数据的目标,还存在哪些问题:

  1. 频繁写RDB,将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽时,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环
  2. bgsave子进程需要通过fork操作从主进程创建出来,过程中需要复制主进程必要的数据结构,内存越大虚拟内存到物理内存映射索引表越大,fork耗时越大,主进程阻塞时间越长
  3. 如果调低RDB执行频率,就会失去做快照的意义;
  4. 当单实例redis内存非常大时,也会存在一些问题:
    • RDB文件生成时的fork时长就会增加,会导致Redis实例阻塞
    • RDB进行恢复的时长也会增加,会导致Redis较长时间无法对外提供服务
    • 主从同步时,会导致全量同步的时长增加,效率不高,主从切换慢

2.5 如何解决?

3. Pika

3.1 是什么?

Pika 主要解决的是用户使用 Redis 的内存大小超过 50G、80G 等等这样的情况,会遇到启动恢复时间长,一主多从代价大,硬件成本贵,缓冲区容易写满等问题。Pika 就是针对这些场景的一个解决方案。

3.2 架构

  1. 整体架构


    Pika.png
  1. RocksDB写入流程


    Pika-RocksDB.png

3.3 Pika优点

  1. 使用了SSD来保存数据,解决了Redis使用内存成本太高的问题
  2. 全量同步时直接读取RocksDB的数据文件,增量同步时使用binlog机制,不使用RDB内存快照,避免了大内存时的影响
  3. Pika实例重启时,可以直接从SSD上的数据文件中读取数据,不用像RDB文件全部重新加载数据或是从AOF文件中全部回放操作,重启快
  4. Pika通过binlog机制实现写命令的增量同步,不再受内存缓冲区大小的限制,不用担心缓冲区溢出而触发的主从库重新全量同步问题

总结

本节分析了AOF、RDB、Pika三种缓冲方案的实现,以及各自解决了什么问题,又带来了什么问题;具体使用时还要具体分析权衡利弊,下面几点建议

上一篇 下一篇

猜你喜欢

热点阅读