乐趣区

初识Redis一

前言

今天来讲讲 redis 以下知识点,如有不当请多指教!

  • Redis 持久化
  • 主从复制
  • Sentinel 机制
  • Redis Cluster

Redis 持久化

redis 是基于 内存 的,如果不想办法将数据保存在硬盘上,一旦 redis 重启(退出 / 故障),内存的数据将会全部丢失。

Redis 提供了两种持久化方法:

RDB(基于快照),将某一时刻的所有数据保存到一个 RDB 文件中。
AOF(append-only-file),当 Redis 服务器执行写命令的时候,将执行的写命令保存到 AOF 文件中。

RDB

保存某个时间点的全量数据快照

  • 手动触发

    SAVE:阻塞 Redis 的服务器进程,知道 RDB 文件被创建完毕
    BGSAVE:Fork 出一个子进程来创建 RDB 文件,不阻塞服务器进程,使用 lastsave 指令可以查看最近的备份时间

  • 自动触发

    根据 redis.conf 配置里的 save m n 定时触发(用的是 BGSAVE)
    主从复制时,主节点自动触发
    执行 Debug Relaod
    执行 Shutdown 且没有开启 AOF 持久化

注意:Redis 服务器在启动的时候,如果发现有 RDB 文件,就会自动载入 RDB 文件(不需要人工干预)

RDB 的优缺点

优点:
RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照,适合备份,全量复制等场景。
且加载 RDB 恢复数据远远快于 AOF 的方式。

缺点:
没办法做到实时持久化 / 秒级持久化,因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。

RDB 的相关配置

// 在 n 秒内修改 m 条数据时创建 RDB 文件
save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes  //bgsave 出错时停止写入
rdbcompression yes  // 压缩 RDB 文件
rdbchecksum yes   // 校验文件是否损坏

AOF

与 RDB 不一样的是,AOF记录的是命令,而不是数据。

如何开启 AOF?
只需在配置文件中将 appendonly 设置为 yes 即可。

AOF 的工作流程:

1、所有的写入命令追加到 aof_buf 缓冲区中。
2、AOF 会根据对应的策略向磁盘做同步操作。刷盘策略由 appendfsync 参数决定。
3、定期对 AOF 文件进行重写。重写策略由 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 两个参数决定。

appendfsync 参数有如下取值:

appendfsync always     # 每次有数据修改发生时都会写入 AOF 文件。appendfsync everysec   # 每秒钟同步一次,该策略为 AOF 的默认策略。appendfsync no         # 从不同步。高效但是数据不会被持久化。

AOF 重写

为什么要重写?
重写后可以加快节点启动时的加载时间

重写后的文件为什么可以变小?
进程内超时的数据不用再写入到 AOF 文件中
多条写命令可以合并为一个

重写条件

1、手动触发
     直接调用 bgrewriteaof 命令

2、自动触发

先来看看有关参数:
auto-aof-rewrite-min-size:执行 AOF 重写时,文件的最小体积,默认值为 64MB。
auto-aof-rewrite-percentage:执行 AOF 重写时,当前 AOF 大小 (即 aof_current_size) 和上一次重写时 AOF 大小 (aof_base_size) 的比值。

只有当 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 两个参数同时满足时,才会自动触发 AOF 重写。

后台重写

Redis 将 AOF 重写程序放到 子进程 里执行 (BGREWRITEAOF 命令),像 BGSAVE 命令一样 fork 出一个子进程来完成重写 AOF 的操作,从而不会影响到主进程。

AOF 后台重写是不会阻塞主进程接收请求的,新的写命令请求可能会导致 当前数据库和重写后的 AOF 文件的数据不一致
为了解决数据不一致的问题,Redis 服务器设置了一个AOF 重写缓冲区,当子进程完成重写后会发送信号让父进程将 AOF 重写缓冲区的数据写到新的 AOF 文件。

RDB 和 AOF 比较

RDB 和 AOF 并不互斥,它俩可以同时使用。

RDB 的优点:载入时恢复数据快、文件体积小。
RDB 的缺点:会一定程度上丢失数据(因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。)

AOF 的优点:丢失数据少 (默认配置只丢失 1 秒 的数据)。
AOF 的缺点:恢复数据相对较慢,文件体积大

如果 Redis 服务器同时开启了 RDB 和 AOF 持久化,服务器会 优先使用 AOF 文件来还原数据(因为 AOF 更新频率比 RDB 更新频率要高,还原的数据更完善)

主从复制

单机有什么问题?

单机即在一台机器上部署一个 redis 节点,主要会存在以下问题:
1、如果发生机器故障,例如磁盘损坏,主板损坏等,未能在短时间内修复好,客户端将无法连接 redis
2、Redis 的内存是有限的,可能放不下那么多的数据
3、单台 Redis 支持的并发量也是有限的

