Comparando clustering Cassandra com Mysql database
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.
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.
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.
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