Migração de Cassandra para Kubernetes: recursos e soluções



Encontramos regularmente o banco de dados Apache Cassandra e a necessidade de operá-lo dentro da estrutura da infraestrutura baseada no Kubernetes. Neste artigo, compartilharemos nossa visão das etapas, critérios e soluções existentes necessários (incluindo uma visão geral dos operadores) para a migração do Cassandra para os K8s.

"Quem pode controlar uma mulher vai lidar com o estado"


Quem é Cassandra? É um sistema de armazenamento distribuído projetado para gerenciar grandes quantidades de dados enquanto fornece alta disponibilidade sem um único ponto de falha. O projeto dificilmente precisa de uma longa introdução; portanto, apresentarei apenas os principais recursos do Cassandra, que serão relevantes no contexto de um artigo específico:

  • Cassandra é escrito em Java.
  • A topologia do Cassandra inclui vários níveis:
    • Nó - uma instância implantada do Cassandra;
    • Rack - um grupo de instâncias do Cassandra, unidas por qualquer atributo, localizadas em um data center;
    • Datacenter - a totalidade de todos os grupos de instâncias do Cassandra localizadas em um datacenter;
    • Cluster - uma coleção de todos os data centers.
  • Cassandra usa um endereço IP para identificar o host.
  • Para a velocidade das operações de leitura e gravação, o Cassandra armazena parte dos dados na RAM.

Agora, para o potencial real, mude para o Kubernetes.

Lista de verificação para migração


Falando sobre a migração de Cassandra para Kubernetes, esperamos que seja mais conveniente gerenciá-lo com a mudança. O que será necessário para isso, o que ajudará nisso?

1. armazenamento de dados


Como já especificado, parte dos dados que o Cassanda armazena na RAM - no Memtable . Mas há outro dado que é salvo no disco - na forma de SSTable . A esses dados é adicionada a entidade Log Log - registros de todas as transações que também são salvas no disco.


Esquema de transação de gravação de Cassandra

No Kubernetes, podemos usar o PersistentVolume para armazenar dados. Graças a mecanismos bem desenvolvidos, trabalhar com dados no Kubernetes se torna mais fácil a cada ano.


Para cada pod com Cassandra, alocaremos nosso PersistentVolume

É importante observar que o próprio Cassandra implica replicação de dados, oferecendo mecanismos internos para isso. Portanto, se você estiver construindo um cluster Cassandra a partir de um grande número de nós, não será necessário usar sistemas distribuídos como Ceph ou GlusterFS para armazenar dados. Nesse caso, será lógico armazenar dados no disco host usando discos persistentes locais ou hostPath montagem.

Outra pergunta é se você deseja criar um ambiente de desenvolvimento separado para cada ramo de recurso. Nesse caso, a abordagem correta seria aumentar um nó Cassandra e armazenar os dados no armazenamento distribuído, ou seja, Ceph e GlusterFS mencionados serão sua opção. Em seguida, o desenvolvedor garantirá que ele não perderá os dados de teste, mesmo que um dos nós do cluster Kuberntes seja perdido.

2. Monitoramento


Uma opção praticamente não alternativa para monitoramento no Kubernetes é o Prometheus (falamos sobre isso em detalhes no relatório correspondente ) . Como está Cassandra com os exportadores métricos de Prometheus? E o que é ainda mais importante de alguma forma, com os painéis adequados para eles para o Grafana?


Um exemplo da aparência de gráficos em Grafana para Cassandra

Existem apenas dois exportadores: jmx_exporter e cassandra_exporter .

Nós escolhemos o primeiro para nós mesmos, porque:

  1. O JMX Exporter está crescendo e se desenvolvendo, enquanto o Cassandra Exporter não conseguiu o suporte adequado da comunidade. O Cassandra Exporter ainda não suporta a maioria das versões do Cassandra.
  2. Você pode executá-lo como javaagent adicionando o sinalizador -javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180 .
  3. Para ele, existe um painel de controle adequado que é incompatível com o Cassandra Exporter.

3. Seleção de primitivas Kubernetes


De acordo com a estrutura acima do cluster Cassandra, tentaremos traduzir tudo o que está descrito lá na terminologia do Kubernetes:

  • Nó Cassandra → Pod
  • Cassandra Rack → StatefulSet
  • Cassandra Datacenter → pool de StatefulSets
  • Cassandra Cluster → ???

Acontece que falta alguma entidade adicional para gerenciar todo o cluster Cassandra de uma só vez. Mas se algo não estiver lá, podemos criá-lo! O Kubernetes possui um mecanismo de definição de recurso dedicado chamado Definições de Recursos Customizados .


