Cluster Redis--Cluster--failover--process/princípio

URL original:

Introdução

        Este artigo apresenta o processo de failover do cluster Redis (Cluster).

Solução de problemas

        Quando há um problema com um nó no cluster, é necessário haver uma maneira robusta de garantir que o nó esteja com defeito. Os nós no cluster Redis implementam a comunicação de nós por meio de mensagens ping/pong. As mensagens podem não apenas propagar informações de slot de nó, mas também outros estados, como estado mestre-escravo, falha de nó etc. Portanto, a descoberta de falhas também é realizada através do mecanismo de disseminação de mensagens, e os principais links incluem: offline subjetivo (pfail) e offline objetivo (fail).

  • Subjetivo off-line: refere-se a um nó que considera outro nó indisponível, ou seja, o estado off-line. Este estado não é o julgamento final da falha, mas representa apenas a opinião de um nó, podendo haver erros de julgamento.
  • Objetivo offline: Refere-se a marcar o real offline de um nó, e vários nós do cluster acreditam que o nó está indisponível, chegando assim a um resultado consensual. Se o nó primário que contém o slot falhar, um failover será necessário para esse nó.

Subjetivo off-line

        Cada nó no cluster envia periodicamente mensagens ping para outros nós, e o nó receptor responde com mensagens pong. Se a comunicação falhar o tempo todo dentro do tempo limite do nó do cluster, o nó de envio considerará que o nó de recebimento está com defeito e marcará o nó de recebimento como um estado subjetivo offline (pfail). O processo é mostrado na figura abaixo:

Descrição do processo:
1) O nó a envia uma mensagem ping para o nó b. Se a comunicação for normal, uma mensagem pong será recebida e o nó a atualizará o horário da última comunicação com o nó b.

2) Se houver um problema de comunicação entre o nó a e o nó b, a conexão será desconectada e a conexão será reconectada na próxima vez. Se a comunicação falhar o tempo todo, o último tempo de comunicação registrado pelo nó a com o nó b não pode ser atualizado.

3) Quando a tarefa de temporização no nó a detecta que o último tempo de comunicação com o nó b é muito alto cluster-nodetimeout, ela atualiza o estado local do nó b como subjetivo offline (pfail).

        Subjetivo offline significa simplesmente que quando um nó não pode concluir com êxito a comunicação da mensagem de ping com outro nó dentro do período de tempo limite da nota do cluster, o nó é marcado como um estado offline subjetivo. A estrutura de estado do cluster em cada nó precisa salvar outras informações de nó, que são usadas para julgar o estado de outros nós de sua própria perspectiva. 

        O cluster Redis é muito rigoroso ao julgar se o nó está com defeito. Apenas um nó pensa que está subjetivamente offline e não pode julgar com precisão se está com defeito. Por exemplo, a seguinte cena:

        A comunicação entre os nós 6379 e 6385 é interrompida, o que faz com que 6379 julgue que 6385 está em um estado offline subjetivo, mas a comunicação entre os nós 6380 e 6385 é normal. Neste caso, não pode ser determinado que o nó 6385 está com defeito. Portanto, para um mecanismo robusto de descoberta de falhas, somente quando a maioria dos nós no cluster julgar que o 6385 está com defeito, pode-se considerar que o 6385 realmente falhou e, em seguida, o failover é executado para o nó 6385. Esse processo de vários nós cooperando para concluir a descoberta de falhas é chamado de objetivo offline.

objetivamente offline

        Quando um nó julga que outro nó está offline, o status do nó correspondente seguirá a mensagem para se espalhar no cluster. O corpo da mensagem da mensagem ping/pong carrega os dados de status de outros nós no cluster 1/10. Quando o nó receptor descobre que o corpo da mensagem contém o status subjetivo do nó offline, ele encontrará a estrutura ClusterNode do nó defeituoso localmente e salve-o no meio da lista vinculada do relatório offline. A estrutura é a seguinte:

struct clusterNode { /* 认为是主观下线的clusterNode结构 */
    list *fail_reports; /* 记录了所有其他节点对该节点的下线报告 */
    ...
};

        Por meio da propagação de mensagens Gossip, os nós do cluster coletam continuamente relatórios offline de nós defeituosos. Quando mais da metade dos nós mestres que possuem slots marcam um nó como offline subjetivo. Acione o processo offline objetivo. Existem dois problemas aqui:

