redis入门指南(五)—— 复制与哨兵

时间:2023-12-12 12:32:14

写在前面

  学习《redis入门指南》笔记,结合实践,只记录重要,明确,属于新知的相关内容。

一、复制

  1、在复制中,数据库分为两类,一类主数据库,一类从数据库,主库用来读写,从库用来读,主库可以拥有多个从库,但从库只能拥有一个主库。

  2、使用复制非常简单,只需要在从库的启动参数运行时命令配置文件中加入“ slaveof 主库地址 从库地址 ”即可,主库无需配置;可通过INFO replication查看主从的复制信息。

  3、从库默认为只读,可通过修改配置文件参数slave-read-only为no使其可写,但从库的数据不会同步给主库;当使用slaveof命令修改了复制的主库,从库会停止和当前主库同步,转而同步新主库的数据;对于从库还可以使用SLAVE NO ONE停止接收从库信息,转换为主库。

  4、复制原理:从库启动后向主库发送SYNC命令,主库收到后开始执行RDB持久化(即使没有开启持久化)并缓存持久化期间收到的命令,这两项任务结束后,会将rdb文件和缓存一并发给从库,从库使用临时文件保存这些数据,然后替换本地rdb文件并载入到内存,这一过程成为复制初始化,最后主库一旦收到写命令都会异步发送给从库。当主从断开重连后,2.6版本以前会重新执行复制初始化,2.8版本加入了增量复制。

  5、主从复制采用异步方式,命令执行完毕立刻返回给客户端,之后异步发送命令给从库,这样保证了写入性能,但主从的数据会有一个不一致的时间窗,在命令同步完成前,如果网络断开,主库无法知道多少个从库同步了数据;通过设置参数min-slaves-to-write(至少有多少个从库连接才可以写入) 和min-slaves-max-lag(允许从库失去连接的最长时间)来降低主从不一致的可能性,这一特性默认关闭。

  6、通过复制可以实现读写分离,并且从库也可以拥有自己的从库;对于较耗时的操作例如持久化,可以禁用主库的持久化而开启从库的,当从库崩溃重启后主库会自动同步数据过来;当主库崩溃时,必须先将从库提升为主库(通过slaveof no one),再将崩溃的主库设置为新的主库的从库,即可将数据同步。

  注意:当开启复制,并关掉主库持久化功能时,若主库崩溃,一定不能使用监控工具直接重启主库,因为主库没有持久化,直接重启会导致主库数据丢失,并且从库会跟着复制主库,使得从库数据也被清空,失去持久化以及复制的意义。

  7、基于RDB方式的持久化有明显的缺点,首先当主库禁用RDB时,依然会生成RDB文件,下次启动时会以该快照文件启动,这使得数据可能是任意时间点的,而不是最新的;其次,当硬盘性能较差时,每次和从库同步,都会执行一次快照对硬盘读写,性能会降低。2.8.18版本引入了无硬盘复制(通过参数repl-diskless-sync yes开启),不再将快照内容存储到硬盘,而是通过网络发送给从库,避免了硬盘性能瓶颈。

  8、redis2.8版本实现了主从库的增量复制,首先,从库会存储主库的运行id(run id保证唯一),在复制同步阶段,主库每发一个命令,都会将其存放到一个积压队列中,并记录积压队列的存放命令的偏移量范围,然后从库每次收到命令会记录下该偏移量,重连时,主库判断从库传来的运行id是否与自己一致,接着判断命令偏移量是否在积压队列中,如果在则执行增量复制,将积压队列中相应的命令发给从库。如果不满足以上条件就会全部同步。

  9、增量复制,使用“ PSYNC 主库运行id 断开前最新的命令偏移量 ”命令代替SYNC,增量复制的过程对于使用者来说时透明的;需要关注的就是积压队列(一个循环队列)的大小,通过参数repl-backlog-size(默认1M)来配置,参数repl-backlog-ttl(默认1小时)用来控制与从库断开多久后可以释放积压队列的内存。

二、哨兵

  10、哨兵是一个独立的进程,提供了故障监控和自动化恢复的功能(如主库停止服务时,将从库提升为主库),哨兵可以用来监控数据库,也可以用来监控其他哨兵。

  11、使用哨兵前,要先建立一个配置文件,如名为sentinel.conf,内容为:

 格式为:sentinel monitor master-name ip port quorum
