카산드라 장비가 클러스터링이 되어 있다면, nodetool status로 서로 연동되어 있음을 확인할 수 있다. 


$ nodetool status

Datacenter: datacenter1

=======================

Status=Up/Down

|/ State=Normal/Leaving/Joining/Moving

--  Address       Load       Tokens  Owns    Host ID                               Rack

UN  1.1.1.1  77.1 GB    256     ?       e9fdd401-e83e-428e-b848-5f51602145e6  rack1

UN  1.1.1.2  75.07 GB   256     ?       ca478c2c-5fec-4ee8-9f3f-37c33cc761d0  rack1

UN  1.1.1.3  73.75 GB   256     ?       b3d60757-ef63-4847-b6c5-4ee4289e9a27  rack1




데이터는 어떻게 저장되어 있을까?


카산드라에서 nodetool ring 커맨드를 실행하면, 카산드라의 consistent hashing을 통해 여러 노드 address에 저장될 수 있도록 구성되어 있음을 확인할 수 있다. 



$ nodetool ring 

Datacenter: datacenter

==========

Address       Rack        Status State   Load            Owns                Token

                                                                                           9220917267562992196

1.1.1.1  rack1       Up     Normal  75.52 GB        ?                   -9221498249641296905

1.1.1.2  rack1       Up     Normal  77.02 GB        ?                   -9200410371552807557

1.1.1.3  rack1       Up     Normal  77.17 GB        ?                   -9177126049054932799

...

1.1.1.1  rack1       Up     Normal  77.17 GB        ?                   9220917267562992196


커맨드 결과를 살펴보면 토큰이 점점 작은 값(큰 음수)에서 큰 값(큰 양수)로 이어지는지 볼 수 있다. 


같은 클러스터의 다른 장비에서 nodetool ring 커맨드를 사용하면 동일한 결과가 보인다. 클러스터 내의 데이터가 저장되는 가상 단위라 말할 수 있다.



내용을 자세히 설명한다.


consistent hashing을 소개하면, 버켓(bucket)은 미리 정해진 범위(range)로 되어 있다. 카산드라 노드는 범위를 할당하고 다음처럼 계산된다. 

범위(range)의 시작을 토큰(token)이라 부른다. 카산드라 1.2까지는 토큰이라 불렀는데, 2.0부터는 vnode라고 한다. 


그리고 CQL을 통해 데이터를 저장할 때, row key는 token을 기반으로 각 노드에 분산 저장된다. 



<그림 참조 : https://academy.datastax.com >


범위는 토큰 값의 구분 값이 들어가 있다. 

range start : 토큰 값

range end : 다음 토큰 값 -1




카산드라에서 consistent hashing에 쓰이는 기본 알고리즘은 Murmur3Patitioner이다. 

https://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archPartitionerM3P.html

https://docs.datastax.com/en/cassandra/2.1/cassandra/configuration/configCassandra_yaml_r.html


Murmur3Partitioner(m3p)는 RandomPartitioner보다 빠른 해싱과 성능이 좋다. 

(Paritioner가 여러 존재하지만, ByteOrderedPartitioner를 사용할 때는 hot spot 이슈가 생길 수 있다. 많은 이들은 



또한 cql에서 paging을 사용할 수 있다. (setFetchSize와 setPagingState를 java driver에서 지원한다)

https://docs.datastax.com/en/cql/3.1/cql/cql_reference/paging.html

http://docs.datastax.com/en/developer/java-driver/3.1/manual/paging/ 




카산드라는 키를 읽고 저장할 때 어느 범위에 있는지 알기 위해 모든 클러스터의 카산드라는 동일한 해시 함수를 사용한다. 즉 모든 노드는 클러스내의 모든 범위를 알아야 하고 자기 노드의 범위 뿐 아니라 다른 노드의 범위를 알고 있다. 


따라서, 요청을 받은 노드를 coordinator라 한다. 카산드라 키가 요청받은 노드(coordinator)에 속하지 않으면 범위에 맞는 노드로 요청을 보낸다. 



vnode는 토큰을 상위 개념이지만, 토큰을 아예 안쓰는 것은 아니다. 최신 버전(2.0 이상)은 특별히 토큰 관리를 하지 않지만, cassandra.yml에 initial_token이라는 옵션을 사용해 각 카산드라에서 나름 토큰의 범위를 지정할 수 있었다. 반대로 생각해보면 cassandra 관리를 각 카산드라 서버별로 작업을 진행해야했기에 관리가 좀 불편했다.. 


cassandra문서에 따르면 현재 initial_token은 disable이다. initial_token이 true이고 하나의 token_num이 1개이면 완전 single node가 된다. 하나의 개발 장비로 구성할 때는 이 방법이 좋을 수 있을 것이다. 

https://docs.datastax.com/en/cassandra/2.1/cassandra/configuration/configCassandra_yaml_r.html





각 노드에 하나의 토큰만 할당하기 보다 num_tokens(기본 값 256)을 사용해 늘릴 수 있다. 바로 vnode이다. vnode는 데이터를 분산시키기 위해 존재한다. 





만약 10대의 장비가 있고 num_tokens가 256이면 전체 vnode 개수는 2560이 될 것이다. 실제 개수는 정확히 나온다. 


$ nodetool ring | grep Normal | wc -l

2560


num_tokens를 256으로 사용한다면, increment repair하는데 도움이 된다고 한다(직접 해본 적은 없다)


vnode는 카산드라의 rebuild작업을 수동으로 할때 편리하다. 부하가 더 많은 노드에 분산되기 때문에 재시작에 유리할 수 있다. 게다가 rebuild할 때 하나의 복제본을 사용할 수 있다. 따라서 안정성이 더 확보된다. 






Posted by '김용환'
,