1) Por que o nó mestre responsável pelo slot deve participar da decisão de descoberta de falhas? Porque no modo cluster, apenas o nó mestre que processa o slot é responsável pela manutenção das informações chave, como solicitações de leitura e gravação e slots de cluster, enquanto o nó escravo apenas replica os dados e informações de status do nó mestre.

2) Por que mais da metade dos slots de processamento são masternodes? Mais da metade deles deve ser usado para lidar com a segmentação de cluster causada por partições de rede e outros motivos. O pequeno cluster dividido não pode concluir o processo chave de subjetivo offline para objetivo offline, impedindo assim que o pequeno cluster continue a fornecer serviços externos após concluir o failover.

        Assumindo que o nó a marca o nó b como subjetivo offline, o nó a envia o status do nó b para outros nós através de uma mensagem após um período de tempo, quando o nó c recebe a mensagem e analisa o corpo da mensagem contendo o status pfail do nó b, ele irá acionar o objetivo O processo offline é mostrado na figura a seguir:

Descrição do fluxo:

  1. Quando o corpo da mensagem contém o status de pfail de outros nós, o status do nó de envio será julgado.Se o nó de envio for o nó mestre, o status de pfail relatado será processado e o nó escravo o ignorará.
  2. Localize a estrutura do nó correspondente a pfail e atualize a lista vinculada do relatório offline interno do clusterNode.
  3. Tente fazer logoff objetivamente de acordo com a lista atualizada do relatório de logoff.

Aqui está uma descrição detalhada de como manter o relatório offline e tentar fazer logout de forma objetiva.

1. Manter a lista de relatórios offline

        Haverá uma estrutura de lista vinculada offline na estrutura ClusterNode de cada nó, que salva os relatórios offline de outros nós mestres para o nó atual. A estrutura é a seguinte:

typedef struct clusterNodeFailReport {
    struct clusterNode *node; /* 报告该节点为主观下线的节点 */
    mstime_t time; /* 最近收到下线报告的时间 */
} clusterNodeFailReport;

        O relatório offline salva a estrutura do nó que relatou a falha e a hora em que o relatório offline foi recebido recentemente. Quando o status de falha é recebido, a lista vinculada de relatório offline e online do nó correspondente será mantida. O pseudocódigo é como segue:

def clusterNodeAddFailureReport(clusterNode failNode, clusterNode senderNode) :
    // 获取故障节点的下线报告链表
    list report_list = failNode.fail_reports;
    
    // 查找发送节点的下线报告是否存在
    for(clusterNodeFailReport report : report_list):
        // 存在发送节点的下线报告上报
        if(senderNode == report.node):
            // 更新下线报告时间
            report.time = now();
            return 0;
            
        // 如果下线报告不存在,插入新的下线报告
        report_list.add(new clusterNodeFailReport(senderNode,now()));
    return 1;

        Cada relatório de downline tem uma data de expiração. Cada vez que um downline objetivo é acionado, ele detectará se o relatório de downline expirou e o relatório de downline expirado será excluído. Se o relatório off-line não for atualizado dentro do tempo de cluster-node-time*2, ele expirará e será excluído. O pseudocódigo é o seguinte:

def clusterNodeCleanupFailureReports(clusterNode node) :
    list report_list = node.fail_reports;
    long maxtime = server.cluster_node_timeout * 2;
    long now = now();
    for(clusterNodeFailReport report : report_list):
        // 如果最后上报过期时间大于cluster_node_timeout * 2则删除
        if(now - report.time > maxtime):
            report_list.del(report);

        O período de validade do relatório offline é server.cluster_node_timeout*2, que é principalmente para falsos positivos. Por exemplo, o nó A relatou que o nó B estava offline na última hora, mas depois voltou ao normal. Agora existem outros nós relatando o offline subjetivo do Nó B e, de acordo com a situação real, os falsos positivos anteriores não podem ser usados.

Dicas de operação e manutenção

        Se os relatórios off-line de mais da metade dos nós de slot não puderem ser coletados dentro do tempo de cluster-node-time*2, os relatórios off-line anteriores serão expirados, ou seja, a velocidade dos relatórios off-line subjetivos não poderá acompanhar a velocidade expirada dos relatórios offline. , o nó com falha nunca será marcado como objetivamente offline causando a falha do failover. Portanto, não é recomendado definir o tempo do nó do cluster muito pequeno.

