Redis进阶

持久化

当要插入一个新的数据的时候,就需要把这个数据,同时写入到内存和硬盘。当查询某个数据时,直接从内存读取,硬盘的数据只是在redis重启的时候,用来恢复内存中的数据。

代价就是消耗了更多的空间,同一份数据,存储了两遍。

Redis实现持久化的策略

RDB=》Redis DataBase

  • 定期备份:定期把我们Redis内存中的所有数据,都给写入到硬盘中,生成一个快照,一旦Reids重启,就可以根据刚刚的快照就能把内存中的数据给恢复过来

    • 手动触发:通过Redis客户端执行特定的命令,来触发快照生成

      • save:执行save的时候,Redis就会全力以赴的进行快照生成,此时会阻塞Redis客户端的其它命令
      • bgsave:background save,不会影响Redis服务器处理其他客户端的请求和命令。

      image-20230918105638023

    • 自动触发

      • 在Redis配置文件中,设置一下,让Redis每隔多长时间/每产生多少次修改就触发
      • 通过shutdown命令关闭服务器也会触发
      • redis进行主从复制的时候,主节点也会自动生成rdb快照,然后把rdb快照文件内容传输给从节点。
  • Redis生成的rdb文件是在Redis的工作目录下,也可以通过配置文件指定,rdb文件是一个二进制文件,把内存中的数据,以压缩的形式保存到这个二进制文件中。

  • Redis提供了检查rdb文件完整性的工具,redis-check-rdb

  • 当执行生成rdb镜像操作的时候,此时就会把要生成的快照数据,先保存到一个临时文件中,当这个快照生成完毕之后,再删除之前的rdb文件,把新生成的临时的rdb文件名字改成dump.rdb

  • 手动破坏rdb文件,如果通过正常流程重新启动redis服务器,此时redis服务器会在退出的时候,自动触发rdb操作,但是如果是异常重启(kill -9或者服务器断电),此时redis来不及生成rdb,内存中尚未保存到快照中的数据,就会随着重启而丢失。

  • flashall:也会删除rdb文件

  • 当redis服务器挂了之后,可以查看redis日志,默认路径在 /var/log/redis/

  1. RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6小时执行bgsave备份,并把RDB文件复制到远程机器或者文件系统中
  2. Redis加载RDB的恢复速度远快于AOF的方式。
  3. RDB方式数据没有办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork创建子进程,属于重量级操作,频繁执行成本过高
  4. RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能有风险。

最大的问题:不能实时的持久化保存数据,两次生成快照之间实时的数据可能会丢失

AOF=》Append Only File

类似mysql中的binlog,会把用户的每个操作,都记录到文件中,当redis重新启动的时候,就会读取AOF文件中的内容,用来恢复数据,当开启AOF,就不会读取RDB了,以AOF为主。

在配置文件中更改 appendonlyyes即可开始

image-20230919094048089

使用AOF之后,又要写内存,又要写硬盘,还能和之前一样快吗?

  1. AOF机制并非直接让工作线程把数据写入硬盘,而实现写入一个内存中的缓冲区,积累到一定的数据之后,才写一次硬盘,大大减少了写硬盘的次数。并且只是顺序写,而不是随机写。
  2. Redis给出了一些选项,让程序员,根据实际情况来决定怎么取舍(也就是提供了不同的缓冲区刷新策略)。
    1. 刷新频率越高,性能影响就越大,刷新频率越低,性能影响就越大
    2. always:命令写入aof_buf后调用fsync同步,每一条命令保存一次
    3. erversec:每一秒保存一次
    4. no:由操作系统来写入,redis不管
  3. Redis就存在一个机制,能够针对aof文件进行整理操作。这个整理就是能够剔除其中的冗余操作,并且合并了一些操作,达到给aof文件瘦身。

AOF的触发时机

  • 手动触发:调用bgrewriteaof命令
  • 自动触发:根据配置文件中的参数自动确定触发时机
    • auto-aof-rewrite-min-size:表示触发重写时AOF的最小文件大小,默认为64MB。
    • auto-aof-rewrite-percentage:表示当前AOF占用大小相比较上次重写时增加的比例。

