Sobre a mudança do Redis para o cluster Redis

Sobre a mudança do Redis para o cluster Redis

Chegando a um produto que vem sendo desenvolvido há mais de uma década, não é nenhuma surpresa encontrar nele tecnologias desatualizadas. Mas e se em seis meses você tiver que manter a carga 10 vezes maior e o custo das quedas aumentar centenas de vezes? Nesse caso, você precisa de um engenheiro Highload legal. Mas, na ausência de empregada, confiaram-me a solução do problema. Na primeira parte do artigo contarei como mudamos do Redis para o Redis-cluster e, na segunda parte, darei conselhos sobre como começar a usar o cluster e o que prestar atenção ao usá-lo.

Seleção de tecnologia

Isso e ruim? Redis separados (redis autônomo) em uma configuração de 1 mestre e N escravos? Por que chamo isso de tecnologia obsoleta?

Não, o Redis não é tão ruim... No entanto, existem algumas deficiências que não podem ser ignoradas.

  • Primeiro, o Redis não oferece suporte a mecanismos de recuperação de desastres após uma falha mestre. Para resolver este problema, utilizamos uma configuração com transferência automática de VIPs para um novo mestre, alterando a função de um dos escravos e trocando os demais. Esse mecanismo funcionou, mas não poderia ser considerado uma solução confiável. Em primeiro lugar, ocorreram alarmes falsos e, em segundo lugar, era descartável e, após a operação, foram necessárias ações manuais para carregar a mola.

  • Em segundo lugar, ter apenas um mestre levou ao problema de fragmentação. Tivemos que criar vários clusters independentes “1 mestre e N escravos”, depois distribuir manualmente os bancos de dados entre essas máquinas e esperar que amanhã um dos bancos de dados não aumentasse tanto a ponto de ter que ser movido para uma instância separada.

Quais são as opções?

  • A solução mais cara e rica é o Redis-Enterprise. Esta é uma solução in a box com suporte técnico completo. Apesar de parecer ideal do ponto de vista técnico, não nos convinha por razões ideológicas.
  • Cluster Redis. Pronto para uso, há suporte para failover mestre e fragmentação. A interface quase não difere da versão normal. Parece promissor, falaremos sobre as armadilhas mais tarde.
  • Tarantool, Memcache, Aerospike e outros. Todas essas ferramentas fazem praticamente a mesma coisa. Mas cada um tem suas próprias deficiências. Decidimos não colocar todos os ovos na mesma cesta. Usamos Memcache e Tarantool para outras tarefas e, olhando para frente, direi que em nossa prática houve mais problemas com eles.

Especificações de uso

Vamos dar uma olhada em quais problemas resolvemos historicamente com o Redis e quais funcionalidades usamos:

  • Cache antes de solicitações para serviços remotos como 2GIS | Golang

    OBTER DEFINIR MGET MSET "SELECIONAR DB"

  • Cache antes do MYSQL | PHP

    GET SET MGET MSET SCAN "CHAVE POR PADRÃO" "SELECIONAR DB"

  • O armazenamento principal para o serviço de trabalho com sessões e coordenadas do motorista | Golang

    GET SET MGET MSET "SELECIONAR DB" "ADICIONAR GEO KEY" "OBTER GEO KEY" SCAN

Como você pode ver, nada de matemática superior. Qual é então a dificuldade? Vejamos cada método separadamente.

método
descrição
Recursos do cluster Redis
Solução

PREPARE-SE
Chave de gravação/leitura

MGET MSET
Escreva/leia várias chaves
As chaves estarão em nós diferentes. Bibliotecas prontas podem realizar múltiplas operações apenas dentro de um nó
Substitua MGET por um pipeline de operações N GET

SELECIONE BD
Selecione a base com a qual trabalharemos
Não suporta vários bancos de dados
Coloque tudo em um banco de dados. Adicione prefixos às chaves

SCAN
Percorra todas as chaves do banco de dados
Como temos um banco de dados, examinar todas as chaves do cluster é muito caro
Mantenha uma invariante dentro de uma chave e faça um HSCAN nesta chave. Ou recuse completamente

GEO
Operações com uma geokey
A geokey não está fragmentada