sentinel monitor mymaster 127.0.0.1

  mymaster 表示主库名字,可以随便定义,之后是主库ip,port,1表示最低通过票数。配置哨兵时,只需配置主库,因为哨兵会主动发现主库的相关从库。

  12、哨兵启动时,会先读取配置文件,master-name只能由字母、数字、“. - _”组成,quorum表示执行故障恢复操作前至少需要几个哨兵节点同意;一个哨兵节点可以监控多个主从系统(只需要配置文件多条配置),多个哨兵节点也可以监控同一个主从系统。

  13、哨兵启动后,会与要监控的数据库建立两条连接,其中一条用来订阅主库的__sentinel__:hello频道以获取同样监控主库的其他哨兵的信息,由于订阅时无法执行其他命令,所以另一条连接用来发送其他命令。

  14、建立连接后,哨兵执行三个操作,每10秒向主库和从库发送INFO命令,每2秒向主库和从库的__sentinel__:hello发送自己的信息,每1秒向主库,从库和其他哨兵节点发送PING。

  15、发送INFO命令,获得数据库相关信息,运行id,复制信息等,从库的信息也在此时获得,并向每个从库建立两条连接,之后根据此信息不断更新自己的监控队列。

  16、向频道__sentinel__:hello发送信息,用来与同样监控该数据库的哨兵分享自己的信息,如果发现新哨兵,则向其建立一条连接(用来发送PING,只需要一条连接),消息内容为:

<哨兵的地址>,<哨兵的断开>,<哨兵的运行id>,<哨兵的配置版本>,<主库的名字>, <主库的地主>,<主库的端口>,<主库的配置版本>

  17、发送PING命令,实现了自动发现后,哨兵要通过PING监控节点是否运行,当配置参数down-after-milliseconds的值小于一秒时,会每隔down-after-milliseconds发送PING,大于1秒时,每隔一秒发送。

 sentinel down-after-milliseconds master-name   // 每隔1秒
sentinel down-after-milliseconds master-name // 每隔600毫秒

  18、当超过down-after-milliseconds选项指定的时间后,仍没有回复,则哨兵认为其已经主观下线(表示从当前进程来看,该节点已停止服务),如果该节点是主库,则会判断是否需要故障恢复,哨兵发送SENTINEL is-master-down-by-addr询问其他哨兵是否也认为主库已停止服务,当达到指定数量(quorum参数),则会认为其客观下线,并选举领头哨兵对其执行故障恢复。

  19、选举领头哨兵使用Raft算法,发现主库客观下线的哨兵向每个节点发送命令。要求对方选择自己成为领头哨兵,如果对方没有选过其他人,则会同意其成为领头哨兵,当发起选举的哨兵发现有超过半数且大于quorum个哨兵同意自己成为领头哨兵,则成功当选,当有多个哨兵时,会出现谁也没有当选的情况,此时会等待一个随机时间重新发起参选请求,直到成功;因为要有超过半数的哨兵同意,所以一次只会选举出一个领头哨兵。

  20、选出领头哨兵后,开始进行故障恢复,先从停止服务的主库的从库中挑选一个来充当新的主库,选择优先级最高的从库,可通过slave-priority参数配置优先级,如果有多个优先级最高的从库,则选择复制的命令偏移量最大的(信息最完整),如果还没有选出唯一一个,则选择运行id最小的一个;选出数据库之后,领头哨兵发送SLAVE NO ONE使其升为主库,而向其他从库发送SLAVEOF命令使其成为新主库的从库,最后则是更新哨兵的内部记录,当旧的主库也更新为新主库的从库,使得当其恢复时以从库身份运行。

  21、部署哨兵时,应尽可能地使哨兵的视角与每节点一致,如为每一个节点部署哨兵,每个哨兵与其对应的节点网络应尽可能一致,设置quorum参数为N/2+1(N为哨兵数量);但当节点较多时,会产生大量冗余连接,或者redis负载较高时,影响其对哨兵的回复或与其他哨兵的通信,所以哨兵配置还要根据实际的生存环境选择。