突然挂了!Redis缓存都在内存中,这下完了!( 二 )


“这里面呀记录了我对数据执行更改的所有操作 , 像是INSERT , UPDATE、DELETE等等动作 , 等我要进行数据恢复的时候就可以派上大用场了”
听他这么一说 , 我一下来了灵感!告别了MySQL大哥 , 回去研究起新的方案来了 。
AOF持久化
你们也知道 , 我也是基于命令式的 , 每天的工作就是响应业务程序发来的命令请求 。
回来以后 , 我决定照葫芦画瓢 , 学着MySQL大哥的样子 , 把我执行的所有写入命令都记录下来 , 专门写入了一个文件 , 并给这种持久化方式也取了一个名字:AOF(AppendOnlyFile) 。
突然挂了!Redis缓存都在内存中,这下完了!
文章图片
不过我遇到了RDB方案同样的问题 , 我该多久写一次文件呢?
我肯定不能每执行一条写入命令就记录到文件中 , 那会严重拖垮我的性能!我决定准备一个缓冲区 , 然后把要记录的命令先临时保存在这里 , 然后再择机写入文件 , 我把这个临时缓冲区叫做aof_buf 。
突然挂了!Redis缓存都在内存中,这下完了!
文章图片
说干就干 , 我试了一下 , 竟然发现数据没有写入到文件中去 。 多方打听才知道 , 原来操作系统也有个缓存区 , 我写的数据被他缓存起来了 , 没有给我写入到文件中去 , 这不是坑爹呢嘛!
看来 , 我写完了还得要去刷新一下 , 把数据真正给写下去 , 思来想去 , 我还是提供一个参数 , 让业务程序去设置什么时候刷新吧 。
appendfsync参数 , 三个取值:always:每个事件周期都同步刷新一次everysec:每一秒都同步刷新一次no:我只管写 , 让操作系统自己决定什么时候真正写入吧
AOF重写
这一次我不像之前那么冲动 , 我决定先试运行一段时间再去告诉MySQL大哥 , 免得又被他戳到软肋 。
试用了一段时间 , 各方面都运行良好 , 不过我发现随着时间的推移 , 我写的这个AOF备份文件越来越大 , 越来越大!不仅非常占硬盘空间 , 复制移动 , 加载分析都非常的麻烦耗时 。
我得想个办法把文件给压缩一下 , 我把这个过程叫做AOF重写 。
突然挂了!Redis缓存都在内存中,这下完了!
文章图片
一开始 , 我打算去分析原来的AOF文件 , 然后将其中的冗余指令去掉 , 来给AOF文件瘦瘦身 , 不过我很快放弃了这个想法 , 这工作量实在太大了 , 分析起来也颇为麻烦 , 浪费很多精力跟时间 。
原来的一条条记录这种方式实在是太笨了 , 数据改来改去 , 有很多中间状态都没用 , 我何不就把最终都数据状态记录下来就好了?
比如:RPUSHname_list'编程技术宇宙'RPUSHname_list'帅地玩编程'RPUSHname_list'后端技术学堂'
可以合并成一条搞定:RPUSHname_list'编程技术宇宙''帅地玩编程''后端技术学堂'
AOF文件重写的思路我是有了 , 不过这件事干起来还是很耗时间 , 我决定和RDB方式一样 , fork出一个子进程来做这件事情 。
谨慎如我 , 发现这样做之后 , 子进程在重写期间 , 我要是修改了数据 , 就会出现和重写的内容不一致的情况!MySQL大哥肯定会挑刺儿 , 我还得把这个漏洞给补上 。
突然挂了!Redis缓存都在内存中,这下完了!
文章图片
于是 , 我在之前的aof_buf之外 , 又准备了一个缓冲区:AOF重写缓冲区 。
从创建重写子进程开始的那一刻起 , 我把后面来的写入命令也copy一份写到这个重写缓冲区中 , 等到子进程重写AOF文件结束之后 , 我再把这个缓冲区中的命令写入到新的AOF文件中 。