
1 Redis问诊
作为全球最大的同性交友网站的资深会员,持久性一直是我们不泻懈的追求,比如Redis就一直希望自己能像MySQL一样老而弥坚。
但是呢,Redis自己又一直不太确定这件事情,去网上查资料也是众说纷纭。俗话说:自己的病自己看,熊猫大夫来诊断。于是Redis来到了熊猫诊所。
Redis:『医生,请问我是否跟MySQL一样持久?』
熊猫:『不要叫我医生,请叫我大夫』
Redis:『好的。。。大夫,请问我是否跟MySQL一样持久?』
熊猫:『不是是否,而是能否』
Redis:『请问这有区别嘛?』
熊猫:『有滴:是否代表默认配置,与生俱来的持久;能否则代表通过调整配置,多磕药,能否变的持久一些』
Redis:『好的大夫,请问我能否跟MySQ¬一样持久?』
熊猫:『简而言之,你是健康的』
Redis:『。。。。。。这是一点儿心意,还请您笑纳』
熊猫:『咱们屋里聊聊?』
2 刷盘持久性
在DB领域,持久性的目的是容灾,即在发生宕机、崩溃、断网、磁盘满等种种人为不可控事件时,保证数据的一致性和完整性。
男同胞都懂,持久是件很难的事。目前为止,我知道的方法只有两种:一是刷盘(原地复活),二是副本(影分身)。
刷盘,又叫落盘,是单机实现持久性的唯一手段。基于B-Tree的DB,一般通过WAL(Write Ahead Log预写日志)实现持久性。其原理是在真正修改B-Tree之前,把对DB的修改以append-only的方式写入磁盘,同时后台线程根据WAL把对DB的修改异步合并到B-Tree中。
如果在把WAL合并到B-Tree的过程,DB进程意外重启了,在重启过程中DB仍然可以把WAL重新应用到B-Tree上,从而确保DB数据的一致性和完整性。
为什么刷盘时不直接修改B-Tree,而是在中间多加一份WAL呢?为了速度。WAL是append-only的,顺序写磁盘速度远超随机写。
3 Redis是使用了WAL么?
似是而非。
通常WAL是Write Ahead Log的缩写,但在Redis中,它使用是Write After Log。或者说,Redis写Log的操作是在修改内存数据之后进行的,而不是在修改内存数据之前。Redis如此邯郸学步的借口是:不希望把错误的命令写入到RDB中。
通过先执行命令修改内存数据,Redis可以发现哪些命令是错误的,从而避免把这些错误的命令写入到RDB中。
但这并不是重点,重点是:通常我们使用WAL的目的是为了实现事务回滚,即当事务在执行过程中出现意外时,事务可以Rollback已经执行的部分操作,从而从整体上保证DB中数据的逻辑一致性。这是事务ACID中最重要的目标:Atomicity(原子性)
但Redis却抛弃了这一目标,并辩解声称:程序员应该为自己的代码负责,他们有责任写出无错的代码。
4 Redis如何实现原子性?
事务原子性,要求把一组可能影响多个对象操作绑定为一个整体。他们荣辱与共、同吃同睡、共同进退,好的就像没离婚的夫妻一样。
要实现原子性,目前我知道的方向有两类:一是Undo (Rollback),二是Redo (Retry)。一般DB基于Undo的方案,而Redis耍赖不管,当甩手掌柜,只好我们自己来接手这件事。
万幸的是,Redis的隔离级别很高,是Serializability(可串行化)。当我们执行lua脚本编写的一组事务代码的时候,如果中途发现因条件不具备导致执行失败,此时我们可以选择手动回滚所有的修改,因为可串行化保证了没有其它线程在并发修改数据。当然,如果你习惯使用Redis的MULTI系列指令,也需要自己负责起回滚的责任。
5 Redis持久么?
银样蜡枪头。
1 单机持久性
Redis提供appendfsync参数,可以调整AOF的刷盘时机,可选项有:
always:看起来很强壮,但其实并没有把命令的日志刷盘到AOF文件,而是只写到了aof_buf内存缓冲区中,在下一个event loop前才会调用fsync刷盘。因此,是有机会丢失数据的。同时,该选项会极大拖慢Redis响应速度,因此并不推荐使用
everysec (默认):每秒调用一次fsync,把aof_buf的数据刷盘到AOF文件。如果期间Redis进程意外崩溃,可能丢失1秒的数据
no:只是把命令的日志写到aof_buf内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
2 副本持久性
Redis的主从机制也很弱, 无法提供与MySQL一主二从三副本对等的配置。
Redis提供了wait指令,但一方面需要在代码中手动调用太麻烦,另一方面wait指令还可能会超时,此时主从节点的数据状态就不一致了,如果此时自动切主的话,就可能带一些问题。
3 弱持久性
Redis还真是要速度有速度,要持久有速度。
它只能提供弱持久性,无论是单机还是副本,都无法做到与MySQL相仿的地步。
6 找工作:缓存 or 统计
前几天,看脉脉上有人问是否可以把Redis当作主库。下面有人回复讲字节的海外电商就是这么干的,说实话把我震惊到了。
对于大多数互联网业务,完整一致的数据都可能是一种重要资产。从CAP的角度来,Redis是一种AP架构,强调速度,强调可用性,但也因此削弱了一致性。在电商这种金融类业务中,使用Redis还是要慎重。
在我看来,适合Redis的工作只有两种:缓存 or 统计。
这两种数据都具有很强的展示属性,就是拿来给用户看的。而且经常可以容忍一定的误差,比如秒级的误差可能并不影响用户对业务的判断。比如像电商业务中剩余库存的数量,每日访问网站的pv/uv数等。
就跟ChinaJoy上的Show Girl一样,站出来就是给你看的嘛,真正下单的时候买到手的东西跟你看到的完全不一样。
怀念在完美做游戏的日子,那时候天还是蓝的,水还是绿的,我还是有工作的
7 先帝创业未半
而中道崩殂,越明年,政通人和,百废俱兴。很久没写公众号了,最近赋闲,倒是有时间把一些想法整理一下了。
以前觉得能力不足,总是想着再等等,万一写错了,误导别人岂不是不好?现在想想,其实就是懒散罢了。坦然承认,倒也没敢下决心改掉懒散的习惯,是我琢磨着不要给自己太大的压力是不是会更好一些?写多写少,更多的是给自己一份交待,偶尔搏大家一笑。
8 References
AOF设置成为always时,数据绝对不会丢失吗?
04 | AOF日志:宕机了,Redis如何避免数据丢失?