2. Tente fazer logoff objetivamente

        Toda vez que um nó do cluster recebe o status pfail de outros nós, ele tentará acionar um objetivo offline. O processo é mostrado na figura a seguir:

Descrição do fluxo:

  1. Primeiro, conte o número de relatórios offline válidos e saia se for menos da metade do número total de nós mestres que mantêm slots no cluster.
  2. Quando o relatório offline é maior que a metade do número de nós mestres no slot, o nó defeituoso correspondente é marcado como um estado offline objetivo.
  3. Transmita uma mensagem de falha para o cluster para notificar todos os nós para marcar o nó com falha como objetivamente off-line. O corpo da mensagem de falha contém apenas o ID do nó com falha.

Use pseudocódigo para analisar o processo offline objetivo, como segue:

def markNodeAsFailingIfNeeded(clusterNode failNode) {
    // 获取集群持有槽的节点数量
    int slotNodeSize = getSlotNodeSize();
    // 主观下线节点数必须超过槽节点数量的一半
    int needed_quorum = (slotNodeSize / 2) + 1;
    // 统计failNode节点有效的下线报告数量(不包括当前节点)
    int failures = clusterNodeFailureReportsCount(failNode);
    // 如果当前节点是主节点, 将当前节点计累加到failures
    if (nodeIsMaster(myself)):
        failures++;
    // 下线报告数量不足槽节点的一半退出
    if (failures < needed_quorum):
        return;
    // 将改节点标记为客观下线状态(fail)
    failNode.flags = REDIS_NODE_FAIL;
    // 更新客观下线的时间
    failNode.fail_time = mstime();
    // 如果当前节点为主节点,向集群广播对应节点的fail消息
    if (nodeIsMaster(myself))
        clusterSendFail(failNode);

A transmissão da mensagem de falha é a última etapa do downline objetivo e assume responsabilidades muito importantes:

  • Notifique todos os nós no cluster para marcar o nó defeituoso como um estado offline objetivo e entrar em vigor imediatamente.
  • Notifique o nó escravo do nó com falha para acionar o processo de failover.

        Deve ser entendido que, embora haja um mecanismo de mensagem de falha de transmissão, é incerto para todos os nós no cluster saber que o nó com falha entra no estado offline objetivo. Por exemplo, quando ocorre uma partição de rede, é possível que o cluster seja dividido em dois clusters separados, um grande e outro pequeno. O cluster grande contém metade dos nós do slot e pode concluir o objetivo offline e transmitir a mensagem de falha, mas o cluster pequeno não pode receber a mensagem de falha, conforme mostrado na figura a seguir:

        No entanto, quando a rede for restaurada, desde que o nó defeituoso fique objetivamente offline, ele será propagado para todos os nós do cluster por meio de mensagens Gossip.

Dicas de operação e manutenção

        A partição de rede fará com que o cluster pequeno dividido não receba a mensagem de falha do cluster grande. Portanto, se todos os nós escravos do nó defeituoso estiverem no cluster pequeno, o failover subsequente não será concluído. A topologia do rack reduz a possibilidade de mestre e escravo serem particionados.

Recuperação

        Após o nó defeituoso tornar-se objetivamente off-line, se o nó off-line for o nó mestre que detém o slot, ele precisa selecionar um de seus nós escravos para substituí-lo, de modo a garantir a alta disponibilidade do cluster. Todos os nós escravos do nó mestre offline são responsáveis ​​pela recuperação de falhas. Quando o nó escravo descobre que o nó mestre replicado por ele mesmo entrou no objetivo offline por meio de tarefas internas de temporização, o processo de recuperação de falhas será acionado, conforme mostrado na figura a seguir :

1. Verificação de elegibilidade

        Cada nó escravo deve verificar a última hora de desconexão do nó mestre para determinar se é elegível para substituir
o nó mestre com falha. Se o tempo de desconexão entre o nó escravo e o nó mestre exceder cluster-node-time*cluster-
slave-fator de validade, o nó escravo atual não será elegível para failover. O parâmetro cluster-slavevalidity-factor é usado para o fator de validade do nó escravo, o padrão é 10.

2. Preparando-se para o período eleitoral

        Quando o nó escravo é elegível para failover, o tempo para acionar a eleição de failover é atualizado e o
processo subsequente só pode ser executado após o tempo ser atingido. Os campos relacionados ao tempo de eleição de falha são os seguintes:

struct clusterState {
    ...
    mstime_t failover_auth_time; /* 记录之前或者下次将要执行故障选举时间 */
    int failover_auth_rank; /* 记录当前从节点排名 */
}

        A razão pela qual o mecanismo de disparo atrasado é adotado aqui é principalmente para suportar o problema de prioridade usando diferentes tempos de eleição atrasados ​​para vários nós escravos. Um deslocamento de replicação maior indica um nó escravo de menor latência, portanto, deve ter uma prioridade mais alta para substituir um nó mestre com falha. O pseudocódigo de cálculo de prioridade é o seguinte:

def clusterGetSlaveRank():
    int rank = 0;
    // 获取从节点的主节点
    ClusteRNode master = myself.slaveof;
    // 获取当前从节点复制偏移量
    long myoffset = replicationGetSlaveOffset();
    // 跟其他从节点复制偏移量对比
    for (int j = 0; j < master.slaves.length; j++):
        // rank表示当前从节点在所有从节点的复制偏移量排名, 为0表示偏移量最大.
        if (master.slaves[j] != myself && master.slaves[j].repl_offset > myoffset):
            rank++;
    return rank;
}

