从零开始的Redis学习 | 3_Redis发布订阅,事务,持久化

这是我之前写的:

Jedis 使用及 StringRedisTemplate 常用方法

阿里大鱼短信服务 --- 发送验证码、短信通知

Java 集成阿里大鱼平台短信服务发送验证码到手机

Java 集成阿里大鱼平台短信服务发送验证码 --- 补齐注册部分

Java连接Redis,以及短信验证那些,这边就跳过了。感兴趣的看我以前的博客,都是比较简单,包看包会。

1. Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

当有新消息通过 PUBLISH 命令发送给频道 channel1 时,这个消息就会被发送给订阅它的三个客户端:

1.1 实例

以下实例演示了发布订阅是如何工作的,需要开启两个 redis-cli 客户端。

  • 创建订阅频道名为 runoobChat。

    127.0.0.1:6379> SUBSCRIBE runoobChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "runoobChat"
    3) (integer) 1
    # 以下是发布两次消息后,订阅频道接收的信息
    1) "message"
    2) "runoobChat"
    3) "Redis PUBLISH test"
    1) "message"
    2) "runoobChat"
    3) "Learn redis by runoob.com"
    
  • 开第二个redis客户端,在同一个频道 runoobChat发布两次消息,订阅者就能接收到消息。

    127.0.0.1:6379> PUBLISH runoobChat "Redis PUBLISH test"
    (integer) 1
    127.0.0.1:6379> PUBLISH runoobChat "Learn redis by runoob.com"
    (integer) 1
    127.0.0.1:6379>
    

1.2 Redis 发布订阅命令

命令描述
PSUBSCRIBE pattern [pattern ...]订阅一个或多个符合给定模式的频道。
PUBSUB subcommand [argument [argument ...]]查看订阅与发布系统状态。
PUBLISH channel message将信息发送到指定的频道。
PUNSUBSCRIBE [pattern [pattern ...]]退订所有给定模式的频道。
SUBSCRIBE channel [channel ...]订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel ...]]只退订给定的频道。

2. Redis 事务

2.1 Redis事务定义

  • Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • Redis 事务的主要作用就是串联多个命令防止别的命令插队。

Redis 事务可以一次执行多个命令,并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历一下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

2.2 Multi、Exec、discard

命令描述
DISCARD取消事务,放弃执行事务块内的所有命令。
EXEC执行所有事务块内的命令。
MULTI标记一个事务块的开始。
UNWATCH取消 WATCH 命令对所有 key 的监视。
WATCH key [key ...]监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
  • 从输入 Multi 命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入 Exec 后,Redis 会将之前的命令队列中的命令依次执行。
  • 组队的过程中可以通过 discard 来放弃组队。

2.3 事务的错误处理

  • 组队中某个命令出现了报告错误,执行时整个的所有队伍都会被取消。

  • 如果执行阶段某个命令报出了错误,则只有报差的命令不会被执行,而其他的命令都会执行,不会回滚。

2.4 为什么要做成事务

场景一1:一个账户多台移动设备登陆,同时去参加双十一抢购

  • 悲观锁:总是假设最坏的情况。 每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。 传统的关系型数据库里边就用到了很多这种锁机制,比如读锁,写锁等,都是在做操作之前先上锁。

    乐观锁适用于写比较少的情况,即冲突真的很少发生,这样可以省去锁的开销,从而提高系统的吞吐量。

  • 乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。 乐观锁适用于写比较少的情况,即冲突真的很少发生,这样可以省去锁的开销,从而提高系统的吞吐量。 悲观锁使用于写比较频繁的情况,即经常产生冲突,上层引用会不断的进行重试,这样反倒降低了性能,所以使用锁比较合适。

    悲观锁使用于写比较频繁的情况,即经常产生冲突,上层引用会不断的进行重试,这样反倒降低了性能,所以使用锁比较合适。

2.5 三特性

单独的隔离操作

  • 事务中的所有命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

没有隔离级别的概念

  • 队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在"事务内的查询要看到事务里的更新,在事务外查询不能看到"这个让人万分头痛的问题。

不保证原子性

  • Redis 同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

3. Redis 持久化

3.1 RDB (Redis DataBase)

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。

  • 备份是如何执行的

    Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

  • 关于 fork

    在 Linux 程序中,fork() 会产生一个和父进程完全相同的子进程,但子进程在此后多会 exec系统调用,处于效率考虑,Linux 中引入了 "写时复制技术",一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段内容要发生变化时,才会将父进程的内容复制一份给子进程。

  • rdb的保存文件

    在 redis.conf中配置文件名称,默认为 dump.rdb

  • rdb的保存策略

    save <seconds> <changes>

  • 手动保存快照

  • rdb的保存文件

    在 redis.conf 中配置文件名称,默认为 dump.rdb。

    rdb文件的保存路径,也可以修改。默认为 Redis 启动时命令行所在的目录下。

  • rdb的保存策略

    # 在多少秒之内完成了多少次对数据库的修改,然后就会进行持久化。
    save <seconds> <changes>
    
  • 手动保存快照

    bgsave 命令用于在后台异步保存当前数据库的数据到磁盘。

    BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

    save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。

  • stop-writes-on-bgsave-error yes

    当 Redis 无法写入磁盘的话,直接关掉 Redis 的写操作。

  • rdbcompression yes

    进行 rdb 保存时,将文件压缩。

  • rdbchecksum yes

    在存储快照后,还可以让 Redis 使用 CRC 64算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

  • rdb 的备份

    先通过 config get dir 查询rdb文件的目录

    将 *.rdb的文件拷贝到别的地方

  • rdb 的恢复

    关闭 Redis

    先把备份的文件拷贝到工作目录下

    启动 Redis,备份数据会直接加载

  • rdb 的优点

    节省磁盘空间

    恢复速度快

  • rdb 的缺点

    虽然 Redis 在 fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。

    在备份周期在一定间隔时间做一次备份,所以如果 Redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。

3.2 AOF (Append Only File)

  • 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

  • AOF 默认不开启,需要手动在配置文件中配置

  • 可以在 redis.conf 中配置文件名称,默认为 appendonly.aof

  • AOF 文件故障备份

    AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载。

    AOF 和 RDB 同时开启,系统默认取 AOF 的数据。

  • AOF 文件故障恢复

    AOF 文件的保存路径,同RDB的路径一致。

    如遇到 AOF 文件损坏,可通过

    redis-check-aof --fix appendonly.aof 进行恢复
    
  • AOF 同步频率设置

    始终同步,每次Redis 的写入都会立刻记入日志

    每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。

    不主动进行同步,把同步时机交给操作系统。

  • Rewrite

    AOF 采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当 AOF 文件的大小超过所设定的阙值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令 bgrewriteaof。

  • Redis如何实现重写?

    AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set 语句。重写 aof 文件的操作,并没有读取旧的 aof 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 aof 文件,这点和快照有点类似。

  • 何时重写

    重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定负担的,因此设定 Redis 要满足一定条件才会进行重写。

  • 系统载入时或者上次重写完毕时,Redis 会记录此时 AOF 大小,设为 base_size,如果 Redis 的 AOF 当前大小 >= base_size + base_size*100%(默认)且当前大小>=64mb(默认)的情况下,Redis会对 AOF 进行重写。

  • AOF 的优点

    备份机制更稳健,丢失数据概率更低。

    可读的日志文本,通过操作 AOF 稳健,可以处理误操作。

  • AOF 的缺点

    比起 RDB 占用更多的磁盘空间。

    回复备份速度要慢。

    每次读写都同步的话,有一定的性能压力。

    存在个别 Bug,造成恢复不能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值