CHAVE POR PADRÃO
Procurando uma chave por padrão
Como temos um banco de dados, pesquisaremos todas as chaves do cluster. Muito caro
Recusar ou manter o invariante, como no caso do SCAN

Redis vs Redis-cluster

O que perdemos e o que ganhamos ao mudar para um cluster?

  • Desvantagens: perdemos a funcionalidade de vários bancos de dados.
    • Se quisermos armazenar dados logicamente não relacionados em um cluster, teremos que fazer muletas na forma de prefixos.
    • Perdemos todas as operações “base”, como SCAN, DBSIZE, CLEAR DB, etc.
    • As multioperações tornaram-se muito mais difíceis de implementar porque podem exigir acesso a vários nós.
  • Apresenta:
    • Tolerância a falhas na forma de failover mestre.
    • Fragmentação no lado do Redis.
    • Transfira dados entre nós de forma atômica e sem tempo de inatividade.
    • Adicione e redistribua capacidade e cargas sem tempo de inatividade.

Eu concluiria que, se você não precisa fornecer um alto nível de tolerância a falhas, não vale a pena mudar para um cluster, porque pode ser uma tarefa nada trivial. Mas se você escolher inicialmente entre uma versão separada e uma versão em cluster, então você deve escolher um cluster, pois não é pior e, além disso, vai te aliviar de algumas dores de cabeça

Preparando-se para mover

Vamos começar com os requisitos para mudança:

  • Deve ser perfeito. Uma parada completa do serviço por 5 minutos não nos convém.
  • Deve ser o mais seguro e gradual possível. Quero ter algum controle sobre a situação. Não queremos descartar tudo de uma vez e orar pelo botão de reversão.
  • Perda mínima de dados durante a movimentação. Entendemos que será muito difícil mover-se atomicamente, por isso permitimos alguma dessincronização entre os dados no Redis regular e em cluster.

Manutenção de cluster

Pouco antes da mudança, devemos pensar se podemos apoiar o cluster:

  • Gráficos. Usamos Prometheus e Grafana para representar graficamente a carga da CPU, uso de memória, número de clientes, número de operações GET, SET, AUTH, etc.
  • Perícia. Imagine que amanhã você terá um cluster enorme sob sua responsabilidade. Se quebrar, ninguém além de você poderá consertá-lo. Se ele começar a desacelerar, todos correrão em sua direção. Se precisar adicionar recursos ou redistribuir a carga, volte para você. Para não ficar grisalho aos 25 anos, é aconselhável prever esses casos e verificar com antecedência como a tecnologia se comportará sob determinadas ações. Vamos falar sobre isso com mais detalhes na seção “Expertise”.
  • Monitoramento e alertas. Quando um cluster falha, você quer ser o primeiro a saber disso. Aqui nos limitamos a uma notificação de que todos os nós retornam as mesmas informações sobre o estado do cluster (sim, acontece de forma diferente). E outros problemas podem ser percebidos mais rapidamente pelos alertas dos serviços do cliente Redis.

Realocação

Como iremos nos mover:

  • Primeiro de tudo, você precisa preparar uma biblioteca para trabalhar com o cluster. Tomamos o go-redis como base para a versão Go e o alteramos um pouco para nos adequar. Implementamos Multimétodos por meio de pipelines e também corrigimos levemente as regras de repetição de solicitações. A versão PHP teve mais problemas, mas eventualmente decidimos pelo php-redis. Recentemente, eles introduziram o suporte a cluster e, em nossa opinião, parece bom.
  • Em seguida, você precisa implantar o próprio cluster. Isso é feito literalmente em dois comandos baseados no arquivo de configuração. Discutiremos a configuração com mais detalhes abaixo.
  • Para movimentação gradual, usamos o modo seco. Como temos duas versões da biblioteca com a mesma interface (uma para a versão regular e outra para o cluster), não custa nada criar um wrapper que funcione com uma versão separada e duplicar paralelamente todas as solicitações ao cluster, compare as respostas e escreva discrepâncias nos logs (no nosso caso em NewRelic). Assim, mesmo que a versão do cluster seja interrompida durante a implementação, nossa produção não será afetada.
  • Depois de implementar o cluster no modo seco, podemos observar com calma o gráfico de discrepâncias de resposta. Se a taxa de erro se mover lenta mas seguramente em direção a alguma pequena constante, então está tudo bem. Por que ainda existem discrepâncias? Porque a gravação em versão separada ocorre um pouco mais cedo do que no cluster e devido ao microlag, os dados podem divergir. Resta apenas olhar os registros de discrepâncias e, se todos forem explicados pela não atomicidade do registro, podemos seguir em frente.
  • Agora você pode alternar o modo seco na direção oposta. Escreveremos e leremos o cluster e o duplicaremos em uma versão separada. Para que? Durante a próxima semana gostaria de observar o trabalho do cluster. Se de repente acontecer que há problemas no pico de carga, ou não levamos algo em consideração, sempre temos uma reversão de emergência para o código antigo e os dados atuais graças ao modo seco.
  • Resta desativar o modo seco e desmontar a versão separada.