Usando a classificação de prioridade acima, atualize o tempo de disparo da eleição, o pseudocódigo é o seguinte:

def updateFailoverTime():
    // 默认触发选举时间: 发现客观下线后一秒内执行。
    server.cluster.failover_auth_time = now() + 500 + random() % 500;
    // 获取当前从节点排名
    int rank = clusterGetSlaveRank();
    long added_delay = rank * 1000;
    // 使用added_delay时间累加到failover_auth_time中
    server.cluster.failover_auth_time += added_delay;
    // 更新当前从节点排名
    server.cluster.failover_auth_rank = rank;

Todos os nós escravos com o maior deslocamento de replicação acionarão o processo de eleição de falha antecipadamente, conforme mostrado na figura a seguir:


3. Iniciar uma eleição

        Quando a detecção da tarefa de temporização do nó escravo atinge o tempo de eleição da falha (failover_auth_time), o processo de eleição é iniciado da seguinte forma:

(1) Atualizar época de configuração

        A época de configuração é um número inteiro que só aumenta e não diminui. Cada nó mestre mantém uma época de configuração (clusterNode.configEpoch) para indicar a versão do nó mestre atual. As épocas de configuração de todos os nós mestres não são iguais, e a época do escravo nodes copiará a época de configuração do node master. O cluster inteiro mantém uma época de configuração global (clusterState.current Epoch), que é usada para registrar a versão máxima da época de configuração de todos os nós mestres no cluster. Execute o comando cluster info para visualizar as informações de época de configuração:

127.0.0.1:6379> cluster info
...
cluster_current_epoch:15 // 整个集群最大配置纪元
cluster_my_epoch:13 // 当前主节点配置纪元

        A época de configuração seguirá a mensagem ping/pong para propagar no cluster. Quando o remetente e o receptor são nós mestres e a época de configuração é igual, significa que há um conflito. A parte com o nodeId maior incrementará o global epoch de configuração e atribua-o ao nó atual para distingui-lo. Conflito, o pseudocódigo é o seguinte:

def clusterHandleConfigEpochCollision(clusterNode sender) :
    if (sender.configEpoch != myself.configEpoch || !nodeIsMaster(sender) || !nodeIsMast
        (myself)) :
    return;
    
    // 发送节点的nodeId小于自身节点nodeId时忽略
    if (sender.nodeId <= myself.nodeId):
        return
        
    // 更新全局和自身配置纪元
    server.cluster.currentEpoch++;
    myself.configEpoch = server.cluster.currentEpoch;

O principal papel da era da configuração:

  1. Indica as diferentes versões de cada nó mestre no cluster e a maior versão do cluster atual.
  2. Toda vez que um evento importante ocorre no cluster, o evento importante aqui se refere ao surgimento de um novo nó mestre (recém-unido ou convertido de um nó escravo), e os nós escravos competem pela eleição. Todos irão incrementar a época de configuração global do cluster e atribuí-la ao nó mestre relevante para registrar este evento chave.
  3. O nó mestre tem uma época de configuração maior para representar o estado atualizado do cluster. Portanto, quando mensagens de ping/pong são trocadas entre nós, se houver inconsistência nas informações chave, como slots, a parte com a época de configuração maior deve prevalecer para evitar desatualização O estado polui o cluster.