AOF重写流程

image-20230919101454418

父进程仍然负责接受请求,子进程负责针对aof文件进行重写,重写的时候,不关心aof文件中原来都有啥,只是关心内存中最终的数据状态,子进程只需要把内存中当前的数据,获取出来,以AOF的格式写入到一个新的AOF文件中。

子进程只包含了fork之前的数据,fork之后的数据是没有的。

子进程写新的AOF文件的同时,父进程会把新接收到的请求产生的AOF数据先写入到缓冲区再刷新到旧的AOF文件中,并且父进程里又准备了一个aof_rewrite_buf,专门存放fork之后的数据,也就是父进程要写两个缓冲区。等子进程把fork之前的数据写完之后,会通过一个信号通知父进程告诉父进程写完了,父进程此时就会将aof_rewrite_buf中的数据写到新的AOF文件中。

都写完之后就可以用新的AOF文件代替旧的AOF文件。

  • 如果,在执行bgrewriteaof的时候,当前redis正在进行aof重写,此时不会再执行aof重写。
  • 如果,在执行bgrewriteaof的时候,当发现redis正在生成rdb文件,此时aof重写操作就会等待rdb快照生成完毕之后,再进行aof重写。

rdb对于fork之后的新数据,直接置之不理。aof则对于fork之后新数据,采用aof_rewrite_buf缓冲区来处理。

混合持久化

AOF本来是按照文本的方式来写入文件的。但是文本的方式写入文件,后续加载的成本是比较高的,所以redis就引入了“混合持久化”的方式,结合了rdb和aof的特点。

按照aof的方式,每一个请求/操作,都记录入文件。在触发aof重写之后,就会把当前内存的状态按照rdb二进制格式写入到新的aof文件中。后续再进行的操作,仍然是按照aof文本的方式追加到文件后面。

当redis上同时存在aof文件和rdb快照的时候,以aof为主,rdb直接被忽略。aof包含的数据比rdb更全。

image-20230919120247064

事务

Redis的事务,主要意义是为了打包,避免其它客户端的命令,插队插到中间。Redis如果是按照集群模式部署,不支持事务。

Redis中的ACID和MySQLACID的区别

  • 不具备原子性(原子性以MySQL的原子性为主,不仅要能保证一次全部执行,还要能够保证执行成功和回滚操作),把多个操作打包到一起,要么全都执行,要么全都不执行,不保证成功。
  • 不具备一致性,redis没有约束,也没有回滚机制,事务执行过程中如果某个修改操作失败,就可能引起不一样的情况。
  • 不具备持久性,redis本身就是内存数据库,数据是存储早内存的,虽然redis提供了持久化操作,但是和事务没有什么直接关系
  • 不涉及隔离性,redis是一个单线程模型的服务器程序,所有的请求/事务,都是串行执行的。

Redis中实现事务,是引入了队列(每个客户端都有一个),开启驶入的时候,此时客户端输入的命令,就会发给服务器并且进入这个队列中(而不是执行),当遇到了“执行事务”命令的时候,此时就会把队列中这些任务按照顺序依次执行。

Redis中事务的命令

multi:开启事务

exec:执行事务

discard:放弃当前事务

watch:必须搭配事务使用,并且必须在multi之前使用,watch一个key,会给key设定一个版本号,在执行事务的时候,会进行判定,如果当前key在事务开启到最终执行这个过程中,没有别的客户端修改,才能真正设置,key的版本号与最开始watch时不一样,则表明其它客户端修改过了,因此丢弃当前事务,exec返回nil

Redis分布式部署方式

主从模式

在若干个redis节点中,有的是“主”节点,有的是“从”节点,从节点上的数据要跟随主节点变化,从节点的数据要和主节点的数据保持一致。就是把主节点上的数据复制到从节点,主节点上有任何修改都会同步到从节点中。

从节点就是主节点的副本。在redis主从模式中,从节点上的数据,不允许修改,只能读取数据。

主从模式主要是针对读操作,进行并发量和可用性的提高,实际业务中读操作往往比写操作更频繁。

