O que evitar no Cassandra
- Postado por Adriano Bonacin
- Categorias cassandra
- Data 23/06/2023
- Comentários 0 comentário
Introdução
No último artigo conversamos um pouco sobre o Apache Cassandra, um banco de dados NoSQL. O Cassandra tem características que todo mundo quer: um banco de dados multi-primary, tolerante a falhas, globalmente distribuído, fácil de escalar e com uma linguagem muito próxima de SQL. Isso faz com que pessoas façam uma má escolha na hora de selecionar o banco de dados do seu projeto. Vamos tentar falar aqui de casos em que o Cassandra não joga muito bem e quando não usá-lo.
Talvez pareça uma cópia do artigo do John Schulz (in memoriam), mas não é. Eu confesso que li este artigo várias vezes e leio toda vez que vou falar sobre casos de uso. Então a sensação é apenas porque ele me influenciou muito.
O que eu vejo por aí são bastante casos de uso, então para ser um pouco diferente, vou escrever sobre algumas coisas que sinalizam que você está usando o Cassandra de forma errada ou que você deve evitar quando tem um cluster Cassandra.
Flexibilidade nas queries
Mais de uma centena de vezes na minha vida eu tive que lidar com pessoas que querem extrair dados do Cassandra e não conseguem. E não conseguem mesmo. Sabe por que? Porque o Cassandra não foi projetado para você extrair dados de qualquer jeito.
Se você lembrar da figura do ScyllaDB, dá pra ter uma ideia do problema.
Você só consegue extrair dados informando o valor da Partition Key (aqui representado por Row A, Row B). Qualquer outra opção vai ser um problema. E a comunidade/empresas tentam lidar com isso, hoje há secondary index, materialized view, umas outras formas de attached index e até uma integração do Cassandra com Solr no Datastax Search (vamos falar dos produtos Datastax mais adiante). Tudo isso para tentar contornar a falta de flexibilidade nas queries do Cassandra.
Uma das primeiras coisas que a gente aprende quando vamos estudar modelagem de dados no Cassandra é que ele é Query Driven. Se você começa a modelar suas tabelas no Cassandra sem conhecer essa característica, você pode ter problemas em um futuro não muito distante. Então eu diria que grande parte dos casos dos maus casos de uso estão relacionados com isso.
Banco de dados DW
Se tem uma coisa que o Cassandra não é bom, é para ambientes DW. Se você precisa de funções de agregação, como SUM, AVG, MAX, MIN, COUNT, você pode fazer isso por Partition Key (PK). No exemplo da figura anterior, você pode agregar se filtrar por Row A. Porém, normalmente isso não é exatamente o que um banco de dados DW precisa.
Você pode pensar, que tal ter uma tabela com vendas_por_uf onde a gente concentra todas as vezes de determinada UF em uma única PK. Aí temos um outro problema: Cassandra não gosta de partições grandes, acima de 100MB. A leitura fica bastante comprometida nestes casos, embora versões mais recentes tenham evoluído um pouco neste aspecto.
Via de regra use sempre uma leitura envolvendo apenas um PK, você será mais feliz.
Update/Delete
Outra grande parte dos casos problemáticos está relacionada com alteração/deleção de linhas. O Cassandra não nasceu para isso. O problema é bem mais complicado que isso, mas vou tentar sintetizar. Pense que o Cassandra usa uma estratégia parecida com a do PostgreSQL para atualizar linhas. Se você tentar alterar um registro, ele insere um novo registro e ignora o antigo. Se você deleta uma linha, ele não a deleta de fato. Apenas marca o registro como deletado.
Aí você pode pensar: mas o PostgreSQL consegue lidar com isso usando o vacuum, e funciona muito bem. Sim é verdade, mas o Cassandra tem outros problemas pelo fato de ser distribuído. E com isso ele não lida bem com updates e deletes. Se você usa seu Cassandra como fila, saiba que isso é quase um crime.
Ainda na linha de alterar registros uma coisa que você deve evitar ainda mais é fazer uma leitura antes da escrita. Parece um detalhe pequeno, mas isso limita muito a escalabilidade do seu cluster.
Normalização
Outras coisas que você não encontra no Cassandra são joins. Se você quer usar as tradicionais regras de normalização, você está no lugar errado. Muito pelo contrário, inclusive, o Cassandra prega a desnormalização. Significa você ter os mesmos dados em tabelas diferentes. Como no caso citamos anteriormente, uma tabela chamada compras_por_id em que a PK é o id_compra e você busca pelo id_compra e uma outra tabela com os mesmos dados chamada compras_por_cliente onde o id_cliente é a PK e você busca compras por id_cliente. Além disso, se você precisar do nome do cliente você vai precisar incluir o nome_cliente em ambas as tabelas.
Você pode estar se perguntando: mas isso é eficiente? Bom, aí já é outra história: o Cassandra sempre pregou Hardware (HW) commodity, o que teoricamente implica você ter discos suficientes por um preço baixo.
Hardware
Vou aproveitar o assunto para incluir aqui cuidados que precisamos ter com HW. Quando citamos HW commodity não quer dizer hardware ruim, antigo ou algo assim. É só um hardware não especializado. Se você roda o Oracle em um Exadata você tira benefícios de um hardware altamente especializado para Oracle. Aqui não temos essa necessidade, mas temos que ter alguns cuidados.
No Cassandra não há smart features no hardware, os únicos requisitos são evitar SAN a qualquer custo para ambientes on-premises com muitas requisições, dê preferência ao tradicional “disco na barriga”. O próprio banco de dados tem replicação para garantir redundância e alta disponibilidade, então nem precisa de RAID.
Não use NAS ou NFS em hipótese alguma! Mas você já ouviu falar que o Astra DB armazena as SSTables em um Object Storage, então por que não usar o mesmo no seu Cassandra? Bom, AstraDB é um caso à parte. Tem muita adaptação para que funcione dessa forma, o que não há, pelo menos ainda, no Cassandra.
Memória
Aqui entra nossa boa e velha JVM. O Cassandra é escrito em Java e por isso a JVM é utilizada. Há um tamanho mínimo de HEAP recomendado: 8GB. Se você quer um ambiente de desenvolvimento ou teste, saiba que uma HEAP menor que isso pode te trazer problemas que não estão relacionados com sua query ou modelo de dados.
E no outro extremo, HEAP muito grande não vai te levar a um ganho de performance. Via de regra você não deve passar de 32GB, normalmente usamos um máximo de 31GB. Por que 31? Veja a resposta aqui. Concluindo, não use menos de 8GB nem mais de 31GB.
Transação
Há uma expectativa de que com o Cassandra 5.0 a gente evolua nesse sentido, mas no momento em que escrevo este artigo, isso ainda é uma promessa. O novo Cassandra deve usar um outro algoritmo que deve permitir utilizar uma transação para modificar seus dados.
Fato é que no momento não temos isso. Se você está acostumado com seu banco relacional em que você pode escrever e desfazer o que foi feito com rollback, lamento informar, mas isso não é possível aqui. Se você precisa garantir que as escritas ocorram e sejam replicadas para todos os nodes envolvidos, você pode aumentar a consistência da escrita para ALL. Isso vai fazer com que todos os nodes deem um ACK para que a app receba o OK. Mas isso está longe de ser uma transação ACID como estamos acostumados.
Consistência forte
Nativamente a consistência não é o forte do Cassandra, mas isso é ajustável. Mas vale citar que ajustar isso por ter implicações em disponibilidade. Exemplo: quero que minha escrita seja feita em todos os nodes (ALL). Se um node estiver indisponível, sua escrita falha. Então via de regra, não use Cassandra se você precisar de consistência forte. Se você tentar forçar a consistência você pode cair em cenários de indisponibilidade, que é o oposto do que o Cassandra te oferece.
Conclusão
Tomara que vocês não tenham desistido de usar Cassandra após esse post. Estes são os principais problemas que tenho visto ultimamente, mas devem existir mais. Espero que tenham gostado dos pontos que citei. Caso você deseje conversar sobre algum deles em detalhes ou tenha alguma sugestão para acrescentar, por favor use os comentários ou nos procure em alguma rede social.