Os cenários de aplicação para configurar o epoch são:

  1. Novos nós são adicionados.
  2. Detecção de colisão de mapeamento de nó de slot.
  3. Votação do nó escravo para detecção de conflito eleitoral.

Dicas de desenvolvimento

        Anteriormente, ao modificar o mapeamento do nó do slot por meio do comando cluster setslot, era necessário garantir que a época de configuração local (configEpoch) do nó mestre que executava a solicitação fosse o valor máximo, caso contrário as informações do slot modificado não seriam transmitidas ao nó com uma época de configuração mais alta durante a propagação da mensagem. Como o mecanismo de comunicação Gossip não pode saber com precisão qual nó é a maior época de configuração atual, o comando clustersetslot{slot}node{nodeId} no final da tarefa de migração de slot precisa ser executado uma vez em todos os nós mestres.

        Toda vez que um nó escravo inicia uma votação, a época de configuração global do cluster será automaticamente incrementada e armazenada separadamente na
variável clusterState.failover_auth_epoch para identificar a versão da eleição iniciada pelo nó escravo desta vez.

(2) Transmitir mensagem eleitoral

        Transmita a mensagem de eleição (FAILOVER_AUTH_REQUEST) no cluster e registre o status da mensagem que foi enviada para garantir que o nó escravo só possa iniciar uma eleição dentro de uma época de configuração. O conteúdo da mensagem é o mesmo da mensagem de ping, mas o tipo é alterado para FAILOVER_AUTH_REQUEST.

4. Votação eleitoral

        Somente o nó mestre que detém o slot processará a mensagem de eleição de falha (FAILOVER_AUTH_REQUEST), pois cada nó detentor do slot possui um voto único em uma época de configuração, quando recebe a primeira mensagem do nó escravo solicitando um voto Responder à mensagem FAILOVER_AUTH_ACK como um voto , e então as mensagens de eleição de outros nós escravos na mesma época de configuração serão ignoradas.
O processo de votação é, na verdade, um processo de eleição do líder, por exemplo, existem N nós mestres com slots no cluster representando N votos. Como o nó mestre que possui um slot em cada época de configuração só pode votar em um nó escravo, apenas um nó escravo pode obter N/2+1 votos, garantindo que o único nó escravo possa ser encontrado.

        O cluster Redis não usa nós escravos diretamente para a eleição do líder, principalmente porque o número de nós escravos deve ser maior ou igual a 3 para garantir que haja nós N/2+1 suficientes, o que levará ao desperdício de recursos dos nós escravos. A eleição do líder é realizada utilizando todos os nós mestres que possuem slots no cluster, mesmo que haja apenas um nó escravo para completar o processo de eleição.

        Quando o nó escravo coleta os votos de N/2+1 nós mestres com slots, o nó escravo pode realizar a operação de substituição do nó mestre. Por exemplo, existem 5 nós mestres com slots no cluster e 4 mestres nós após a falha do nó mestre b. Quando um dos nós escravos coleta 3 votos, o representante tem votos suficientes para substituir o nó mestre, conforme mostrado na figura a seguir:

Dicas de operação e manutenção

        O nó mestre defeituoso também é contado no número de votos. Supõe-se que a escala de nós no cluster seja de 3 mestres e 3 escravos, dos quais 2 nós mestres são implantados em uma máquina. os nós não podem coletar 3/3 2+1 votos primários causarão falha no failover. Esta questão também se aplica ao link de localização de falhas. Portanto, ao implantar um cluster, todos os nós mestres precisam ser implantados em pelo menos 3 máquinas físicas para evitar problemas de ponto único.

        Votação nula: Cada época de configuração representa um ciclo de eleição. Se um número suficiente de votos não for obtido dos nós dentro do período cluster-node-timeout*2 após o início da votação, a eleição será anulada. O nó escravo incrementa a época de configuração e inicia a próxima rodada de votação até que a eleição seja bem-sucedida.

5. Substitua o nó mestre

