transactions
redis的事务并不能回滚,即使执行失败了,后面的命令一样会执行
exec命令触发前面被queue的命令原子执行
最后:transaction最终将被scripts替代,因为它们提供了原子性,原子性可以理解为redis单线程执行命令自带的原子性,并且更快,script命令仍然没有rollback功能
redis官方解释:redis只有在错误的program时才会出现,你应该修改你的bug,而不是rollback
pipeline
redis使用client-server模型,也叫Request/Response protocol
因此一个请求完成需要经历的步骤:
- client发送请求给server,从socket读取reponse,通常是阻塞的
- server执行命令并发送reponse给client
RTT(Round Trip Time):包从client发送到server,再从server返回到client的时间
这也意味着,如果RTT为250毫秒,则不管server的性能有多牛逼,client端感知道的ops为:4/s
恰逢你想一次执行多个命令,如果通过普通的串行调用,这个时间耗费就相当高了
此时,你就可以使用pipelining了(注意server端分片的情况,key不同请慎重),它能有效减少RTT
还有需要注意的是:server端将把多个命令的结果放到一个queue里面,这是会产生额外内存消耗的,如果有10k个操作使用pipeline执行,则server端就需要相应结果集对应的内存。
pipeline还减少了read() write()操作的性能损耗,如果请求被挨个发送到server,则相比pipeline,server和client调用read()和write()的次数增加了,这是一个系统方法调用,意味着从用户态到内核态的切换,上下文切换是一个速度上的较大的损害
和script对比,性能可能略低,原因是多个命令,每次执行完上一个命令后,需要将reply放置,才能执行下一个命令,script则没有这个问题。
pipeline也可以和script一起使用,如多次执行eval或evalSha命令
rdb
优点:
- 一个压缩文件,对应了server某个时间点的数据
- 容灾恢复,可以传到远程中心
- 除了bgsave fork一个子进程外,其他的备份操作由子进程完成
- 大数据量时,使用rdb重启redis,速度快于aof
缺点 - 不够实时,如果1小时备份一次,或10000次备份一次,则丢失的数据量可能比较大
- 大数据量时,fork一个子进程也是相当耗时的,这段时间server将不能响应client的请求
解决办法 控制单个redis的大小,配合aof
过程
- fork child process
- child 生成临时dump.rdb
- child用新的rdb文件去替换老rdb
aof
优点:
- 可以配置隔多久写一次追加日志,默认为1s,这样丢失的数据就比较少了
- 它是一个append only file,不怕断电,有机制可以修改写了一半的命令
- 当aof文件变得很大时,redis会自动BGREWRITEAOF重写aof文件,通过后台重新生成一个当前数据集的文件,生成完成后替换现有的aof文件
- 容易解析格式,甚至错误的执行了flushAll命令,只要文件没有重写,就可以删除flushAll命令,利用aof文件重启redis来恢复
缺点
- 通常比rdb大
- 在每个命令都fsync到文件的模式,性能很差
- 之前遭遇过一些特殊的bug,仅在某个命令下出现,这一点上,它没有rdb那么健壮
rewrite过程
- fork child process
- child向临时文件写new AOF
- parent把新的更改放在内存缓冲区中,此时老的aof追加过程依旧继续,保证数据安全
- child rewrite结束后,parent获得信号,将内存缓冲区中的变化追加到child生成的aof文件的尾部
- 原子的将aof文件的名字改成新的文件名,然后往新的文件append
该怎么使用备份
- 如果允许数据丢失一段时间,可以直接使用rdb
- 长久计划中,将统一rdb和aof
- 用定时任务将rdb文件copy到其他物理机,删除很久以前的rdb