部署主从

  • 配置从节点:配置文件中加上 slaveof masterip masterport,然后从节点使用该配置文件启动,即可成为从节点。
  • 查看主从结构信息:在redis-cli中使用info replication命令即可看到当前的角色,从节点上可以看到主节点的ip,port,主节点的id。主节点可以看到当有多少个从节点,数据同步的进度,以及网络的延迟。
  • 断开主从复制关系:slave no one,当从节点断开主从数据,它就不属于其它节点了,里面有的数据不会抛弃,但是主节点进行修改,从节点就不会继续修改了。

主从复制的基本流程

image-20230919185422879

redis提供了一个psync命令,完成数据同步的过程,这个命令不需要手动执行,redis会在建立好主从关系之后,自动执行psync,从节点负责执行psync,从节点从主节点这边拉去数据。

语法:psync replicationid offset

replicationid:主节点在启动的时候生成的一个复制节点,即使是同一个主节点,每次重启生成的replicationid,从节点和主节点建立了复制关系,就会从主节点这边获取到repilicationid。使用info replication,即可看到。

image-20230920100943026

offset:主节点和从节点都会维护这个偏移量,主节点会把修改命令,每个命令的字节数,进行累加。从节点的偏移量,描述了现在从节点数据同步到哪里了,具体的同步进度。

pysnc:可以从主节点获取全量数据,也可以获取一部分数据,如果offset是-1,就是获取全量数据,如果写一个具体的正整数,则是从当前偏移量位置来进行获取。

不是从节点索要那部分,主节点就给那部分,得看主节点方不方便,如果主节点不方便,就只能全量返回。

image-20230920101838163

全量复制

在复制的时候,如果主节点收到了新的数据,那么这部分新数据也会通过一系列手段,传输给从节点。

如果从节点开启了aof,在加载数据的过程中,从节点会产生大量的aof日志,由于从节点收到的是大批量的数据,此时产生的aof日志,可能存在一定的冗余信息,因此针对aof日志进行整理,也是必要的过程。

新版redis也支持diskless的方式来传输数据,但是也不能完美的解决复制时的问题。

image-20230920102449003

部分复制:全量复制的特殊情况,优化手段,目的和全量复制一样。

image-20230920163959347

实时复制:从节点,已经和主节点同步好了数据,但是之后,主节点这边也会源源不断的收到新的修改数据的请求,主节点上的数据就会随之改变。也需要能够同步给从节点。

主从复制的缺点:

  1. 从机多了,复制数据的延时非常明显。
  2. 主机挂了,从机不会升级成主机,只能通过人工干预的方式更换主节点。

从节点和主节点之间断开连接的两种情况:

  1. 从节点使用slaveof no one主动和主节点断开连接,这个时候,从节点就能够晋升成主节点
  2. 主节点挂掉了,这个时候从节点不会晋升成主节点,必须通过人工干预的方式,恢复主节点(哨兵机制就是为了解决这个问题)

主从+哨兵(sentinel)

哨兵机制是通过独立的进程来体现的,和之前的redis server是不同的进程。redis-sentinel不负责存储数据,只是对其他的redis-server进程起到监控的作用。

主节点无法启动,手动恢复节点:

  1. 把选中的从节点,通过slaveof no one,将从节点转换为主节点
  2. 把其他的从节点,修改slaveof的主节点ip port,连上新的主节点
  3. 告知客户端,客户端能够连接新的主节点,用来完成修改数据的操作
  4. 把之前挂了的主节点,修改之后,就可以作为一个新的从节点,挂到这组机器当中

自动恢复:

  1. 多个sentinel节点,分布在不同的服务器上监听所有的redis服务器
  2. 如果从节点挂了没关系, 如果主节点挂了,哨兵就要发挥作用了,但是为了防止误判(可能由于sentinel节点网络波动,没有收到主节点的心跳包,误判主节点挂掉了),所以需要多个sentinel节点共同判断是否挂掉。
  3. 主节点真的挂掉了,此时多个sentinel节点中选择出一个leader,由这个leader去执行主节点的更变。
  4. 这个sentinel的leader,会根据一定规则从从节点中选择一个节点执行slaveof no one,将该从阶段转换为主节点,然后将其它从节点的主节点更变为这个新的主节点。