Quando votos suficientes são coletados dos nós escravos, a operação de substituição do nó mestre é acionada:

  1. O nó escravo atual cancela a replicação e se torna o nó mestre.
  2. Execute a operação clusterDelSlot para revogar os slots pelos quais o mestre defeituoso é responsável e execute clusterAddSlot para delegar esses slots a si mesmo.
  3. Transmita sua própria mensagem pong para o cluster, informando a todos os nós do cluster que o nó escravo atual se tornou o nó mestre e assumiu as informações de slot do nó mestre defeituoso.

tempo de failover

        Após introduzir o processo de descoberta e recuperação de falhas, podemos estimar o tempo de failover neste momento:

  1. Tempo de identificação subjetiva offline (pfail) = cluster-node-timeout.
  2. Tempo de propagação da mensagem de status offline subjetiva <=cluster-node-timeout/2.
    1. O mecanismo de comunicação de mensagens enviará uma mensagem de ping para os nós não comunicantes que excederem o tempo limite do cluster-node-time/2, e o corpo da mensagem dará prioridade ao nó do estado offline ao selecionar quais nós incluir, geralmente mais da metade dos os nós mestres podem ser coletados durante esse período de tempo.pfail reporte para concluir a descoberta de falhas.
  3. Tempo de transferência do escravo <= 1000 ms.
    1. Devido ao mecanismo de eleição atrasada, o nó escravo com o maior deslocamento atrasará a eleição em no máximo 1 segundo. Normalmente a primeira eleição será bem sucedida, então o tempo para o nó escravo realizar a transferência é menor que 1 segundo.

Com base na análise acima, o tempo de failover pode ser estimado da seguinte forma:

failover-time(毫秒) ≤ cluster-node-timeout + cluster-node-timeout/2 + 1000

        Portanto, o tempo de failover está intimamente relacionado ao parâmetro cluster-node-timeout, cujo padrão é 15 segundos. Durante a configuração, ajustes apropriados podem ser feitos de acordo com a tolerância do negócio, mas quanto menor melhor, o consumo de largura de banda será melhor explicado na próxima seção.

Simulação de failover

        Os principais detalhes do failover foram apresentados até o momento.A seguir, uma análise do comportamento do failover simulando o cenário de falha do nó mestre através do cluster construído anteriormente. Use kill-9 para forçar o encerramento do processo do nó mestre 6385, conforme mostrado na figura a seguir:

 Confirme o status do cluster:

Forçar o fechamento do processo 6385:

análise de log

1. A replicação entre o nó escravo 6386 e o ​​nó mestre 6385 é interrompida e o log é o seguinte:

2. Ambos os nós mestres 6379 e 6380 marcaram 6385 como offline subjetivo e mais da metade deles foram marcados como status offline objetivo, e os seguintes logs foram impressos:

3. O nó escravo identifica o nó mestre que está replicando e prepara o tempo de eleição após entrar no objetivo offline.O log imprime o atraso de eleição de 964 milissegundos e o executa, e imprime o deslocamento de replicação do nó escravo atual.

4. Após a chegada do tempo de eleição atrasada, o nó escravo atualiza a época de configuração e inicia uma eleição de falha.

5. Os nós mestres 6379 e 6380 votam no nó escravo 6386, o log é o seguinte:


6. Após obter 2 votos do nó mestre do nó, mais da metade deles realiza a operação de substituição do nó mestre para concluir o failover:

Restaurar um nó manualmente

        Após a conclusão bem-sucedida do failover, recuperamos o nó 6385 com falha e observamos se o status do nó está correto:

1) Reinicie o nó com falha 6385.

 2) Depois que o nó 6385 for inicializado e descobrir que seu slot responsável está atribuído a outro nó, a configuração de cluster existente deverá prevalecer e se tornar o nó escravo do novo nó mestre 6386. O registro de chaves é o seguinte:

3) Outros nós no cluster recebem a mensagem de ping de 6385 e limpam o status offline do objetivo:

4) O nó 6385 torna-se o nó escravo e inicia o processo de replicação para o nó mestre 6386:

5) O estado final do cluster é mostrado na figura abaixo.

 6386 torna-se mestre e 6385 torna-se seu escravo

Outros URLs

"Desenvolvimento e operação do Redis" => Capítulo 10 Clustering => 10.6 Failover

Acho que você gosta

Origin blog.csdn.net/feiying0canglang/article/details/123580874
Recomendado
Clasificación