vlambda博客
学习文章列表

快速上手redis主从复制和哨兵

1、redis性能瓶颈在哪里?

首先说说redis为什么这么快。主要有以下几点原因:

  • 纯内存操作;

  • 单线程操作,避免频繁上下文切换;

  • 采用IO多路复用模型;

  • 纯ANSI C语言编写;

由于redis是纯内存操作并且采用了IO多路复用模型,因此redis的性能瓶颈不应该是CPU,内存和网络延迟更应该是redis的性能瓶颈。

2、redis为什么需要高可用?

需要高可用的原因主要为:

  • 单点故障:因此需要将数据生成多个副本分布在不同的机器上;

  • 内存容易成为瓶颈:因此需要对数据进行分片;

redis有三种高可用方案,分别是:

  • 主从复制

  • 哨兵

  • 集群

3、主从复制

主库:可以读写,将数据同步给从库。

从库:只能读,如果修改从库数据会报错(将slave-read-only设置为no则不会报错)。

一个主库可以有多个从库,但一个从库只能有一个主库。从库也可以作为主库。

主从复制可以同来实现读写分离,比如在电商系统中,读的压力大于写,那么可以配置一主多从的redis高可用架构,主库用来写,多个从库用来读。

由于主从复制不能有多个主库,因此当写压力过大时一主多从不再满足需求,此时需要使用redis集群。


如何配置主从复制?两种方法如下:

  • 在从库的redis.conf中配置slaveof host port;

  • 在从库执行slaveof host port命令;

由于配置主从复制比较简单,我这里就不演示了。


主从复制配置好后,可以使用info section命令查看关于Redis服务器的各种信息和统计数值。比如查看复制相关信息,可以使用info replication。

在一个主库上执行info replication如下所示。

127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=14,lag=0
master_replid:0dca9fd8627630d1058cd3ae740c39edc03f07c5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14


也可以使用role命令查看节点角色。

如果当前库已经是某个主库的从库,那么执行slaveof host port 将使当前库停止对旧主库的同步,丢弃旧数据集,转而开始接收新主库的同步。


另外,对一个从库执行命令slave no one将使得这个从库关闭复制功能,并从从库转变回主库,原来同步所得的数据集不会被丢弃。


利用slave no one不会丢弃同步所得数据集这个特性,可以在主库失败的时候,将从库作为新的主库,从而实现无间断运行。

3.1、主从复制原理

a)复制初始化
  1. 从库启动后,向主库发生SYNC命令;

  2. 主库接收到命令并在后台保存RDB快照(异步),并将保存快照期间接收到的客户端命令缓存起来,然后一起发给从库;

  3. 从库会将收到的内容写入磁盘临时文件,最后用临时文件替换旧的RDB文件(在写临时文件期间,从库不会阻塞客户端请求,并且用同步前的数据响应客户端,可以在redis.conf中配置slave-serve-stale-data为no来让从库在同步完成前对除了info和slave之外的所有命令响应错误);

b)复制同步阶段

主库每当收到写命令就将命令同步给从库(同步的内容就是redis通信协议的内容)。

c)增量复制

主从库断开连接后,从库再次连接主库时,不必再进行一次复制初始化,而是直接增量复制(redis2.8版本开始支持)。

原理:

  1. 在复制同步阶段,主库每接收到一个命令,都会将该命令放到积压队列中,并记录好偏移量,从库同步数据时,也会记录好偏移量;

  2. 增量复制使用psync命令代替sync命令,且psync命令会带两个参数,psync 主库id 断开前最新的命令偏移量;

  3. 主库收到psync命令后,会判断从库传过来的主库id与自身id是否相等;如果相等,则再判断从库传过来的偏移量是否在积压队列中;

  4. 如果上述两个条件有一个不满足,则不满增量复制,而进行一次复制初始化;

d)无硬盘复制

复制初始化时,由于主库会进行快照生成RDB文件,因此会影响性能。redis2.8版本支持无硬盘复制(redis.conf中将repl-diskless-sync设置为yes),主库直接通过网络将数据发生给从库。

3.2、异步复制导致主从库数据不一致怎么解决?

redis主从复制不保证强一致性,而是保证最终一致性。

另外,可以在主库的redis.conf中可以做如下配置。

# 允许最小连接的从库数
min-slaves-to-write 3 
# 允许从库最长失去连接的时间
min-slaves-max-lag 10

以上两个配置只要有一个不满足,则主库不可写。

3.3、主从复制崩溃恢复

在主从复制中,主库一般是禁用持久化的,因为从库已经做数据备份了,禁用持久化可以提高性能。

从库崩溃,直接重启从库即可。

主库崩溃,不能直接重启主库,因为主库禁用持久化,如果重启主库则直接丢失数据,然后同步给从库,从库也相应地丢失数据。

为了避免数据丢失,当主库崩溃时,需要做以下两步操作:

  1. 在从库执行slave no one命令将从库升级为主库;

  2. 重启崩溃的主库,然后使用slave命令将其设置为新主库的从库;

无论主库崩溃还是从库崩溃,都需要手动操作,手动操作不仅麻烦还容易出错,因此redis提供哨兵这一机制来支持自动操作。

4、哨兵

哨兵的功能:

  • 监控主从库是否正常运行;

  • 主库故障时自动将主库转为从库;

可以部署多个哨兵,哨兵之间也会互相监控。

哨兵甚至可以监控多个主从系统,通过在sentinel.conf中配置多行sentinel monitor配置来实现。

哨兵是一个可执行文件,在redis的src目录下面,名称为redis-sentinel。

在sentinel.conf中,做如下配置。

sentinel monitor mymaster 127.0.0.1 6379 1
  • mymaster是自己定义的主库名;

  • 127.0.0.1:6379是主库的ip和端口号,sentinel.conf中只需要配置要监控的主库即可,而从库sentinel会根据主库自动发现;

  • 1表示至少需要1个哨兵节点同意;

然后执行以下命令启动sentinel进程

src/redis-sentinel sentinel.conf


下面演示一下哨兵是如何自动化监控主从复制的。

为了简单起见,现有一主一从,主库为127.0.0.1::6379,从库为127.0.0.1::6380。

  1. 启动一个哨兵进程,观察启动日志;

  2. 然后我们刻意停掉主库,观察哨兵的日志变化;

  3. 最后,手动重启旧主库,观察哨兵的日志变化(哨兵只会帮助我们选举新的主库,然后将旧主库变为新主库的从库,并不会为我们重启旧主库);

以上三步哨兵的日志如下图所示。