Comparando clustering Cassandra com Mysql database

Matheus Ricardo dos Santos
6 min readApr 25, 2021

Este artigo contém um tutorial de como configurar um cluster local do cassandra utilizando docker e uma comparação de desempenho com o Mysql.

1. Introdução

O objetivo deste artigo é ressaltar os pontos fortes e fracos de cada um dos sistemas de gerenciamento de banco de dados. Portanto, os resultados não devem ser utilizados para julgar qual o melhor sistema. Esta decisão depende do problema a ser resolvido.

Os arquivos e as queries utilizados neste artigo estão disponíveis no seguinte repositório:

https://github.com/MatheusrdSantos/cassandra-mysql-benchmark

2. Configurando o Cluster Cassandra

Para construir as instâncias do cluster precisamos de uma imagem docker. Para isso, utilizaremos a imagem oficial do Cassandra. Serão utilizadas três instâncias que estarão rodando na mesma rede. Cada uma delas possui 2GB de RAM disponível para a execução dos processos.

Também utilizaremos o docker-compose para automatizar o processo de criação das instâncias.

É importante que os três nodes estejam rodando na mesma rede e que declaremos os nodes que serão seeds como variável de ambientes. Desta forma o cassandra consegue garantir que cada node tenha o endereço de seus vizinhos.

Cada um dos nodes também deve ser exposto para uma porta diferente em seu computador. Isto é necessário caso você queira testar requests a diferentes nodes do cluster.

Caso você queria armazenar os dados de cada node em um diretório externo ao docker você deve mapear o diretório /var/lib/cassandra para algum diretório local em sua máquina.

Após a criação do arquivo docker-compose.yml basta rodar o seguinte comando no terminal:

docker-compose up -d

3. Configurando o Mysql

A configuração do Mysql é mais simples, basta seguir o tutorial disponível no DockerHub da imagem oficial: https://hub.docker.com/_/mysql

Também podemos utiliazar o docker-compose para automatizar o processo de criação e execução da instância Mysql:

Para garantir as mesmas circunstâncias de teste, a instância do Mysql foi limitada a utilizar o total de RAM das três instâncias do cassandra somadas (6GB).

4. Dados utilizados

Para popular os bancos de dados foi utilizado um dataset que cotém as cidades do mundo: https://simplemaps.com/data/world-cities. Em sua versão gratuita o banco de dados conta com 26 mil cidades cadastradas. Estes dados encontram-se em formato csv. Devido a isso, foi necessário converté-los para Sql e Cql.

Link para os scripts de criação e população do banco:

5. Estrutura dos bancos

Para o Mysql foi utilizada a seguinte estrutura:

Para o Cassandra a estrutura foi criada para a realização das consultas de cidades por país e cidades por estado. Também foi utilizado 2 como fator de replicação. Isto significa que cada registro está presente em duas máquinas do cluster.

6. Plano de testes

Os testes se baseiam na eficiência dos modelos e nos recursos de hardware consumidos para a realização e armazenamento dos bancos.

Para a realização dos testes foram preparados dois cenários:

  • Banco com 26 mil registros
  • Banco com 52 mil registros (para este cenário duplicamos os dados)

Para cada cenário executamos as seguintes consultas:

  • Selecionar as cidades dos paises ‘Brazil’, ‘United States’ e ‘Italy’
  • Selecionar as cidedades dos estados de ‘São Paulo’, ‘Washington’ e ‘Rio Grande do Norte’

Consulta 1:

# CQL
SELECT * FROM cities.city_per_country WHERE country = 'Brazil';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where country_id in (Select id from cities_db.Countries where name = 'Brazil'));

Consulta 2:

# CQL
SELECT * FROM cities.city_per_country WHERE country = 'United States';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where country_id in (Select id from cities_db.Countries where name = 'United States'));

Consulta 3:

# CQL
SELECT * FROM cities.city_per_country WHERE country = 'Italy';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where country_id in (Select id from cities_db.Countries where name = 'Italy'));

Consulta 4 :

# CQL
SELECT * FROM cities.city_per_state WHERE state = 'Rio Grande do Norte';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where name = "Rio Grande do Norte");

Consulta 5:

# CQL
SELECT * FROM cities.city_per_state WHERE state = 'Washington';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where name = "Washington");

