KeyDB como [potencial] substituto do Redis

No Habr não há análises de "alternativa mais rápida ao Redis" — KeyDB. Após adquirir uma experiência bastante recente com seu uso, gostaria de preencher essa lacuna.

KeyDB como [potencial] substituto do Redis

A história é bastante banal: um dia, com um grande aumento no tráfego, foi registrada uma significativa degradação do desempenho do aplicativo (ou seja, do tempo de resposta). Naquele momento, infelizmente, não conseguimos realizar um diagnóstico adequado do que estava acontecendo, então planejou-se uma série de testes de carga. Após a realização desses testes, conseguimos identificar o ponto crítico, que se revelou ser o cache de banco de dados no Redis. Como muitas vezes acontece, o problema não poderia ser resolvido instantaneamente e da maneira correta — pelos desenvolvedores (mudando a lógica de trabalho). Assim, surgiu a curiosidade e o desejo de contornar a situação. E assim surgiu este artigo.

Problemas

Sobre o Redis em geral

Como muitos sabem, o Redis é um banco de dados de thread única. Para ser mais preciso, ele é assim no que diz respeito ao trabalho com dados do usuário. Desde a quarta versão, operações internas e de serviço do Redis traduzido têm execução paralela. No entanto, essa mudança afetou apenas uma pequena parte da carga, uma vez que o principal trabalho gira em torno dos dados do usuário.

Sobre esse tema, inúmeras discussões foram travadas, mas os desenvolvedores do Redis teimosamente não querem implementar uma paralelização completa, mencionando o quão complicado isso tornaria o aplicativo e aumentaria os custos indiretos, além de introduzir mais bugs. A sua posição é a seguinte: se você está enfrentando o problema da unicidade de núcleo — você tem problemas com a arquitetura do aplicativo e algo precisa mudar. No entanto, entre os usuários, há também "outro lado" — daqueles que se empacaram em um único núcleo e afirmam que o Redis cria um gargalo para si mesmo. Em casos de cargas realmente grandes — cedo ou tarde — o confronto com esse problema é inevitável, o que impõe limitações significativas à arquitetura e/ou complicações forçadas nela.

Não vou avaliar uma opinião ou outra. Em vez disso, compartilharei nosso caso específico e como o resolvemos.

Nosso caso

Em um dos projetos, encontramos um problema em que a equipe de desenvolvimento configurou um cache de dados do banco de dados (PostgreSQL) via Redis de maneira extremamente agressiva. Esta foi a única solução que, durante picos de tráfego, salvou o PostgreSQL da falência e, consequentemente, o aplicativo.

Após uma série de testes de carga, realizamos uma análise da situação e descobrimos que o Redis estava limitando-se a um único núcleo (o que é chamado de ‘no polku’), após o que acontecia uma degradação bastante rápida do aplicativo. O ‘afogamento’ seguia uma progressão geométrica: assim que o limite de desempenho do Redis era alcançado, tudo parava de funcionar.

Parecia mais ou menos assim:

KeyDB como [potencial] substituto do Redis

Do lado do New Relic, o problema foi claramente identificado:

KeyDB como [potencial] substituto do Redis

Aqui estão as estatísticas da operação get no Redis:

KeyDB como [potencial] substituto do Redis

Depois que o problema foi comunicado em detalhes aos desenvolvedores, ficou claro que ‘neste momento, não era possível resolver o problema’. Assim, começaram as buscas por uma solução no lado da operação, e a resposta foi a já mencionada KeyDB.

No entanto, antes de começar a revisão, vale mencionar que o projeto utiliza Redis standalone, pois a solução em cluster baseada em Sentinel apresenta latências muito superiores. Uma das soluções óbvias seria criar várias réplicas do cache: e deixar que o aplicativo acessasse em todos os lugares com balanceamento! Contudo, após discussões com os desenvolvedores, fomos forçados a descartar essa opção devido ao mecanismo ativo e complexo de invalidação de cache do aplicativo. O mesmo problema se aplicava ao particionamento do cache.

Uma rápida visão geral da KeyDB

Em busca de uma possível solução para o problema, descobrimos um aplicativo chamado KeyDB. Este é um fork do Redis, desenvolvido por uma empresa canadense e distribuído sob a licença livre BSD. O projeto é bastante jovem: existe desde o início de 2019. Sua história é que os autores também enfrentaram as limitações do Redis em algum momento... e decidiram criar seu próprio fork. Além disso, ele não apenas resolveu problemas conhecidos, mas também ganhou recursos adicionais, que estão disponíveis apenas na versão enterprise do Redis.

Para quem deseja se aprofundar mais sobre o KeyDB, há um ótimo artigo introdutório no Medium, que apresenta o SGBD e benchmarks resumidos que o comparam com seu ‘pai’ — Redis.

Antes de tudo, o que nos atraiu no KeyDB foi a solução potencial para nossos problemas, além de algumas funcionalidades adicionais que eram interessantes. O uso do KeyDB prometia as seguintes vantagens:

  • obtenção de verdadeiro suporte a múltiplos threads;
  • completa e absoluta compatibilidade com o Redis (para nós, isso foi especialmente importante, pois não era possível realizar quaisquer adaptações do lado do aplicativo), o que também prometia uma migração sem problemas;
  • mecanismo de backup integrado no armazenamento S3;
  • replicação ativa simples de implementar;
  • clusterização e shardização simples sem Sentinel ou qualquer outro software auxiliar.

Mais de 3 mil estrelas e uma variedade de colaboradores no GitHub também pareceram promissores. O aplicativo está em contínuo desenvolvimento e manutenção, o que é visível pelos commits, interações em issues e as PRs fechadas (aceitas). A resposta do principal mantenedor em todas as frentes é sempre amigável e rápida. Em resumo, havia muitos argumentos a favor.