如图上面是 master 节点,下面是slave 节点,即主节点和从节点。从节点也是可以对外提供服务的,主节点是有数据的,从节点可以通过复制操作将主节点的数据同步过来,并且随着主节点数据不断写入,从节点数据也会做同步的更新。
整体起到的就是数据备份的效果

除了一主一从模型之外,redis 还提供了一主多从的模型,也就是一个 master 可以有多个 slave,也就相当于有了多份的数据副本。

读写分离

除了作为数据备份,主从模型还能做另外一个功能,就是读写分离。
master 节点负责提供写服务,slave 节点提供读服务,而将数据读取的压力进行分流和负载,分摊给所
有的从节点。

主从复制的配置

  1. slaveof 命令

slaveof 198.162.88.66 6379

执行该命令使当前 redis 节点成为指定 redis 节点的从节点,此复制命令是 异步 进行的,redis 会自动进行后续数据复制的操作

如果想取消从节点可以执行 slave of on one 命令

2、修改配置

# 配置主节点的 IP 和端口号
slaveof ip port
# 从节点只做读的操作,保证主从数据的一致性
slave-read-only yes

runid 和复制偏移量

redis 每次启动的时候都会有一个随机的 ID,作为一个标识,这个 ID 就是 runid,当然重启之后值就改变了。
假如端口为 6380 的 redis 去复制 6379,知道 runid 后,在 6380 上做一个标识,如果 runid 改变了,说明主可能重启了或者发生了其它变化,这时候就可以做一个全量复制把数据同步过来。或者第一次启动时根本不知道 6379 的runid,也会进行全量复制

偏移量:数据写入量的字节
比如主执行 set hello world,就会有一个偏移量,然后从同步数据,也会记录一个偏移量
当两个偏移量达到一致时候,实际上数据就是完全同步的状态。

全量复制

全量复制主节点会将 RDB 文件也就是当前状态去同步给 slave,在此期间主节点新写入的命令会单独记录起来,然后当 RDB 文件加载完毕之后,会通过偏移量对比将这个期间产生的写入值同步给 slave,这样就能达到数据完全同步的效果

全量复制过程
  1. 在其内部有一条命令 psync,是做同步的命令,它可以完成全量复制和部分复制的功能,当启动 slave 节点时,它会发送psync 命令给主节点,需要传递两个参数,runidoffset(偏移量),也就是从节点向主节点传递主节点的 runid 以及自己的偏移量,对于第一次复制而言,就直接传递?和 -1,当然这个参数是由 slave 内部传的。
  2. master 接收到命令后知道从希望做全量复制,主就会将自己的 runid 和 offset 传递给从节点
  3. slave 节点保存 master 的基本信息
  4. master 执行 bgsave 生成 RDB 文件,并且在此期间新产生的写入命令会被记录到repl_back_buffer(复制缓冲区)
  5. 主节点向从节点传输 RDB 文件
  6. 主节点向从节点发送复制缓冲区内容
  7. 清空从节点旧的数据
  8. 从节点加载 RDB 文件到内存中,同时加载缓冲区数据

执行全量复制除了开销大之外,还会有个问题:
假如 master 和 slave 网络发生了抖动,那一段时间内这些数据就会丢失,对于 slave 来说这段时间 master 更新的数据是不知道的。最简单的方式就是再做一次全量复制,从而获取到最新的数据,在 redis2.8 之前是这么做的。

部分复制

redis2.8 之后提供部分复制,如果发生类似网络抖动,可以有这样一种机制将这种损失降低到最低,如何实现的?

部分复制过程
  1. 如果发生了抖动,相当于连接断开了
  2. 主节点会将写命令记录到缓冲区(repl_back_buffer)
  3. 当 slave 再次去连接 master 时候,就是说网络抖动结束之后,会触发部分复制
  4. 从节点会执行 pysnc 命令,将当前自己的 offset 和主的 runid 传递给 master
  5. 如果发现传输的 offset 偏移量是在 buffer 内的,如果不在内就说明你已经错过了很多数据,buffer 也是有限的,默认是 1M(建议调为 10M),会将 offset 开始到队列结束的数据同步给从节点。这样 master 和 slave 就达到了一致。

通过部分复制有效的降低了全量复制的开销。

Redis Sentinel

简介

Sentinel(哨兵)是用于监控 redis 集群中 master 状态的工具,是 Redis 的高可用性解决方案,sentinel 哨兵模式已经被集成在 redis2.4 之后的版本中。
Sentinel 系统可以监视一个或者多个 redis master 服务,以及这些 master 服务的所有从服务;当某个 master 服务下线时,自动将该 master 下的某个从服务升级为新的 master 服务,替代已下线的 master 服务继续处理请求,等挂掉的主服务器重连上来,会将它变成从服务器。

