用户可以通过SLAVEOF host port 或者设置slaveof选项,让一个服务器去复制另一个服务器,复制功能包括同步和命令传播,同步用于将从服务器状态更新为主服务器状态,传播用于在主服务器数据库状态被修改时,让主从服务器状态回到一致。
从服务器向主服务器发送SYNC命令,主服务器执行BGSAVE命令,生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令,将RDB文件发送给从服务器,从服务器接收并载入RDB文件,主服务器将缓冲区中的写命令发送给从服务器,保证两边数据库状态一致。
缺点:效率低下
使用PSYNC同步,初次复制时完整重同步,断线后使用部分重同步
部分重同步主要依赖三个变量
主服务器维护了一个固定长度先进先出队列,默认大小为1MB的复制积压缓冲区,并且复制积压缓冲区会为队列中每个字节记录相应的复制偏移量,如果从服务器的偏移量之后的数据仍在复制积压缓冲区内,则执行部分重同步,否则执行完整重同步,执行同步之后会判断从服务器的ID是否与主服务器一致,不一致则执行完整重同步。
通过repl_backlog_size修改缓冲区大小
从服务器发送PSYNC命令
如果主服务器返回
REPLCONF ACK (replication-offset)每秒一次
min-slaves-to-write: x
min-slaves-max-lag: y
从服务器少于x个,或者x个从服务器延迟大于等于y秒,主服务器拒绝执行写命令。
SENTINEL是redis的一个特殊模式,SENTINEL系统可以监视任意多个主服务器,以及这些主服务器下的从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器替代下线的主服务器继续处理命令请求。
启动SENTINEL:
redis-sentinel /path/sentinel.conf
redis-server /path/sentinel.conf --sentinel
对于每个被sentinel监视的主服务器,sentinel会创建两个连向主服务器的异步网络连接:一个是命令连接,用于向主服务器发送命令,另一个是订阅连接:这个连接专门用于订阅主服务器的_sentinel_:hello频道。
SENTINEL默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息,包括主服务器本身的信息和主服务器属下的所有从服务器的信息,SENTINEL也会创建连接到从服务器的命令连接和订阅连接。
对于每个与SENTINEL连接的服务器,SENTINEL既通过命令连接向服务器的_sentinel_:hello频道发送信息,又通过订阅连接从服务器的_sentinel_:hello频道接收信息。
SENTINEL之间不会创建订阅连接
SENTINEL会以每秒一次的频率向所有与它创建了命令连接的实例发送PING命令,如果一个实例在down-after-miliseconds毫秒内,连接向SENTINEL返回无效回复,那么SENTINEL会修改这个实例所对应的实例结构,在结构flags属性打开SRI_S_SOWN标识。然后SENTINEL回向其他SENTINEL发送命令SENTINEL is-master-down-by-addr
询问其他SENTINEL是否同意主服务器下线,该命令返回SENTINEL is-master-down-by ,当达到一定数量(quorum)已下线判之后,SENTINEL就会将其视为已下线,并选举领头SENTINEL执行故障转移操作。
向一个节点node发送CLUSTER MEET命令,可以让node节点与ip和port所指定的节点进行握手,当握手成功时,node节点就会将ip和port所指定的节点添加到node节点所在的集群中。节点只能使用0号数据库。Redis服务器在启动时会根据cluster-enabled配置是否为yes来决定是否开启服务器的集群模式。
集群模式下:
1)节点会继续使用文件事件处理器来处理命令请求和返回命令回复。
2)节点会继续使用时间事件处理器来执行serverCron函数,而serverCron函数会调用集群模式下特有的clusterCron函数执行集群模式下的常规操作(如向其他节点发送Gossip消息,检查节点是否下线,或者检查是否需要对下线节点进行自动故障转移)。
3)使用数据库保存键值对,继续使用RDB和AOF,继续使用订阅和发布模块执行PUBLISH和SUBSCRIBE
4)继续使用redisServer保存服务器状态,使用redisClient保存客户端状态,集群模式下的数据保存在cluster.h/clusterNode、cluster.h/clusterLink以及cluster.h/clusterState结构中。
clusterNode结构保存了一个节点的当前状态,比如节点的创建时间,节点的名字,节点当前的配置纪元,节点的IP端口,每个节点都会为自己和集群中所有其他节点创建一个相应的clusterNode结构。
clusterNode结构的link属性是一个clusterLink结构,该结构保存了连接节点所需的有关信息,比如套接字描述符,输入缓冲区和输出缓冲区。
每一个节点都保存着一个clusterState结构,这个结构记录了在当前节点的视角下,集群所处的状态,节点会使用clusterState的slots_to_keys保存槽和键之间的关系。
1)节点A为节点B创建一个clusterNode结构,并添加到clusterState.nodes中
2)节点A对节点B发送一条MEET消息
3)节点B为节点A创建一个clusterNode结构并添加自己的clusterState的nodes中,并向A返回一条PONG消息。
4)节点A接收到PONG消息之后,向节点B返回一条PING消息,握手完成
5)节点A通过Gossip协议将节点B的信息传播给集群中的其他节点
Redis集群通过分片的方式保存数据库中的键值对;集群的整个数据库被分为16384个槽,数据库的键属于这16384个槽中的一个,通过向节点发送CLUSTER ADDSLOTS
[slot…]将一个或多个槽指派给其他节点负责。当16384个槽都有节点在处理时,集群处于上线状态(ok),否则处于下线状态(fail)。clusterNode的slots属性和numslot记录了节点负责处理哪些槽。slots属性是一个二进制位数组,长度为16384 / 8 = 2048个字节。如果在索引i上的二进制位为1,表示当前节点负责处理槽i,否则不处理,numslots记录节点负责处理槽的数量。
节点还会将自己的slots数组通过消息发送给集群中的其他节点,接收到消息的节点会将消息保存到相应节点的clusterNode结构里面,clusterState的slots数组记录了集群中所有16384个槽的指派信息。
客户端向集群中的节点发送数据命令时,如果键所在的槽正好指派给了当前节点,那么节点直接执行命令,如果没有指派给当前节点,那么节点会向客户端返会一个MOVED错误,并再次发送之前执行的命令,这是隐式执行的。
将任意数量的已经指派给某个节点的槽改为指派给另一个节点,并且相关槽所属的键值对也会从源节点被移动目标节点,重新分片可以在线执行。
重新分片原理:
1)redis-trib对目标节点发送CLUSTER SETSLOT
2)redis-trib对源节点发送CLUSTER SETSLOT
3)redis-trib向源节点发送CLUSTER GETKEYSINSLOT
4)对于每个键名,redis-trib向源节点发送一个MIGRATE
5)重复3)和4)
6)redis-trib向集群中地任意一个节点发送CLUSTER SETSLOT
ASK错误:如果客户端向源节点发送了一个键key的命令请求,如果未找到该key,那么节点会检查自己的clusterState.migraing_slots_to[i],看键key所属的槽i是否正在迁移,如果正在迁移,那么节点会向客户端发送一个ASK错误,接收到ASK错误的客户端会根据错误提供的ip地址和端口号,转向正在导入槽的目标节点,然后向目标节点发送一个ASKING命令(ASKING命令的作用是打开发送该命令的客户端的REDIS_ASKING标识,允许当前节点破例执行这个槽i的命令一次),之后在重新发送原本想要执行的命令。
Redis集群中的节点分为主节点和从节点,主节点用于处理槽,从节点则用于复制某个主节点,当被复制的主节点下线时,某个从节点代替下线的主节点继续处理命令请求。
CLUSTER REPLICATE
1)接收到该命令的节点会将自己的clusterState.myself.slaveof指针指向node_id所对应的节点的clusterNode,并修改自己在clusterState.myself.flags,打开REDIS_NODE_SLAVE。
2)调用复制代码,复制主节点。
集群中的每个节点都会定期向集群中的其他节点发送PING消息,以此检测对方是否在线,如果目标节点没有在规定时间内向源节点返回PONG消息,源节点会将目标节点标记为疑似下线。如果在一个集群里面,半数以上负责处理槽的主节点都将某个主节点x报告为疑似下线,那么这个主节点x将被标记为已下线,将主节点x标记为已下线的节点会像集群广播一条关于主节点x的FAIL消息,所有收到FAIL消息的节点都会立即将主节点x标记为已下线。
故障转移:
1)复制下线节点的所有从节点中,选举出一个从节点(Raft算法)
2)被选中的从节点执行SLAVEOF no one命令,成为新的主节点
3)新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽指派给自己
4)新的主节点向集群广播一条PONG消息
5)新的主节点开始接收和自己负责的槽有关的命令请求
集群中的系欸但通过发送和接收消息来进行通信,常见的消息包括MEET、PING、PONG、PUBLISH,FAIL。
Redis通过MULTI、EXEC、WATCH命令实现事务。
showlog-log-slower-than:运行时长超过多少微秒会被记录到日志。
showlog-max-len:最多保存多少条慢查询日志
SLOWLOG GET :查看慢查询日志
MONITOR:将客户端变为一个监视器,打开客户端的REDIS_MONITOR标识,别监视的服务器运行的命令会打印在监视器中。