Migração e resultados

Mesmo que o projeto de migração fosse uma espécie de aventura (devido à novidade do KeyDB), não havia muito a perder. Afinal, reverter alterações era bastante rápido e simples — ainda bem que toda a infraestrutura está implantada no Kubernetes, e os mecanismos integrados Rolling Update resolvem bem essas tarefas.

Em geral, preparamos os templates do Helm, mudamos o aplicativo no ambiente de teste para o novo banco de dados e implementamos tudo isso, entregando ao departamento de QA do cliente.

Começou o teste, que durou cerca de uma semana, e não nos aprofundamos nos detalhes. Sabemos apenas que o cliente verificou as funções padrão de trabalho com o Redis usando o driver PHP phpredis, além de realizar testes de QA na interface do usuário. Após isso, recebemos sinal verde: nenhum efeito colateral no uso do novo software foi detectado. Ou seja, do ponto de vista do aplicativo, nada realmente mudou..

Vale ressaltar que não alteramos nada na configuração: literalmente — apenas trocamos a imagem utilizada. O mesmo se aplica ao monitoramento e à exportação de métricas para o Prometheus: o mais comum entre eles funciona perfeitamente com o KeyDB e sem quaisquer modificações. Assim, pode-se afirmar com confiança que, do ponto de vista operacional, esta foi uma mudança simplesmente ideal.

Graças a tudo isso, após a mudança do aplicativo para o novo SGBD, pode-se não modificar nada, e como uma "medida de estabilização" — mantê-lo assim e operá-lo por um tempo em produção. No entanto, se você deseja ver um aumento de desempenho (ou, pelo menos, quaisquer mudanças), não deve esquecer que padrão o parâmetro KeyDB que controla a multithreading (server-threads), é igual a um, ou seja, o SGBD funciona exatamente da mesma forma que o Redis..

Após a troca, testes e um certo tempo de operação no novo aplicativo (com KeyDB), decidimos repetir o teste de carga com os mesmos parâmetros usados para o Redis. Quais foram os resultados?.

No gráfico de consumo da CPU, ficou imediatamente evidente a eliminação dos problemas com o "teto" em um único núcleo: o processo começou a utilizar os recursos disponíveis:

KeyDB como [potencial] substituto do Redis

E, posteriormente, eu tentei bastante "exigir" o aplicativo e observei um consumo que chegava até três núcleos...

Segundo os dados do New Relic, o aplicativo web, em geral, com uma carga semelhante, começou a se comportar de forma significativamente mais adequada. Alguma degradação de desempenho ainda foi observada, no entanto, comparando com o gráfico similar acima, você pode avaliar o progresso significativo:

KeyDB como [potencial] substituto do Redis

O indicador de latência do novo banco de dados (KeyDB) também piorou, mas permaneceu dentro de limites aceitáveis:

KeyDB como [potencial] substituto do Redis

No próximo gráfico, fica claro que o número de solicitações para a própria KeyDB é semelhante:

KeyDB como [potencial] substituto do Redis

Resumindo esses testes sintéticos, pode-se dizer que tanto o Redis quanto o KeyDB mostram uma degradação significativa de desempenho em latência (40 ms+) com um aumento substancial no número de conexões paralelas (1000+). No nosso caso, o aplicativo web conseguia "reduzir" a latência do Redis mesmo com um número de conexões mais baixo (400+), embora para o KeyDB essa carga permanecesse aceitável.

Como resultado, obtemos um serviço de "monitoramento como serviço", automatizado na linha de produção de integração contínua. O desenvolvedor ou testador precisa apenas definir a lista de métricas em um arquivo JSON, e tudo o mais acontece automaticamente. Obtemos um controle de qualidade transparente dos lançamentos: todas as notificações sobre desempenho, consumo de recursos ou regressões arquitetônicas.

Este exemplo ilustra perfeitamente a força da comunidade de código aberto no desenvolvimento de projetos pelos quais se interessa. Na internet, encontrei uma frase excelente, cujo sentido geral era o seguinte: "Uma grande empresa cria um produto interessante, torna parte de suas funções abertas, mas a parte mais importante permanece paga. A comunidade usa, usa, e depois alguém desiste e faz um fork, implementando aquelas funções pagas e abrindo-as para todos." O KeyDB é exatamente esse caso.

Falando sobre a migração em si, que ocorreu de maneira surpreendentemente simples, não obtivemos um aumento tão significativo no desempenho quanto se poderia esperar ao olhar os gráficos dos autores do KeyDB... No entanto, este é apenas o nosso caso específico, no qual podem existir muitas variações, incluindo a famosa arquitetura do aplicativo (por exemplo, um grande número de comandos get no Redis em vez de uma variante mais eficiente de solicitações agregadas mget…). No entanto, conseguimos obter resultados positivos, juntamente com várias funções úteis que ainda iremos implementar em breve.

De modo geral, o KeyDB parece promissor: à medida que adquirimos experiência prática com este SGBD (que ainda está por vir!) e o projeto avança, consideraremos a possibilidade de sua aplicação em outras situações.

No entanto, não deve-se considerar este artigo como um guia (e muito menos — um apelo) para desistir do Redis em favor do KeyDB. Apesar da nossa experiência positiva, está claro que isso não é uma solução mágica. O caso foi bastante específico: especificamente para resolver um problema imediato em uma situação que exigia uma solução rápida e com custos mínimos, essa solução se mostrou justificável. O KeyDB será útil no seu caso? Pelo menos agora você sabe que essa possibilidade existe.

P.S.

Confira também em nosso blog:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster