![](https://cdn-site.yadax.com.br/wp-content/uploads/2018/05/05102421/multi-data-center.png)
Cassandra: Ring, Token, Partition Key
Olá pessoal, tudo bem?
Tem alguns termos que a gente sempre escuta quando estamos falando de arquitetura do Cassandra, principalmente quando o assunto é particionar dados. Vou tentar explicar um pouquinho de alguns deles que influenciam neste particionamento.
Um cenário bastante comum é o que temos os dados distribuídos e replicados em DCs distintos, onde nem sempre a carga é exatamente igual em cada node.
Talvez você já deve ter ouvido falar que cada node é responsável por um determinado número de tokens e que de alguma forma isso influencia nesta distribuição.
A primeira pergunta que me surge é: vocês sabem exatamente onde estão e como seus dados são distribuídos em um cluster Cassandra?
Primeiramente, vamos falar dos tokens/vnodes e um pouco do período anterior a eles.
Nas primeiras versões do Cassandra (até a 1.2), você precisava calcular e indicar quais os tokens cada node possuía. Embora existam serviços na internet que ajudam nisso, era muito esforço manual.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_token_calc-1024x585.png)
Nas versões mais recentes, cada node pode ser responsável por mais de um token e todo o trabalho é feito automaticamente. Foi aí que surgiram os tais vnodes (virtual nodes – como se cada node no novo modelo tivesse vários nodes do formato antigo), quebrando esse paradigma de um token por node.
Quando um novo node é adicionado no cluster, durante o bootstrap, ele recebe uma quantidade de tokens (num_tokens) e em seguida recebe dos outros membros todo dado que ele será o novo responsável.
A próxima pergunta é: como a localização de cada dado está associado a estes tokens?
Tudo está baseado no nosso partition key, no ring e no algoritmo de particionamento (Partitioner).
Começando pelos Partitioners, ele é definido na criação do Cluster e não pode ser alterado. Entenda-os como uma forma de assegurar a distribuição determinística dos dados de entrada.
Até a mesma versão 1.2, o default era o RandomPartitioner, que já assegurava uma distribuição uniforme.
A partir da 1.2, surgiu com uma melhora significativa de performance, o Murmur3Partitioner, que usa a função MurmurHash para atribuir valores entre -2^63 to +2^63-1 para os dados da partition key. Se você não sabe o que é uma função Hash, vale a pena dar uma googlada.
De forma simplificada, o input para o partitioner é sua partition key, ele transforma este valor em um hash, e com este valor vai ser possível descobrir quem é o responsável por este dado, baseando-se nos tokens de cada node.
Para seguir, precisamos agora entender o conceito de ring, que é como cada token está associado a um determinado node.
Será mais fácil colocando a mão na massa. Criei um cluster com 4 nodes, divididos em 2 DCs. Para cada node, atribuí apenas 4 tokens para facilitar nossa análise.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_nodetool_status_ring-1024x350.png)
É possível então verificar quais são os tokes que marcam o final do intervalo (range) e qual o node associado, e a isto damos o nome de ring.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_ring-1024x594.png)
Agora vamos para a criação da nossa keyspace e da nossa tabela.
CREATE KEYSPACE bonacs WITH replication = {'class':'NetworkTopologyStrategy', 'US-EAST-1A': 1, 'US-EAST-1B': 1};
CREATE TABLE users (
username int,
first_name text,
last_name text,
inicio_email text,
dominio_email text,
PRIMARY KEY (username)
);
Após a criação, vamos confirmar que ainda não há SSTable.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_ring_emptytables-1024x470.png)
Talvez a forma mais direta de descobrir onde para onde o dado será enviado é através do comando nodetools getendpoints, informando a keyspace, a tabela e a partition key.
Veja:
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_getendpoints_1-1024x143.png)
Com isso, ele diz que o node 172.31.42.39 e o 172.31.18.33 vão recebê-lo. Vamos inserir, fazer um flush e conferir?
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_flushed_tab-1024x601.png)
Vamos usar uma alternativa agora para descobrir para onde o dado deve ir. Primeiro precisamos verificar qual o token associado ao 6, usando a funcão token no cqlsh.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_token6-300x127.png)
O valor retornado foi o +2705480034054113608. E onde ele se encaixa no nosso ring? Lembrando que o token associado no node marca a margem superior do range.
Na figura abaixo podemos ver que ele se encaixa no 172.31.18.33 e no 172.31.47.250.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_token_range-1024x470.png)
E como ficaria o getendpoints?
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_getendpoints_6-1024x154.png)
Vamos confirmar com um novo insert e flush.
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_flushed_tab_6-1024x509.png)
Por último, gostaria de chamar a atenção para o número de tokens por node. Uma baixa quantidade pode ocasionar um desbalanceamento na distribuição porque os tokens são gerados aleatoriamente e nem sempre os ranges não são do mesmo tamanho.
Veja como ficou nosso cluster após um insert uniformemente distribuído e repare que nosso ring não estava distribuído tão uniforme:
![](https://bonacs.com.br/wp-content/uploads/2018/11/nov2018_nodetool_final-1024x353.png)
Então pense assim: ranges maiores recebem mais dados. Da mesma forma, espera-se que quanto mais tokens um node tenha, mais dados ele receba.
Era isso, gostou? Até a próxima.
Tag:cassandra, partitionkey, ring, token, vnode