Expertise

Primeiro, brevemente sobre o design do cluster.

Em primeiro lugar, o Redis é um armazenamento de valores-chave. Strings arbitrárias são usadas como chaves. Números, strings e estruturas inteiras podem ser usados ​​como valores. Existem muitos destes últimos, mas para a compreensão da estrutura geral isso não é importante para nós.
O próximo nível de abstração depois das chaves são os slots (SLOTS). Cada chave pertence a um dos 16 slots. Pode haver qualquer número de chaves dentro de cada slot. Assim, todas as chaves são divididas em 383 conjuntos disjuntos.
Sobre a mudança do Redis para o cluster Redis

Em seguida, deve haver N nós mestres no cluster. Cada nó pode ser considerado uma instância separada do Redis que sabe tudo sobre outros nós do cluster. Cada nó mestre contém vários slots. Cada slot pertence a apenas um nó mestre. Todos os slots precisam ser distribuídos entre os nós. Se alguns slots não forem alocados, as chaves neles armazenadas ficarão inacessíveis. Faz sentido executar cada nó mestre em uma máquina lógica ou física separada. Também vale lembrar que cada nó roda apenas em um núcleo, e se você quiser rodar múltiplas instâncias do Redis na mesma máquina lógica, certifique-se de que elas rodem em núcleos diferentes (não tentamos isso, mas em teoria deveria funcionar). . Essencialmente, os nós mestres fornecem fragmentação regular, e mais nós mestres permitem escalar solicitações de gravação e leitura.

Depois que todas as chaves forem distribuídas entre os slots e os slots estiverem espalhados entre os nós mestres, um número arbitrário de nós escravos pode ser adicionado a cada nó mestre. Dentro de cada link mestre-escravo, a replicação normal funcionará. Os escravos são necessários para escalar solicitações de leitura e para failover em caso de falha do mestre.
Sobre a mudança do Redis para o cluster Redis

Agora vamos falar sobre operações que seria melhor poder fazer.

