이 문서는 Redis의 장애 조치(센티넬)를 안내합니다. 도움이 되기를 바랍니다!
두 개 이상의 Redis 인스턴스가 마스터-대기 관계를 형성할 때 이들이 형성하는 클러스터는 어느 정도 고가용성을 갖습니다. 즉, 마스터에 장애가 발생하면 슬레이브가 새로운 마스터가 되어 외부 읽기 및 쓰기 서비스를 제공할 수 있습니다. 이 운영 메커니즘은 장애 조치가 됩니다. [관련 추천 : Redis 영상 튜토리얼]
그럼 누가 마스터의 잘못을 발견하고 페일오버 결정을 내릴까요?
한 가지 방법은 아래 그림과 같이 모든 마스터-슬레이브 노드를 모니터링하는 데모 프로세스를 유지하는 것입니다.
Redis 클러스터에는 마스터와 두 개의 슬레이브가 있습니다. 이 데몬 프로세스는 이 세 개의 노드를 모니터링합니다. . 그러나 데몬은 단일 노드이므로 가용성을 보장할 수 없습니다. 아래 그림과 같이 여러 데몬을 도입해야 합니다.
여러 데몬이 가용성 문제를 해결하지만, 특정 마스터를 사용할 수 있는지에 대한 합의에 어떻게 도달할 수 있습니까? 예를 들어 위 그림에서는 daemon1과 master의 두 네트워크가 차단되어 있는데, 이때 daemon과 master의 연결은 원활하게 이루어지나요?
Redis의 sentinel은 여러 데몬 간의 상호 작용 메커니즘 세트를 제공합니다. 여러 데몬이 클러스터를 형성하고 센티널 클러스터가 됩니다. 데몬 노드를 센티넬 노드라고도 합니다. 아래 그림과 같이
이러한 노드는 서로 소통하고, 선택하고, 협상하며, 마스터 노드의 결함 발견 및 장애 조치 결정에서 일관성을 보여줍니다.
센티넬 클러스터는 마스터와 마스터 아래의 슬레이브 수를 모니터링하고 오프라인 마스터를 그 아래의 슬레이브에서 새 마스터로 자동 업그레이드하여 명령 요청을 계속 처리합니다.
Sentinel을 시작하려면
./redis-sentinel ../sentinel.conf
명령 또는
./redis-server ../sentinel.conf --sentinel
명령을 사용할 수 있습니다. Sentinel이 시작되면 다음 단계를 수행해야 합니다.
서버 초기화
Sentinel Essence 위는 특수 모드로 실행되는 Redis 서버이며 일반 Redis 서버와 다른 작업을 수행하며 초기화 프로세스가 완전히 동일하지는 않습니다. 예를 들어 일반적인 Redis 서버 초기화에서는 데이터 복원을 위해 RDB 또는 AOF 파일을 로드하지만 Sentinel은 데이터베이스를 사용하지 않기 때문에 시작 시 이를 로드하지 않습니다.
일반 Redis 서버에서 사용하는 코드를 Sentinel 전용 코드로 교체
일반 Redis 서버에서 사용하는 코드 중 일부를 Sentinel 전용 코드로 교체하세요. 예를 들어 일반 Redis 서버는 서버의 명령 테이블로 server.c/redisCommandTable을 사용합니다.
truct redisCommand redisCommandTable[] = { {"module",moduleCommand,-2,"as",0,NULL,0,0,0,0,0}, {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0}, {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0}, {"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0}, {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0}, ..... {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}, {"unlink",unlinkCommand,-2,"wF",0,NULL,1,-1,1,0,0}, {"exists",existsCommand,-2,"rF",0,NULL,1,-1,1,0,0}, {"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0}, {"getbit",getbitCommand,3,"rF",0,NULL,1,1,1,0,0}, {"bitfield",bitfieldCommand,-2,"wm",0,NULL,1,1,1,0,0}, {"setrange",setrangeCommand,4,"wm",0,NULL,1,1,1,0,0}, {"getrange",getrangeCommand,4,"r",0,NULL,1,1,1,0,0}, {"substr",getrangeCommand,4,"r",0,NULL,1,1,1,0,0}, {"incr",incrCommand,2,"wmF",0,NULL,1,1,1,0,0}, {"decr",decrCommand,2,"wmF",0,NULL,1,1,1,0,0}, {"mget",mgetCommand,-2,"rF",0,NULL,1,-1,1,0,0}, {"rpush",rpushCommand,-3,"wmF",0,NULL,1,1,1,0,0}, {"lpush",lpushCommand,-3,"wmF",0,NULL,1,1,1,0,0} ...... }
Sentinel은 아래와 같이 sentinel.c/sentinelcmds를 서버 목록으로 사용합니다.
struct redisCommand sentinelcmds[] = { {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0}, {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0}, {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, {"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0}, {"client",clientCommand,-2,"rs",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}, {"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0} }
Initializing Sentinel status
서버는 sentinel.c/sentinelState 구조를 초기화합니다(Sentinel 기능과 관련된 모든 상태를 서버에 저장).
struct sentinelState { char myid[CONFIG_RUN_ID_SIZE+1]; /* This sentinel ID. */ //当前纪元,用于实现故障转移 uint64_t current_epoch; /* Current epoch. */ //监视的主服务器 //字典的键是主服务器的名字 //字典的值则是一个指向sentinelRedisInstances结构的指针 dict *masters; /* Dictionary of master sentinelRedisInstances. Key is the instance name, value is the sentinelRedisInstance structure pointer. */ //是否进入tilt模式 int tilt; /* Are we in TILT mode? */ //目前正在执行的脚本数量 int running_scripts; /* Number of scripts in execution right now. */ //进入tilt模式的时间 mstime_t tilt_start_time; /* When TITL started. */ //最后一次执行时间处理器的时间 mstime_t previous_time; /* Last time we ran the time handler. */ // 一个FIFO队列,包含了所有需要执行的用户脚本 list *scripts_queue; /* Queue of user scripts to execute. */ char *announce_ip; /* IP addr that is gossiped to other sentinels if not NULL. */ int announce_port; /* Port that is gossiped to other sentinels if non zero. */ unsigned long simfailure_flags; /* Failures simulation. */ int deny_scripts_reconfig; /* Allow SENTINEL SET ... to change script paths at runtime? */ }
주어진 구성 파일을 기반으로 Sentinel의 모니터링 마스터 서버 목록 초기화
Sentinel 상태의 초기화는 마스터 사전의 초기화를 트리거하며, 마스터 사전의 초기화는 로드된 Sentinel 구성 파일을 기반으로 합니다. 진행하다.
사전의 키는 모니터링하는 메인 서버의 이름이고, 사전의 값은 모니터링하는 메인 서버에 해당하는 sentinel.c/sentinelRedisInstance 구조체입니다.
sentinelRedisInstance 구조의 일부 속성은 다음과 같습니다.
typedef struct sentinelRedisInstance { //标识值,记录了实例的类型,以及该实例的当前状态 int flags; /* See SRI_... defines */ //实例的名字 //主服务器的名字由用户在配置文件中设置 //从服务器以及Sentinel的名字由Sentinel自动设置 //格式为ip:port,例如“127.0.0.1:26379” char *name; /* Master name from the point of view of this sentinel. */ //实例运行的ID char *runid; /* Run ID of this instance, or unique ID if is a Sentinel.*/ //配置纪元,用于实现故障转移 uint64_t config_epoch; /* Configuration epoch. */ //实例的地址 sentinelAddr *addr; /* Master host. */ //sentinel down-after-milliseconds选项设定的值 //实例无响应多少毫秒之后才会被判断为主观下线(subjectively down) mstime_t down_after_period; /* Consider it down after that period. */ //sentinel monitor <master-name> <ip> <redis-port> <quorum>选项中的quorum //判断这个实例为客观下线(objective down)所需的支持投票的数量 unsigned int quorum;/* Number of sentinels that need to agree on failure. */ //sentinel parallel-syncs <master-name> <numreplicas> 选项的numreplicas值 //在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量 int parallel_syncs; /* How many slaves to reconfigure at same time. */ //sentinel failover-timeout <master-name> <milliseconds>选项的值 //刷新故障迁移状态的最大时限 mstime_t failover_timeout; /* Max time to refresh failover state. */ }
예를 들어 Sentinel을 시작하면 다음 구성 파일이 구성됩니다.
# sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor master1 127.0.0.1 6379 2 # sentinel down-after-milliseconds <master-name> <milliseconds> sentinel down-after-milliseconds master1 30000 # sentinel parallel-syncs <master-name> <numreplicas> sentinel parallel-syncs master1 1 # sentinel failover-timeout <master-name> <milliseconds> sentinel failover-timeout master1 900000
그런 다음 Sentinel은 기본 서버 master1에 대해 아래와 같이 인스턴스 구조를 생성합니다.
Sentinel 상태 마스터 사전의 구성은 다음과 같습니다.
메인 서버에 대한 네트워크 연결을 생성합니다.
모니터링되는 메인 서버에 대한 네트워크 연결을 생성합니다. 메인 서버에 명령을 보내고 명령 응답에서 정보를 얻습니다.
Sentinel은 메인 서버에 두 개의 비동기 네트워크 연결을 생성합니다:
Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的master和slave发送INFO命令。
通过master的回复可获取master本身信息,包括run_id域记录的服务器运行ID,以及role域记录的服务器角色。另外还会获取到master下的所有的从服务器信息,包括slave的ip地址和port端口号。Sentinel无需用户提供从服务器的地址信息,由master返回的slave的ip地址和port端口号,可以自动发现slave。
当Sentinel发现master有新的slave出现时,Sentinel会为这个新的slave创建相应的实例外,Sentinel还会创建到slave的命令连接和订阅连接。
根据slave的INFO命令的回复,Sentinel会提取如下信息:
1.slave的运行ID run_id
2.slave的角色role
3.master的ip地址和port端口
4.master和slave的连接状态master_link_status
5.slave的优先级slave_priority
6.slave的复制偏移量slave_repl_offset
Sentinel在默认情况下会以每两秒一次的频率,通过命令连接向所有被监视的master和slave的_sentinel_:hello频道发送一条信息
发送以下格式的命令:
PUBLISH _sentinel_:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
以上命令相关参数意义:
参数 | 意义 |
---|---|
s_ip | Sentinel的ip地址 |
s_port | Sentinel的端口号 |
s_runid | Sentinel的运行ID |
s_runid | Sentinel的运行ID |
m_name | 主服务器的名字 |
m_ip | 主服务器的IP地址 |
m_port | 主服务器的端口号 |
m_epoch | 主服务器当前的配置纪元 |
命令如下所示:
SUBSCRIBE sentinel:hello
如上图所示,对于每个与Sentinel连接的服务器 ,Sentinel既可以通过命令连接向服务器频道_sentinel_:hello频道发送信息,又通过订阅连接从服务器的_sentinel_:hello频道接收信息。
相互连接的各个Sentinel可以进行信息交换。Sentinel为master创建的实例结构中的sentinels字典保存了除Sentinel本身之外,所有同样监视这个主服务器的其它Sentinel信息。
前面也讲到sentinel会为slave创建实例(在master实例的slaves字典中)。现在我们也知道通过sentinel相互信息交换,也创建了其它sentinel的实例(在master实例的sentinels字典中)。我们将一个sentinel中保存的实例结构大概情况理一下,如下图所示:
从上图可以看到slave和sentinel字典的键由其ip地址和port端口组成,格式为ip:port,其字典的值为其对应的sentinelRedisInstance实例。
主观不可用
默认情况下Sentinel会以每秒一次的频率向所有与它创建了命令连接的master(包括master、slave、其它Sentinel)发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
PING命令回复分为下面两种情况:
有效回复:实例返回 +PONG、-LOADING、-MASTERDOWN三种回复的一种
无效回复:除上面有效回复外的其它回复或者在指定时限内没有任何返回
Sentinel配置文件中的设置down-after-milliseconds毫秒时效内(各个sentinel可能配置的不相同),连续向Sentinel返回无效回复,那么sentinel将此实例置为主观下线状态,在sentinel中维护的该实例flags属性中打开SRI_S_DOWN标识,例如master如下所示:
客观不可用
在sentinel发现主观不可用状态后,它会将“主观不可用状态”发给其它sentinel进行确认,当确认的sentinel节点数>=quorum,则判定该master为客观不可用,随后进入failover流程。
上面说到将主观不可用状态发给其它sentinel使用如下命令:
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
各个参数的意义如下:
接受到以上命令的sentinel会反回一条包含三个参数的Multi Bulk回复:
1)down_state> 目标sentinel对该master检查结果,1:master已下线 2:master未下线
2)leader_runid> 两种情况,*表示仅用于检测master下线状态 ,否则表示局部领头Sentinel的运行ID(选举领头Sentinel)
3)leader_epoch> 当leader_runid为时,leader_epoch始终为0。不为时则表示目标Sentinel的局部领头Sentinel的配置纪元(用于选举领头Sentinel)
其中节点数量限制quorum为sentinel配置文件中配置的
sentinel monitor <master-name> <ip> <redis-port> <quorum>
quorum选项,不同的sentinel配置的可能不相同。
当sentinel认为master为客观下线状态,则会将master属性中的flags的SRI_O_DOWN标识打开,例如master如下图所示:
마스터가 다운되면 여러 센티넬 노드가 동시에 상호 작용을 통해 서로의 "주관적 비가용성 상태"를 발견하고 확인하고, 동시에 "객관적 비가용성 상태"에 도달하여 이를 계획할 수 있습니다. 장애 조치를 시작합니다. 그러나 결국 장애 조치 개시자로 센티넬 노드는 하나만 있을 수 있으며, Sentinel Leader를 선출하고 Sentinel Leader 선출 프로세스를 시작해야 합니다.
Redis의 Sentinel 메커니즘은 Raft 프로토콜과 유사한 것을 사용하여 이 선택 알고리즘을 구현합니다.
1 sentinelState의 epoch 변수는 raft 프로토콜의 용어(선거 라운드)와 유사합니다.
2. 마스터가 "객관적으로 사용 불가능"함을 확인한 각 센티넬 노드는 자신의 선택 요청을 주변에 전파합니다(SENTINEL is-master-down-by-addr
3. 선택 요청을 받은 각 센티널 노드가 다른 선택 요청을 받지 못한 경우 첫 번째 후보 센티넬로 의도를 설정합니다. 그리고 회신합니다(선착순). 이번 라운드에서 의도가 표현된 경우 다른 후보는 거부되고 기존 의도는 응답됩니다(위의 세 가지 매개변수에 대해 언급한 바와 같이). Multi Bulk reply, down_state는 1, Leader_runid는 처음 수신한 선택 요청을 시작한 소스 Sentinel의 실행 ID이고, Leader_epoch는 처음 수신한 선택 요청을 시작한 소스 Sentinel의 구성 에포크입니다.)
4 각 시작 매개변수인 경우 요청을 선택한 센티널 노드는 참여하는 센티널(아마도 자체)에 동의하려는 의도의 절반 이상을 받으면 센티널이 리더로 결정됩니다. 이 라운드가 충분히 오래 지속되고 리더가 선출되지 않으면 다음 라운드가 시작됩니다. 리더 센티넬. 확인 후
리더 센티넬은 특정 규칙에 따라 모든 마스터의 슬레이브 중에서 하나를 새로운 마스터로 선택합니다.
failover Failover를 완성한 다음 이 슬레이브에:SLAVEOF no one 명령을 보내 이 슬레이브를 마스터로 변환합니다. 새로운 마스터가 어떻게 선정되는지 살펴볼까요? Sentinel 리더는 모든 오프라인 슬레이브를 목록에 저장한 후 다음 규칙에 따라 필터링 및 필터링합니다.
, 기본값은 100이며, 복제본 우선순위가 낮을수록 우선순위는 높아집니다. 0은 특별한 우선순위로, 마스터로 업그레이드할 수 없음을 나타냅니다.
우선순위가 같은 슬레이브가 여러 개인 경우 가장 큰 복제 오프셋은 다음과 같습니다. selected 볼륨이 가장 큰 슬레이브를 선택한 경우
새 마스터로 업그레이드해야 하는 슬레이브를 선택한 후 Sentinel Leader는 SLAVEOF no one 명령을 보냅니다. 이 노예에게.
sentinel 리더는
새 마스터를 복사이전 마스터를 새 마스터의 슬레이브로 설정하고 계속 모니터링합니다. 다시 온라인 상태가 되면 Sentinel은 이를 새 마스터의 슬레이브로 만드는 명령을 실행합니다.
기본적으로 sentinel은 다른 sentinel과 상호 작용하기 위해 2초마다 명령 연결을 통해 모니터링되는 모든 마스터와 슬레이브의 _sentinel_:hello 채널에 메시지를 보냅니다.
기본적으로 sentinel은 매초 마스터, 슬레이브 및 기타 sentinel에 PING을 보냅니다. 상대방이 오프라인인지 확인하는 명령
센티넬 리더는 일정한 규칙에 따라 선출됩니다.
센티넬 리더는 장애 조치 작업을 수행하고 오프라인 마스터를 대체할 새 마스터를 선출합니다.
더 많은 프로그래밍 관련 지식을 보려면
프로그래밍 소개를 방문하세요! !
위 내용은 Redis의 센티널 장애 조치에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!