什么是RDB持久化?

redis作为内存数据库,享受了内存带来的收益,就要遭受内存数据断电丢失的风险,为了处理这种风险或者说降低这种问题出现后带来的损失,redis提供了两种数据落盘方式,一种是rdb,一种是aof。

  • RDB:对某一刻内存的全量数据的快照,落盘的内容是对应的内存地址和数据。
    • 优点:对主线程几乎(这说明还是有少量影响的)没有影响,服务器启动恢复较快。
    • 缺点:每个rdb文件的数据量很大,耗时也相对较长,所以触发间隔不能太短,否则既耗费大量磁盘空间,又影响redis的性能。所以需要一定的时间间隔,也就会存在间隔时间内增量数据丢失的风险。
  • AOF:基于WAL(write ahead log)方式的实现,类似于Mysql的redolog,针对的是单次请求的备份。
    • 优点:数据丢失很少甚至不丢失。
    • 缺点:每次请求除了操作内存,还需要落盘,影响主线程的吞吐量,所以要么降低这种影响,一般会配置成秒级落盘,而不是每次操作都落盘。另外相对于RDB,服务器启动恢复较慢。

      RDB的持久化过程

  1. 人工手动触发:save,redis系统触发:bgsave。
  2. redis是单线程,持久化工作涉及到大量IO操作,所以显然不能主进程用来做持久化,redis采用的方式是调用glibc的内核函数fork(),基于主线程生成一个子进程。需要注意的是,虽然后续的持久化工作由子进程负责,但是在fork这一步操作中,主进程是阻塞的,也就是说如果频繁触发RDB,对redis的性能是有影响的。
  3. 由于fork生成的子进程和redis的主进程共享内存空间及其数据。来想这么一个问题,子进程在处理持久化的过程当中,主进程继续接收写请求,导致了数据变更,那么子进程持久化的数据就不是同一时刻的快照了。
  4. redis是这么处理的,如果redis主进程在写某一条数据(由于内存页管理,所以会连带整页,比如4K大小),那么这块数据就会被复制一份到内存,生成该数据的副本,主进程在该副本上进行修改操作。所以即使对某个数据进行了修改,Redis持久化到RDB中的数据也是未修改的数据,这也是把RDB文件称为”快照”文件的原因,子进程所看到的数据在它被创建的一瞬间就固定下来了,父进程修改的某个数据只是该数据的复制品。
  5. 而在持久化过程中,随着分离出的页面越来越多,内存就会持续增长,但是不会超过原内存的2倍。正因为修改的部分数据会被额外的复制一份,所以会占用额外的内存,当在进行RDB持久化操作的过程中,与此同时如果持续往redis中写入的数据量越多,就会导致占用的额外内存消耗越大。
  6. 写入的数据还是存在了内存当中,并没有写入当前的持久化文件中,等到下次进行RDB持久化时才会把 ” 写入的数据 ” 落盘到RDB文件中。