Acessaremos o sistema via Redis-CLI. Como o Redis não possui um único ponto de entrada, você pode realizar as seguintes operações em qualquer um dos nós. Em cada ponto chamo a atenção separadamente para a possibilidade de realizar a operação sob carga.

  • A primeira e mais importante coisa que precisamos é a operação dos nós do cluster. Ele retorna o estado do cluster, mostra uma lista de nós, suas funções, distribuição de slots, etc. Mais informações podem ser obtidas usando informações de cluster e slots de cluster.
  • Seria bom poder adicionar e remover nós. Para este propósito existem operações de encontro e esquecimento de cluster. Observe que o esquecimento do cluster deve ser aplicado a CADA nó, tanto mestres quanto réplicas. E o cluster meet só precisa ser chamado em um nó. Essa diferença pode ser desconcertante, por isso é melhor aprender sobre ela antes de colocar seu cluster em operação. Adicionar um nó é feito com segurança na batalha e não afeta de forma alguma a operação do cluster (o que é lógico). Se você for remover um nó do cluster, certifique-se de que não haja slots restantes nele (caso contrário, você corre o risco de perder o acesso a todas as chaves neste nó). Além disso, não exclua um mestre que possua escravos, caso contrário será realizada uma votação desnecessária para um novo mestre. Se os nós não tiverem mais slots, então este é um pequeno problema, mas por que precisamos de opções extras se podemos excluir os escravos primeiro?
  • Se você precisar trocar à força as posições mestre e escravo, o comando cluster failover servirá. Ao convocá-lo para a batalha, você precisa entender que o mestre não estará disponível durante a operação. Normalmente, a troca ocorre em menos de um segundo, mas não é atômica. Você pode esperar que algumas solicitações ao mestre falhem durante esse período.
  • Antes de remover um nó do cluster, não deve haver slots nele. É melhor redistribuí-los usando o comando cluster reshard. Os slots serão transferidos de um mestre para outro. Toda a operação pode demorar vários minutos, depende do volume de dados que estão sendo transferidos, mas o processo de transferência é seguro e não afeta em nada o funcionamento do cluster. Assim, todos os dados podem ser transferidos de um nó para outro diretamente sob carga e sem se preocupar com sua disponibilidade. No entanto, também existem sutilezas. Em primeiro lugar, a transferência de dados está associada a uma certa carga nos nós destinatário e remetente. Se o nó destinatário já estiver muito carregado no processador, você não deverá carregá-lo com o recebimento de novos dados. Em segundo lugar, assim que não houver mais nenhum slot no mestre remetente, todos os seus escravos irão imediatamente para o mestre para o qual esses slots foram transferidos. E o problema é que todos esses escravos vão querer sincronizar os dados de uma só vez. E você terá sorte se a sincronização for parcial e não completa. Leve isso em consideração e combine as operações de transferência de slots e desabilitação/transferência de escravos. Ou espere que você tenha uma margem de segurança suficiente.
  • O que você deve fazer se, durante a transferência, descobrir que perdeu seus slots em algum lugar? Espero que esse problema não afete você, mas se isso acontecer, há uma operação de correção do cluster. No mínimo, ela espalhará os slots pelos nós em ordem aleatória. Recomendo verificar seu funcionamento removendo primeiro o nó com slots distribuídos do cluster. Como os dados em slots não alocados já não estão disponíveis, é tarde demais para se preocupar com problemas de disponibilidade desses slots. Por sua vez, a operação não afetará os slots distribuídos.
  • Outra operação útil é monitorar. Ele permite que você veja em tempo real toda a lista de solicitações que vão para o nó. Além disso, você pode fazer o grep e descobrir se há o tráfego necessário.

Também vale a pena mencionar o procedimento de failover mestre. Resumindo, existe e, na minha opinião, funciona muito bem. No entanto, não pense que se você desconectar o cabo de alimentação de uma máquina com um nó mestre, o Redis mudará imediatamente e os clientes não perceberão a perda. Na minha prática, a troca ocorre em poucos segundos. Durante este tempo, alguns dados ficarão indisponíveis: a indisponibilidade do mestre é detectada, os nós votam por um novo, os escravos são trocados, os dados são sincronizados. A melhor maneira de ter certeza de que o esquema está funcionando é realizar exercícios locais. Aumente o cluster do seu laptop, dê-lhe uma carga mínima, simule uma falha (por exemplo, bloqueando as portas) e avalie a velocidade de comutação. Na minha opinião, só depois de jogar desta forma por um ou dois dias você poderá ter confiança no funcionamento da tecnologia. Bem, ou espero que o software que metade da Internet usa provavelmente funcione.

Configuração