哨兵的核心功能:

  1. 监控
  2. 自动的故障转移

在分布式系统中,要避免使用”单点”

哨兵配置

port 26379
dir /tmp
#              主节点名称 主节点IP    端口  法定票数
sentinel monitor mymaster 172.31.0.3 6379 2
sentinel auth-pass mymaster redis_pwd
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes

每个哨兵都需要不同的配置文件,因为哨兵在运行过程中会重写配置文件

哨兵重新选取主节点的流程

  1. 主观下线:哨兵通过心跳包,判定redis服务器是否正常工作,如果心跳包没有如约而至,那么当前哨兵就认为redis服务器挂了,但是此时还不能排除网络波动的影响,因此就只能单方面认为这个redis节点挂了。
  2. 客观下线:多个哨兵都认为主节点挂了,认为挂了的哨兵节点数达到法定票数,哨兵们就认为这个主节点是客观下线。
  3. 多个哨兵节点,选出一个leader节点,由这个leader节点进行选择一个从节点,作为新的主节点。
  4. leader选举完毕,需要挑选一个从节点,作为新的主节点
    1. 优先级:每个redis数据节点,都会在配置文件中,有一个优先级的设置,slave-priority 优先级高的从节点就会胜出
    2. offset 最大:offset表明从节点从主节点同步数据的进度,数值越大说明从节点的数据和主节点越接近
    3. run id:redis启动时随机生成的一串数字,但是走到这一步,就说明优先级和offset都一样,那么选谁都可以。

注意事项

  1. 哨兵节点不能只有一个
  2. 哨兵节点最好是奇数个,方便选举leader
  3. 哨兵节点不负责存储数据
  4. 哨兵+主从复制解决的问题是“提高可用性”,不能解决“数据极端情况下写丢失”的问题
  5. 哨兵+主从复制不能提高数据的存储容量,当我们需要存的数据接近或者超过机器的物理内存,这样的结构就难以胜任。

集群模式

广义的集群:只要是多个机器,构成了分布式系统,都可以称为一个“集群”

狭义的集群:redis提供的集群模式,这个集群模式之下,主要是解决存储空间不足的问题。

哨兵模式提高了系统的可用性,但是本质上哈市redis主从节点存储数据,其中就要求一个主/从节点,就得存储整个数据的全集。此处的问题的关键,就是引入多台机器,每台机器存储一部分数据。

把数据分成多份,具体怎么分:

数据分片算法
  1. 哈希求余
  2. 一致性哈希
  3. 哈希槽分区

集群模式故障处理

  1. 故障判定,需要识别出某个节点是否是挂了。主观下线、客观下线。
  2. 如果下线的是从节点,就不需要进行处理,如果下线的是主节点,那么该节点的从节点就会触发故障迁移
  3. 从节点会进行休眠,休眠时间为500ms+随机时间[0,500ms]+排名*1000ms,排名的规则,offset越大排名越高
  4. 当从节点从休眠中恢复过来,会对集群中的所有节点发起拉票,但是只有集群中的主节点可以投票,每个主节点只有一票。
  5. 投票完毕,票数最多的从节点会成为新的主节点

以下三种情况会出现集群宕机:

  • 某个分片,所有的从节点和主节点都挂了

  • 某个分片,主节点挂了,但是没有从节点

  • 超过半数的master节点都挂了

前两种情况,都是分片无法提供数据服务了。最后一种情况表示集群遇到了很大的故障问题。

集群扩容

集群扩容操作,是一件风险较高,成本较大的操作

在搬运slows/key的过程中,客户端是否能访问redis集群?

搬运key的时候大部分key是不用搬运的,针对这些未搬运的key,此时可以正常访问的,针对这些正在搬运中的key,是有可能出现访问出错的情况的。

缓存

缓存使用的注意事项:

  1. 缓存穿透:访问的key在redis和数据库中都不存在
  2. 缓存雪崩:大量的key在短时间内一起过期
  3. 缓存击穿:缓存雪崩的特殊情况,热点key过期,大量请求打到数据库上

分布式锁

  1. value设置为服务器编号
  2. 看门狗
  3. redlock
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值