Redis流行的原因( 三 )


优点:1.RDB是一个非常紧凑的文件 , 保存了Redis在某个时间点上的数据集 , 非常适合用于进行备份2.RDB在恢复大数据集时的速度比 AOF 的恢复速度要快缺点:1.数据集比较庞大时 , fork()可能会非常耗时 , 造成服务器在某段时间内停止处理客户端2.每隔一段时间才保存一次RDB文件 , 在这种情况下 , 一旦发生故障停机 , 你就可能会丢失好这段时间的数据
AOF(Append-only file)

  • 开启方式redis.conf配置
appendonly yes# appendfsync always# appendfsync noappendfsync everysec核心函数:flushAppendOnlyFile()每当执行服务器(定时)任务或者函数时flushAppendOnlyFile函数都会被调用 , 这个函数执行以下两个工作WRITE:根据条件 , 将 aof_buf 中的缓存写入到 AOF 文件SAVE:根据条件 , 调用 fsync 或 fdatasync 函数 , 将 AOF 文件保存到磁盘中
优点:1.如不小心执行flushall命令 ,只要AOF文件未被重写 , 停止服务器 ,移除AOF文件末尾的FLUSHALL命令并重启Redis , 就可以将数据集恢复到flushall执行之前的状态2.可读性高3.默认为每秒钟fsync一次 , 也最多只会丢失一秒钟的数据
缺点:1.AOF文件比较大2.加载入内存 , 耗时比RDB慢
混合模式
  • 开启方式
# When rewriting the AOF file, Redis is able to use an RDB preamble in the# AOF file for faster rewrites and recoveries. When this option is turned# on the rewritten AOF file is composed of two different stanzas:##[RDB file][AOF tail]## When loading Redis recognizes that the AOF file starts with the "REDIS"# string and loads the prefixed RDB file, and continues loading the AOF# tail.aof-use-rdb-preamble yes
  • 显式的查看混合模式的数据
  1. 执行BGREWRITEAOF命令
? software redis-cli127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379> set name ivansliOK127.0.0.1:6379> set today 20200608OK127.0.0.1:6379> keys *1) "today"2) "name"127.0.0.1:6379> BGREWRITEAOFBackground append only file rewriting started127.0.0.1:6379> set time 19:15:55OK2. 查看appendonly.aof文件
REDIS0009?redis-ver5.0.7?redis-bits?@?ctime??^used-mem??aof-preamble???today <4nameivansli??4?wq???*2$6SELECT$10*3$3set$4time$819:15:55混合模式的AOF文件数据 , 相当于:某刻的RDB格式全量数据 + 此刻之后的RESP格式增量数据
为什么使用混合模式(RDB优点+AOF优点):
  1. RDB格式数据加载快速
  2. AOF追加的RESP数据 , 可以减少数据的丢失
  3. 既能保证Redis重启时的速度 , 又能降低数据丢失的风险
重启之后数据加载
源码(V5.08)追踪server.cmain() -> loadDataFromDisk()
/* Function called at startup to load RDB or AOF file in memory. */void loadDataFromDisk(void) {long long start = ustime();if (server.aof_state == AOF_ON) {if (loadAppendOnlyFile(server.aof_filename) == C_OK)serverLog(LL_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);} else {rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;if (rdbLoad(server.rdb_filename,/* Restore the replication ID / offset from the RDB file. */if ((server.masterhost ||(server.cluster_enabledserver.master_repl_offset = rsi.repl_offset;/* If we are a slave, create a cached master from this* information, in order to allow partial resynchronizations* with masters. */replicationCacheMasterUsingMyself();selectDb(server.cached_master,rsi.repl_stream_db);}} else if (errno != ENOENT) {serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno));exit(1);}}}