Redis 能否保证数据高可靠性

记录下工作中关于Redis的一些思考,主要关于Redis的事务,脚本,持久化

本文讨论的问题:

  1. Redis的事务或者执行lua脚本可以像关系型数据库事务那样,要么全部提交,要么全部回滚吗?

  2. 当脚本或者事务执行过程中发生宕机Redis中的数据会丢失吗?

原子性

在Redis的开发文档中可以了解到,Redis的事务以及Redis执行lua脚本都可以保证原子性(Redis的每条命令也是原子的),那么原子性可以保证什么?能否解决我们的问题?先来看下原子性的定义

来自维基百科对关系型数据库事务原子性的定义

事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行

来自百度百科原子操作的定义

原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断

Redis 所保证的原子性正是如此

  • 不可分割,保证事务和脚本执行过程中,不会被其他客户端的命令打断
  • 事务和脚本中的命令,要么都执行,要么都不执行

Redis Transactions

如何使用Redis 事务

> MULTI // 开启事务
OK
> SET KEY VALUE // 执行命令,此时的命令只是入队,会在 EXEC 之后原子性的执行事务中所有命令
QUEUED
> EXEC  / DISCARD // 执行或者取消事务

Redis的事务保证

  • 在Redis事务的执行过程中,永远不会执行另一个客户端发出的请求

  • 所有命令都会执行,或者不执行。如果在执行 EXEC 之前,客户端与服务端失去响应,那么事务中所有的命令都不会执行,相反如果执行 EXEC 保证所有的命令都执行

事务中可能发生的错误
  • EXEC 之前:命令无法Queued,例如语法错误(错误的参数数量,错误的命令),或者一些其他错误,例如内存不足(Redis使用了maxmemory 限制最大内存)

  • EXEC 之后:命令也可能会失败,例如针对string类型使用list的命令

EXEC 之前的错误,客户端可以通过检查服务端的响应来解决,当发生入队失败时(Redis响应值非QUEUED),客户端DISCARD当前事务

从Redis 2.6.5开始,Redis 会记录事务期间发生的错误,并拒绝执行事务,在执行EXEC时返回错误信息并自动丢弃该事务

但是EXEC 之后的错误,即使导致部分命令执行失败,Redis还是会执行其他的剩余命令

Redis 事务的不回滚机制

虽然Redis保证了原子性,但是他的事务并不会像关系型数据库那样,在Redis事务中如果某条命令发生了错误,其他的命令会依旧执行,这点相比较关系型数据库来说不免有些"奇怪"了

Redis开发文档中给出的解释如下

  • 只有语法错误才可能导致命令执行失败,大多数情况都是编程错误导致的

  • 因为不需要回滚,使得 Redis 更简单 更高效

关于事务的更多内容👉 https://redis.io/topics/transactions

Redis lua

2.6.0 版本后,Redis 增加了对lua脚本的支持,脚本和Redis事务一样保证了原子性,执行脚本时不会执行其他脚本或Redis命令(所以不要让脚本运行时间过长),同样脚本也没有回滚机制,当脚本中出现lua的异常,或者Redis命令错误,也无法保证全部执行成功

Redis lua 和事务有点类似,但是有些场景使用事务是无法做到的,例如我想对Redis中的数据先读,然后根据原有数据变更,整个过程想要保证原子性,由于事务在EXEC之前无法获取返回值,使用lua 就非常合适

关于Redis lua 更多内容 👉 https://redis.io/commands/eval

Redis 执行命令时宕机数据会丢失吗

看到了这,第一个问题我们已经清楚了,Redis并没有回滚的能力,但是通常情况下,这些需要回滚的场景都是编码错误,我们是可以避免的。我们继续探寻第二个问题的答案

Redis是基于内存的数据库,所以当发生宕机或者停止后重新启动时,Redis会使用磁盘上的持久化文件来恢复数据,所以是否能恢复数据,能恢复多少数据,取决于使用哪一种持久化策略

简单说下两种持久化策略

RDB

按指定的时间间隔将内存中数据集写入快照

AOF

AOF会记录服务器接收的每个写入操作。当Redis命令执行成功后,命令会被传播到AOF程序中。AOF 的三种同步策略

  • appendfsync always :每次有数据修改发生时都会同步到AOF文件
  • appendfsync everysec :每秒钟同步一次,AOF的默认策略
  • appendfsync no :将数据同步将给操作系统管理,通常linux系统30s会同步一次数据,但这取决于操作系统

即使使用always 也无法保证写入的每一条命令都被持久化,从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔

回到我们的问题上,如果使用RDB,毫无疑问,数据只能恢复到上次的备份

即使使用AOF的话,如果在Redis事务执行期间宕机,那么这次事务还是相当于"没有执行",由于命令还没来及写入AOF,在服务恢复后更不可能恢复数据。对于Redis客户端而言,会收到服务端的异常响应

写入AOF的过程也是会被打断的,Redis 文档中提到,如果Redis服务器突然崩溃,导致出现了"半写状态"的AOF文件时,服务器重新启动时,会检测到这种情况,并且退出提示用户使用 redis-check-aof 修复 AOF 文件。"半写状态"的事务或者命令会被删除,服务器可以重新启动。

如果写入AOF过程被打断,对于客户端而言可能是毫无感知的(看了下Redis命令执行相关,AOF应该是发生在响应客户端之后)

所以第二个问题,我们也清楚了,Redis 并不能保证我们写入的数据都安全的持久化

关于持久化的更多内容👉 https://redis.io/topics/persistence

扩展:脚本如何持久化

这里说的是AOF的情况

在Redis 5 之前,默认是将脚本本身传播到AOF中。这种传播方式的好处,不需要将脚本转成Redis命令,在写入AOF或者其他Redis实例时不会占用过多的带宽和CPU

复制脚本不允许脚本中出现随机性的写入,因为这会导致通过AOF恢复数据时,数据不一致,在这点上Redis做了一些限制,由于不是本文重点就不多说了,可以参考Redis开发文档

从Redis 3.2 开始新增了一种脚本复制方式 script effects replication(Redis 5 开始默认使用这种方式处理脚本)。这种模式下,Redis 会收集脚本中所有修改数据的命令。当脚本执行完成后,这些命令被包装成一个事务,传播到AOF 和其他实例。

这种方式的好处

  • 当脚本执行很慢的时候,会影响加载AOF重建数据的时间,这种情况使用 script effects replication 效率更高

  • 这种方式会允许脚本中存在随机性的写入

使用方式

-- 在执行Redis命令前调用,成功启用 script effects replication 返回true
redis.replicate_commands()

总结

所以说Redis无论是事务还是脚本,并不能做到像关系型数据事务一样,所以针对数据一致性要求较高的业务场景,并不适合使用Redis

而且从持久化方面来考虑,这也不是Redis的强项,Redis的优势正是基于内存,所以读写性能高。虽然宕机的可能性看似很极端,通常我们使用了某个服务后,我们会尽可能的保证它的高可用,但是我们需要知道Redis的"持久化"并不能保证我们的数据绝对安全,所以当我们的业务场景对数据一致性,持久化要求很高的时候,关系型数据库依旧是很好的选择

参考

Redis 设计与实现 AOF
Redis 设计与实现 事务
Redis 命令执行过程(上)
Redis 命令执行过程(下)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356