Anúncio de recursos adicionais para logs e alertas

Mas o recurso personalizado por si só não significa nada: você precisa de um controlador para ele. Talvez você precise recorrer à ajuda de um operador Kubernetes ...

4. Identificação de vagens


No ponto acima, concordamos que um nó Cassandra seria igual a um pod no Kubernetes. Mas os endereços IP do pod serão diferentes a cada vez. E a identificação do nó no Cassandra ocorre precisamente com base no endereço IP ... Acontece que após cada remoção do pod, o cluster do Cassandra adiciona um novo nó.

Existe uma saída, e nem uma:

  1. Podemos manter registros por identificadores de host (UUIDs que identificam exclusivamente instâncias do Cassandra) ou por endereços IP e salvar tudo isso em algumas estruturas / tabelas. O método tem duas principais desvantagens:

    • O risco de uma condição de corrida quando dois nós caem ao mesmo tempo. Após a atualização, os nós do Cassandra solicitarão simultaneamente um endereço IP da tabela e competirão pelo mesmo recurso.
    • Se o nó Cassandra perdeu seus dados, não poderemos mais identificá-los.
  2. A segunda solução parece um pequeno hack, mas mesmo assim: podemos criar um Serviço com ClusterIP para cada nó do Cassandra. Problemas com esta implementação:

    • Se houver muitos nós em um cluster Cassandra, teremos que criar muitos serviços.
    • O recurso ClusterIP é implementado através do iptables. Isso pode ser um problema se o cluster Cassandra tiver muitos nós (1000 ... ou até 100?). Embora o balanceamento baseado no IPVS possa resolver esse problema.
  3. A terceira solução é usar uma rede de nós para nós Cassandra em vez de uma rede de pod dedicada, ativando a configuração hostNetwork: true . Este método impõe certas restrições:

    • Para substituir os nós. É necessário que o novo host tenha o mesmo endereço IP do anterior (em nuvens como AWS, GCP, isso é quase impossível);
    • Usando a rede de nós de cluster, começamos a competir por recursos de rede. Portanto, colocar um nó de cluster em mais de um pod com o Cassandra será problemático.

5. Backups


Queremos manter a versão completa dos dados para um nó Cassandra em um planejamento. O Kubernetes oferece uma oportunidade conveniente usando o CronJob , mas aqui Cassandra insere as varas nas rodas.

Deixe-me lembrá-lo de que parte dos dados que Cassandra armazena na memória. Para fazer um backup completo, você precisa transferir dados da memória ( Memtables ) para o disco ( SSTables ). Nesse ponto, o nó Cassandra para de aceitar conexões, completamente desligado do cluster.

Depois disso, um backup ( instantâneo ) é removido e o esquema (espaço de chave ) é salvo . E acontece que apenas um backup não nos fornece nada: você precisa salvar os identificadores de dados pelos quais o nó Cassandra foi responsável - esses são tokens especiais.


Distribuição de token para identificar quais dados são responsáveis ​​pelos nós Cassandra

Um exemplo de script para remover o Cassandra do Google no Kubernetes pode ser encontrado neste link . O único ponto que o script não leva em consideração é descarregar dados no nó antes de remover a captura instantânea. Ou seja, o backup é realizado não para o estado atual, mas para o estado um pouco antes. Mas isso ajuda a não tirar o nó do trabalho, o que parece muito lógico.

 set -eu if [[ -z "$1" ]]; then info "Please provide a keyspace" exit 1 fi KEYSPACE="$1" result=$(nodetool snapshot "${KEYSPACE}") if [[ $? -ne 0 ]]; then echo "Error while making snapshot" exit 1 fi timestamp=$(echo "$result" | awk '/Snapshot directory: / { print $3 }') mkdir -p /tmp/backup for path in $(find "/var/lib/cassandra/data/${KEYSPACE}" -name $timestamp); do table=$(echo "${path}" | awk -F "[/-]" '{print $7}') mkdir /tmp/backup/$table mv $path /tmp/backup/$table done tar -zcf /tmp/backup.tar.gz -C /tmp/backup . nodetool clearsnapshot "${KEYSPACE}" 

Exemplo de script bash para remover o backup de um único nó Cassandra

Soluções prontas para Cassandra em Kubernetes


O que eles estão usando atualmente para implantar o Cassandra no Kubernetes e qual deles é mais adequado para os requisitos fornecidos?

1. Soluções StatefulSet ou Helm Chart