三个定时任务

Sentinel 在内部有 3 个定时任务
1)每隔 10 秒——每个 sentinel 会对 master 和 slave 执行 info 命令 ,这个任务主要用来发现 slave 节点和确认主从关系。
2)每隔 2 秒—— 每个 sentinel 通过 master 节点的 channel 交换信息(pub/sub)。master 节点上有一个名为 __sentinel__:hello 的发布订阅的频道。sentinel 节点通过__sentinel__:hello 频道进行信息交换 (对节点的 ” 看法 ” 和自身的信息),达成共识。
3)每隔 1 秒—— 每个 sentinel 对其他 sentinel 和 redis 节点执行 ping 操作(相互监控),这个其实是一个心跳检测,是失败判定的依据。

主观 / 客观下线

判断主服务器是否下线有两种情况:

主观下线

Sentinel 会以每秒一次的频率向与它创建命令连接的实例 (包括主从服务器和其他的 Sentinel) 发送 PING 命令,通过 PING 命令返回的信息判断实例是否在线
如果一个主服务器在 down-after-milliseconds 毫秒内连续向 Sentinel 发送无效回复,那么当前 Sentinel 就会主观认为该主服务器已经下线了。

客观下线

当 Sentinel 将一个主服务器判断为主观下线以后,为了确认该主服务器是否真的下线,它会向同样监视该主服务器的 Sentinel 询问,看它们是否也认为该主服务器是否下线。
如果足够多的 Sentinel 认为该主服务器是下线的,那么就判定该主服务为客观下线,并对主服务器执行故障转移操作。

conf 文件配置

在 redis-sentinel 的 conf 文件里有这么两个配置:

1)sentinel monitor <masterName> <ip> <port> <quorum>

四个参数含义:
masterName这个是对某个 master+slave 组合的一个区分标识。
ipport 就是 master 节点的 ip 和 端口号。
quorum这个参数是进行客观下线的一个依据,意思是 至少有 quorum 个 sentinel 主观的认为这个 master 有故障,才会对这个 master 进行下线以及故障转移。因为有的时候,某个 sentinel 节点可能因为自身网络原因,导致无法连接 master,而此时 master 并没有出现故障,所以这就需要多个 sentinel 都一致认为该 master 有问题,才可以进行下一步操作,这就保证了公平性和高可用。

2)sentinel down-after-milliseconds <masterName> <timeout>

这个配置其实就是进行主观下线的一个依据,表示:如果这台 sentinel 超过 timeout 这个时间都无法连通 master 包括 slave 的话,就会主观认为该 master 已经下线。

领导者选举

当一个主服务器被认为客观下线以后,此时需要一个 Sentinel 服务器对该服务器进行处理,因此监视这个下线的主服务器的各个 Sentinel 会进行协商,选举出一个领头的 Sentinel,领头的 Sentinel 会对下线的主服务器执行故障转移操作。

选举领头 Sentinel 的规则也比较多,总的来说就是 先到先得(哪个快,就选哪个)

故障转移处理

  1. 多个 sentinel 发现并确认 master 有问题
  2. 选举出一个 sentinel 作为领导
  3. 选出一个 slave 作为 master
  4. 通知其余 slave 成为新的 master 的 slave
  5. 通知客户端主从变化
  6. 等待老的 master 复活成为新 master 的 slave

注意:挑选某一个从服务器作为主服务器也是有策略的,大概如下:

(1)跟 master 断开连接的时长
(2)slave 优先级
(3)复制 offset 大小
(4)run id

Redis Cluster

Redis3.0 版本之前,可以通过 Redis Sentinel(哨兵)来实现高可用,从 3.0 版本之后,官方推出了Redis Cluster,它的主要用途是实现数据分片,并且实现高可用。

在 Redis Sentinel 模式中,每个节点需要保存全量数据,冗余比较多,而在 Redis Cluster 模式中,每个分片只需要保存一部分的数据,

Redis Cluster 每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。

Redis Cluster 的具体实现细节是采用了 Hash 槽 的概念,集群会预先分配 16384 个槽,并将这些槽分配给具体的服务节点,通过对 Key 进行 CRC16(key)%16384 运算得到对应的槽是哪一个,从而将读写操作转发到该槽所对应的服务节点。当有新的节点加入或者移除的时候,再来迁移这些槽以及其对应的数据。在这种设计之下,我们就可以很方便的进行动态扩容或缩容。

Redis Cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。

有关 redis 集群的安装配置在这里就不多说了,在这里对先对 redis cluster 有个了解,日后再来补充。

参考

从零单排学 Redis
Redis Cluster

退出移动版