Consulta 6:

# CQL
SELECT * FROM cities.city_per_state WHERE state = 'São Paulo';
# SQL
Select * from cities_db.Cities where state_id in (Select id from cities_db.States where name = "São Paulo");

Para aferir o tempo de execução de cada request foram utilizados os recursos da cli (Command line interface) de cada. Para o cassandra foi necessário ativar o comando TRACING ON e PAGING OFF. Para o Mysql não foi necessário executar nenhum comando específico pois a cli mostra por padrão o tempo de cada consulta.

Para aferir a quantidade de armazenamento em disco do Cassandra foi utilizada a ferramenta nodetool com o seguinte comando:

# precisa ser realizada para cada node no cluster
docker exec -it cass1 nodetool cfstats -H cities | grep "Memtable data size:"

Para o Mysql:

SELECT table_schema "DB Name",
ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB"
FROM information_schema.tables
GROUP BY table_schema;

7. Resultados

Performance:

Em questão de performance o Cassandra performou as consultas de maneira bem mais rápida que o Mysql.

C1 = consulta 1 (descrita no tópico anterior) …

Quando dobramos o número de entidades no banco de dados também podemos perceber que o cassandra manteve a performance próxima dos resultados anteriores, enquanto o Mysql teve um aumento significativo no tempo de resposta em todos os casos.

C1 = consulta 1 (descrita no tópico anterior) …

O segredo para a alta performance do cassandra está na modelagem de suas tabelas e na escolha correta da partition_key, ambas as escolhas feitas pelo usuário. Nas consultas por estado e por país todos os registros estavam no mesmo node e podem ser filtrado checando apenas uma tabela.

Já no Mysql embora todos os registros estejam na mesma máquina o seu modelo relácional requer que mais tabelas sejam consultadas para realizar a filtragem das cidades.

Armazenamento:

Com relação ao espaço em disco oculpado por cada banco obtivemos um resultado contrário ao anterior. O Mysql ocupou cerca de 5 vezes menos espaço em disco que o Cassandra no cenário 1 e até 10 vezes menos espaço no cenário 2.

O Mysql se manteve bastante compacto

Neste teste podemos ver o que o cassandra sacrificou para ter um alto desempenho. Enquanto o Mysql não visa a replicação de dados na sua estrutura de banco, o Cassandra necessita da replicação para obter a alta performance (a modelagem no Cassandra é query-driven). Os mesmo dados coexistem nas tabelas city_per_state e city_per_country e ainda são replicados entre os clustering como especificado na criação do keyspace:

CREATE KEYSPACE cities WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 2};

O replication_factor=2 significa que cada dado deve existir em dois nodes do cluster. Este é mais um fator que aumenta o espaço oculpado em disco.

8. Considerações Finais

  • Foi necessário limitar a quantidade de RAM utilizada nas instâncias do cassandra pois elas estavam consumindo os 16GB disponíveis em minha máquina. A recomendação mínima para uma instância do cassandra em ambiente de teste é de 8GB de RAM segundo a empresa DataSax (https://docs.datastax.com/en/dse-planning/doc/planning/capacityPlanning.html). Já o Mysql não requesr muitos recursos da máquina e foi limitado apenas para dar condições iguais nos testes.
  • Foi observado que a performance do cassandra é bastante instável, pois em ambos os cenários foi observada uma variação de até 30ms para a aplicação das mesmas consultas. Como resultados foram realizadas 5 consultas iguais para cada consulta de teste (o resutlado final é a média das 5 consultas). Isto ocorre provavelmente pelo valor do LOCAL_QUORUM=2 que significa o número de nodes que devem reponder uma determinada consulta para garantir a consistência dos dados retornados. Portanto, a velocidade de cada consulta depdende da comunicação entre os nodes o que pode variar de acordo com a rede em que os nodes estão inseridos.
  • Os seguintes notebooks foram utilizados para converter o arquivo csv das cidades para os formatos Cql e Sql: https://colab.research.google.com/drive/1vUo0CyOmy3FV9Ffg1gBSKVKE9rgAR5eC?usp=sharing
    https://colab.research.google.com/drive/1Fu8Q66rLvbNO2BLSiyEj3TErB_DhvR2K?usp=sharing

--

--