Usar o StatefulSets básico para iniciar um cluster Cassandra é uma boa opção. Usando o gráfico Helm e os modelos Go, você pode fornecer ao usuário uma interface flexível para implementar o Cassandra.

Geralmente isso funciona bem ... até que algo inesperado aconteça - por exemplo, um nó fica inoperante. As ferramentas padrão do Kubernetes simplesmente não podem levar em consideração todos os recursos acima. Além disso, essa abordagem é muito limitada em como pode ser expandida para uso mais complexo: substituição de nó, backup, restauração, monitoramento etc.

Representantes:


Ambos os gráficos são igualmente bons, mas são propensos aos problemas descritos acima.

2. Soluções baseadas no operador Kubernetes


Essas opções são mais interessantes porque fornecem amplos recursos de gerenciamento de cluster. Para projetar uma instrução Cassandra, como qualquer outro banco de dados, um bom padrão se parece com o Sidecar <-> Controller <-> CRD:


Diagrama de gerenciamento de nós em uma instrução Cassandra projetada corretamente

Considere os operadores existentes.

1. Cassandra-operator por instaclustr


  • Github
  • Disposição: Alfa
  • Licença: Apache 2.0
  • Implementado em: Java

Este é realmente um projeto muito promissor e de rápido desenvolvimento de uma empresa que oferece implantações gerenciadas pelo Cassandra. Como descrito acima, ele usa um contêiner lateral que aceita comandos via HTTP. Como é escrito em Java, às vezes falta a funcionalidade mais avançada da biblioteca client-go. Além disso, o operador não suporta Racks diferentes para um Datacenter.

Mas o operador tem vantagens como suporte ao monitoramento, gerenciamento de cluster de alto nível usando CRD e até documentação sobre remoção de backups.

2. Navegador por Jetstack


  • Github
  • Disposição: Alfa
  • Licença: Apache 2.0
  • Implementado em: Golang

Uma declaração para implantar o DB como serviço. Atualmente, suporta dois bancos de dados: Elasticsearch e Cassandra. Possui soluções interessantes como controle de acesso ao banco de dados via RBAC (para isso, seu próprio navegador-apiserver separado é gerado). Um projeto interessante, que valeria uma olhada mais de perto, mas o último commit foi feito há um ano e meio, o que reduz claramente seu potencial.

3. Cassandra-operator de vgkowski


  • Github
  • Disposição: Alfa
  • Licença: Apache 2.0
  • Implementado em: Golang

Eles não o consideraram "sério", já que o último commit no repositório ocorreu há mais de um ano. O desenvolvimento do operador é abandonado: a versão mais recente do Kubernetes, declarada como suportada, é 1.9.

4. Cassandra-operador de Rook


  • Github
  • Disposição: Alfa
  • Licença: Apache 2.0
  • Implementado em: Golang

Um operador cujo desenvolvimento não está indo tão rápido quanto gostaríamos. Ele possui uma estrutura CRD bem pensada para gerenciar o cluster, resolve o problema de identificação de nós usando o Service with ClusterIP (o mesmo "hack") ... mas por enquanto é tudo. No momento, não há monitoramento e backups prontos (a propósito, começamos a nos monitorar). Um ponto interessante é que, usando esse operador, você também pode implantar o ScyllaDB.

Nota: Utilizamos este operador com pequenas modificações em um de nossos projetos. Não houve problemas no trabalho do operador durante toda a operação (~ 4 meses de operação).

5. CassKop da Orange


  • Github
  • Disposição: Alfa
  • Licença: Apache 2.0
  • Implementado em: Golang

O operador mais jovem da lista: o primeiro commit foi realizado em 23 de maio de 2019. Ele já possui em seu arsenal um grande número de recursos de nossa lista, cujos detalhes podem ser encontrados no repositório do projeto. O operador é baseado no popular operator-sdk. Suporta monitoramento pronto para uso. A principal diferença de outros operadores é o uso do plug-in CassKop , implementado em Python e usado para comunicação entre os nós Cassandra.

Conclusões


O número de abordagens e as opções possíveis para transportar Cassandra para Kubernetes fala por si: o tópico está em demanda.

Nesse estágio, você pode tentar um dos itens acima por sua própria conta e risco: nenhum dos desenvolvedores garante 100% do trabalho de sua solução no ambiente de produção. Mas agora, muitos produtos parecem promissores para tentar usá-los em estandes de desenvolvimento.

Eu acho que no futuro essa mulher no navio terá que partir!

PS


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt475036/


All Articles