事务
Redis事务是一组命令的集合,事务的原理是先将属于一个事务的多个命令发送给Redis,然后再让Redis依次执行这些命令。Redis的事务和传统的关系型数据库不同,在关系型数据库中,用户首先向数据库发送一个BEGIN信号,然后执行多个读写操作,最后,用户发送COMMIT来确认之前的操作,或者发送ROLLBACK来放弃之前的操作。在redis中也有简单的方法可以处理一连串的读写操作,使用命令MULTI为开始,然后传入一连串用户的操作指令,最后以EXEC结束,但这种做法,实际上是在用户执行EXEC之前,客户端缓存保留所有命令,在EXEC之后一次性把所有命令发送到服务器执行,然后等待直到接收所有的命令回复为止。
注意:如果事务块中某一条命令执行出错,关系型数据库的事务会执行回滚,而redis不会执行回滚,而是会继续执行后续的命令。因为redis的事务没有关系型数据库的回滚(rollback)功能。因此需要开发者在事务执行出错时自己处理。需要注意的如果事务中某个命令的语法错误,会导致整个事务中断,而命令执行调用的时候的错误则不会中断事务,这点需要开发者注意。
总结:Redis事务就是以MULTI命令开始,接受多个执行命令,然后以EXEC命令结束执行一个事务或者使用DISCARD取消当前事务。Redis事务保证了隔离性,即一个客户端在执行一个事务的时候不会被另外一个客户端打断或者改变;Redis事务还保证了原子性,即要么处理所有命令,要么不处理任何命令。从版本2.2开始,Redis允许对上述两者进行额外保证,以乐观锁定的形式,与检查和设置(CAS)操作非常相似。
Watch命令
WATCH用于为Redis事务提供检查和设置(CAS)行为。
WATCH监视key以检测对它们的更改。如果在EXEC命令之前修改了至少一个监视key,则整个事务将中止,并且EXEC返回nil应答以通知该事务失败。如果你想取消监控key使用UNWATCH命令
Wact命令主要解决了在多个客户端进行对某个key更改的时候,产生了竞争条件时,可以保证事务的原子性。
举例子:
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 55
QUEUED
127.0.0.1:6379> exec
(nil)
其中 在 执行set age 55之后,另外有一个客户端对age进行了更改操作,如果这个时候还去执行exec 将会返回一个nil,告诉客户端本次事务执行失败,如果在整个事务当中该age没有被更改,那么事务会顺利进行,exec命令之后返回ok。
订阅与发布
Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。
通过执行SUBSCRIBE命令,客户端可以订阅一个或多个频道,从而成为这些频道的订阅者( subscriber)每当有其他客户端向被订阅的频道发送消息(message)时,频道的所有订阅者都会收到这条消息。
订阅某个频道
Redis采用SUBSCRIBE命令订阅某个频道,其返回值包括客户端订阅的频道,目前已订阅的频道数量,以及接收到的消息,其中subscribe表示已经成功订阅了某个频道。
subscribe channel
subscribe 后面可以跟多个频道 名称,以此来订阅多个频道
发布消息到频道
Redis采用PUBLISH命令发送消息,其返回值为接收到该消息的订阅者的数量。
publish channel hello,guys!
如果你想发送带有空格的内容,你的内容应该用双引号引起来
订阅模式频道
模式匹配功能允许客户端订阅符合某个模式的频道,Redis采用PSUBSCRIBE订阅符合某个模式所有频道
psubscribe news.*
当使用模式匹配订阅号,发送消息,只有是以new.开头的通道,都能被该订阅客户端接受到。
列出当前活跃频道
pubsub channels
后面可以接表达式匹配通道名称
查看当前频道的订阅数量
pubsub numsub channel
返回频道名称为channel的订阅数量
取消订阅频道
unsubscribe channel
如果频道channel不指定将默认退订所有频道
主从集群
为了解决单点故障和水平扩容,redis提供了主从集群功能,帮助我们实现高可用的服务。默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
关于redis主从如何配置使用,请点击查看 点我查看
备份与持久化
Redis是一个支持持久化的内存数据库,当数据需要保存在磁盘或者备份迁移的时候,我们可以通过使用redis持久化机制完成数据的保存工作,这样可以保证redis在服务器重启之后仍然可以提供之前的数据服务。持久化方式分为两种,分别是使用RDB方式或者AOF方式。
RDB模式
也叫SNAPSHOTTING模式,快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb(如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可)。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照。另外客户端也可以使用save或者bgsave命令手动通知redis做一次快照持久化。
另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能。
而且由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,必须采用AOF持久化方式。
开启方法
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000 #60秒内容如超过10000个key被修改,则发起快照保存
优点
- RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
- RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心。
- RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
- RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
缺点
- 如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率。但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。
- 每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时, fork()可能会非常耗时,造成服务器在xx毫秒内停止处理客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。
AOF模式
AOF日志的全称是Append Only File,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。AOF比快照方式有更好的持久化性,是由于在使用AOF持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly.aof)。
开启方法
appendonly yes #启用aof持久化方式
appendfsync always #每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
appendfsync no #完全依赖os,性能最好,持久化没保证
优点
- 使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的fsync策略,比如无fsync,每秒钟一次fsync,或者每次执行写入命令时fsync。 AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。
- AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写(BGREWRITEAOF 命令): 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
- AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。
缺点
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
- AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug ) 测试套件里为这种情况添加了测试: 它们会自动生成随机的、复杂的数据集, 并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。
RDB 和 AOF 我应该用哪一个?
RDB和AOF操作都是顺序IO操作,性能都很高。而同时在通过RDB文件或者AOF日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中,所以也不会造成磁盘的随机读。一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug。在数据恢复方面:RDB的启动时间会更短,原因有两个:
一是RDB文件中每一条数据只有一条记录,不会像AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。
另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作,所以在CPU消耗上要远小于AOF日志的加载。
RDB 和 AOF 之间的相互作用:
在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。 反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE 。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。
如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行: 一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。
当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。
本教程涵盖上中下三部分,全面讲解redis各种使用特性,方法,以及高级使用教程,帮助你全面深入了解redis。
本教程是第三部分下,已经完结。