Muitas vezes a configuração é a primeira coisa que você precisa para começar a trabalhar com a ferramenta, e quando tudo funciona você nem quer mexer na configuração. É preciso algum esforço para se forçar a voltar às configurações e analisá-las com cuidado. Na minha memória, tivemos pelo menos duas falhas graves por desatenção à configuração. Preste atenção especial aos seguintes pontos:

  • timeout 0
    Tempo após o qual as conexões inativas são fechadas (em segundos). 0 - não feche
    Nem todas as nossas bibliotecas conseguiram fechar conexões corretamente. Ao desabilitar esta configuração, corremos o risco de atingir o limite do número de clientes. Por outro lado, se houver tal problema, o encerramento automático das conexões perdidas irá mascará-lo e podemos não perceber. Além disso, você não deve habilitar esta configuração ao usar conexões persistentes.
  • Salvar xy e anexar somente sim
    Salvando um instantâneo RDB.
    Discutiremos questões de RDB/AOF em detalhes abaixo.
  • stop-writes-on-bgsave-error não e slave-serve-stale-data sim
    Se ativado, se o instantâneo RDB for interrompido, o mestre deixará de aceitar solicitações de alteração. Se a conexão com o mestre for perdida, o escravo poderá continuar respondendo às solicitações (sim). Ou vai parar de responder (não)
    Não estamos satisfeitos com a situação em que Redis se transforma em abóbora.
  • repl-ping-escravo-período 5
    Após esse período, começaremos a nos preocupar com a falha do master e é hora de realizar o procedimento de failover.
    Você terá que encontrar manualmente um equilíbrio entre falsos positivos e acionar um failover. Em nossa prática, isso leva 5 segundos.
  • repl-backlog-size 1024 MB e epl-backlog-ttl 0
    Podemos armazenar exatamente esta quantidade de dados em um buffer para uma réplica com falha. Se o buffer acabar, você terá que sincronizar completamente.
    A prática sugere que é melhor definir um valor mais alto. Existem muitos motivos pelos quais uma réplica pode começar a atrasar. Se atrasar, provavelmente seu mestre já está lutando para lidar com a situação e a sincronização completa será a gota d'água.
  • máximo de clientes 10000
    Número máximo de clientes únicos.
    Na nossa experiência, é melhor definir um valor mais alto. O Redis lida perfeitamente com conexões de 10k. Apenas certifique-se de que haja soquetes suficientes no sistema.
  • maxmemory-policy volátil-ttl
    A regra pela qual as chaves são excluídas quando o limite de memória disponível é atingido.
    O que importa aqui não é a regra em si, mas a compreensão de como isso acontecerá. O Redis pode ser elogiado por sua capacidade de funcionar normalmente quando o limite de memória é atingido.

Problemas de RDB e AOF

Embora o próprio Redis armazene todas as informações na RAM, também existe um mecanismo para salvar dados em disco. Mais precisamente, três mecanismos:

  • Instantâneo RDB - um instantâneo completo de todos os dados. Definido usando a configuração SAVE XY e lê “Salve um instantâneo completo de todos os dados a cada X segundos se pelo menos Y chaves tiverem sido alteradas”.
  • Arquivo somente anexado - uma lista de operações na ordem em que são executadas. Adiciona novas operações de entrada ao arquivo a cada X segundos ou a cada Y operações.
  • RDB e AOF são uma combinação dos dois anteriores.

Todos os métodos têm suas vantagens e desvantagens, não vou listar todos, apenas chamarei a atenção para pontos que, na minha opinião, não são óbvios.

Primeiro, salvar um instantâneo RDB requer chamar FORK. Se houver muitos dados, isso poderá travar todo o Redis por um período de alguns milissegundos a um segundo. Além disso, o sistema precisa alocar memória para tal instantâneo, o que leva à necessidade de manter um suprimento duplo de RAM na máquina lógica: se 8 GB forem alocados para Redis, então 16 GB deverão estar disponíveis na máquina virtual com isto.

Em segundo lugar, existem problemas com a sincronização parcial. No modo AOF, quando o escravo é reconectado, em vez da sincronização parcial, a sincronização completa pode ser realizada. Por que isso acontece, eu não conseguia entender. Mas vale a pena lembrar disso.

Esses dois pontos já nos fazem pensar se realmente precisamos desses dados no disco se tudo já estiver duplicado pelos escravos. Os dados só podem ser perdidos se todos os escravos falharem, e este é um problema de “incêndio no DC”. Como compromisso, você pode propor salvar dados apenas em escravos, mas neste caso você precisa ter certeza de que esses escravos nunca se tornarão mestres durante a recuperação de desastres (para isso há uma configuração de prioridade de escravo em sua configuração). Para nós mesmos, em cada caso específico pensamos se é necessário salvar os dados em disco, e na maioria das vezes a resposta é “não”.

Conclusão

Concluindo, espero ter conseguido dar uma ideia geral de como funciona o redis-cluster para quem nunca ouviu falar dele, e também ter chamado a atenção para alguns pontos não óbvios para quem já o utiliza por muito tempo.
Obrigado pelo seu tempo e, como sempre, comentários sobre o tema são bem-vindos.

Fonte: habr.com

Adicionar um comentário