Tag Archives: 노드

[NoSQL] Cassandra에서 새로운 노드 추가하고 제거하기

사용자 삽입 이미지
이번에는 카산드라를 사용하여 다수의 서버들간의 클러스터링을 구성하는 방법에 대해 간단히 기록해 보도록 하겠습니다.


사용자 삽입 이미지

테스트로 3대의 노드를 이용하여 하나의 클러스터를 구성하겠습니다. 카산드라에서는 기본적으로 Ring 형태의 노드 구성을 이루게 됩니다. 위의 구성에서 우리는 A노드를 Seed 노드라고 할 것입니다. 이 Seed 노드는 이 클러스터에 새롭게 참가(Join)하는 노드가 있을경우 노드 구성을 알려주는 역할을 합니다.

카산드라 클러스터 구성하기

Node A 설치하기

[code]conf/cassandra.yaml[/code]
위의 설정 파일을 변경하도록 합니다. Node A는 Seed노드이면서 이 클러스터를 첫번째로 존재하게 하는 노드입니다. 다음을 설정하도록 합시다.

cluster_name: ‘Test Cluster’

위의 설정은 이 클러스터의 이름을 설정합니다. 클러스터란 다수의 노드가 모여있는 집합이라고 보시면 됩니다. 하나의 클러스터에 참가하기 위해서는 모두 같은 cluster_name을 가지고 있어야만 합니다. 여기의 이름값이 다를경우 이후의 노드들은 이 클러스터에 참여할 수 없습니다.

auto_bootstrap: false

카산드라에서 부트스트랩이란 자신이 부족한 데이터를 주변의 노드들로부터 가져오는 과정(동기화)을 말합니다. 새롭게 참가하는 노드들은 클러스터의 데이터들을 동기화하면서 참여하여야 합니다. 하지만 Seed노드는 자신이 첫번째 노드이기 때문에 이 과정을 생략합니다.

seeds:
    – 10.0.0.1

시드 노드를 설정합니다. 자기 자신인 경우 127.0.0.1로 하여도 무방하지만 꼭 자신의 IP를 지정하여주도록 합니다.

listen_address: 10.0.0.1

카산드라 서버들간에 통신을 하기 위해 설정해 주어야 하는 설정입니다. 값을 비워둘 경우 기본적으로 InetAddress.getLocalHost()를 호출하여 자신의 값으로 설정된다고 합니다만 잘 안되는것 같습니다. 필수적으로 자기 자신의 IP로 변경하여 줍니다. 여기서 이상한점이 listen은 외부로 해야할텐데 0.0.0.0을 사용해서는 안됩니다. 자신의 IP로 해도 잘 되므로 저렇게 하도록 합니다.

rpc_address: 0.0.0.0

이것이 Thrift를 이용한 클라이언트 접속을 허용하는 설정입니다. 0.0.0.0으로 설정할 경우 모든 원격지 접속을 허용하게 됩니다. 적절히 값을 설정하도록 합니다.

Node B 설치하기

cluster_name: ‘Test Cluster’

Node A가 생성한 클러스터에 접속해야 하므로 꼭! 같은 클러스터 이름을 사용하도록 합시다.

auto_bootstrap: true

Node B부터는 기존의 클러스터에 참여한다는 성격이 강합니다. 기존에 생성된 데이터를 가져와 동기화를 할 필요가 있습니다.

seeds:
    – 10.0.0.1

Seed 노드인 A노드의 주소를 입력하여 줍니다.

listen_address: 10.0.0.2

서버간의 통신을 위하여 자기 자신의 IP주소를 입력하여 줍니다.

rpc_address: 0.0.0.0

마찬가지로 클라이언트 접속을 허용할 IP 대역을 입력하여 줍니다.

Node C 설치하기

여기서부터는 설정이 중복되므로 간단히 내용만 적겠습니다.

cluster_name: ‘Test Cluster’

auto_bootstrap: true

seeds:
    – 10.0.0.1


listen_address: 10.0.0.2


rpc_address: 0.0.0.0


클러스터 운영하기

노드의 연결상태 확인하기

[code][root@NodeA bin]# ./nodetool -h localhost ring
Address   Status State   Load        Owns    Token                                      
                                             1595…794
10.0.0.1  Up     Normal  78.85 KB    36.41%  5136…766
10.0.0.2  Up     Normal  65.88 KB    8.76%   6627…220

10.0.0.3  Up     Normal  59.3 KB     54.83%  1595…794[/code]
위의 노드 상태는 어느 노드에서 확인해도 똑같이 확인이 가능합니다. 이렇게 하나의 클러스터가 탄생하였습니다. Owns는 각 노드들이 데이터를 나눠가진 정도입니다. 이 예제에서는 Node C까지 3개의 노드를 연결하였는데 또 다른 새로운 노드를 추가할 경우 알아서 적절한 위치에 끼어들어가 값을 분배해 나눠갖게 됩니다.
[code][root@NodeA bin]# ./nodetool -h localhost ring
Address   Status State   Load        Owns    Token                                      
                                             1595…794
10.0.0.1  Up     Normal  78.85 KB    36.41%  5136…766
10.0.0.2  Up     Normal  65.88 KB    8.76%   6627…220
10.0.0.3  Down   Normal  59.3 KB     54.83%  1595…794[/code]
만약에 하나의 노드가 죽게 된다면 위와 같이 Down으로 표시가 됩니다. 이경우 적당히 해당 노드를 제거하거나 혹은 해당 노드를 살려내야 합니다.

노드 제거하기

노드를 제거하기 위한 이유로는 대표적으로 2가지가 있을것 같습니다. 정상적인 목적에 의거하여 운영중인 노드를 제거하거나 또는 뜻하지 않은 장애로 서비스중인 클러스터에서 제거해야 하거나.
운영중인 노드를 제거하기 위해서는 decommission(퇴역)이라는 멋진 이름의 명령을 사용합니다.
[code][root@NodeC bin]# ./nodetool -h localhost decommission[/code]
하지만 위와같은 정상적인 명령을 사용할 수 없을때가 있습니다. 예를 들면 현재 노드에서 삭제중이지만 몇시간동안 그상태로 먹통이 된 경우도 있을 수 있습니다. 삭제 명령을 받았지만 아직도 떠나는중(Leaving)????
[code]10.0.0.3    Down   Leaving 218.71 KB       21.76%[/code]
이경우에는 removetoken을 사용하여 강제로 노드를 제거할 수 있습니다.
[code][root@NodeA bin]# ./nodetool -h localhost removetoken 1595…794[/code]
삭제하고자 하는 노드와 정상적으로 통신을 할 수 없는 상태라도 토큰을 이용하여 강제로 노드를 제거할 수 있습니다.

데이터 Fail Over 전략

사실 이름은 멋있지만 Fail Over랄껀 없고 Replication을 통한 노드 한두개쯤 뻗어도 데이터는 손실이 일어나지 않는(않길 바라는..ㅠㅠ) 시스템을 구성하는 방법에 대해 적어보겠습니다. 사실 여기에 필요한 구성은 위에서 모두 끝냈습니다. 하지만 정말 신기하게도 위의 상황에서는 하나의 노드만 뻗어도 데이터를 가져오지 못하는 상황이 발생합니다. 뻗는 노드분의 데이터만 손실이 일어나는게 맞는거 같은데 이상하네요.

이제 키스페이스(Keyspace)를 만들어 보겠습니다.
[code][default@unkown] create keyspace Item with replication_factor = 3;[/code]
자 평범한듯 하지만 위의 키스페이스 생성 옵션중에 replication_factor라는 것이 있네요. 이것은 데이터를 몇군데에 복제할것인가를 정하는 것입니다. 한국인은 3을 좋아하니깐 3으로 해보았습니다.
사실 위의 예제에서는 노드가 3개뿐이기 때문에 2개 이상으로 복제를 하는것이 무의미한 이야기입니다. 하지만 미래에 노드가 늘어날것으로 기대하기 때문에 3으로 해두겠습니다.
[code][default@Item] list user;
Using default limit of 100
——————-
RowKey: park
=> (column=657874, value=686168616861, timestamp=1306150005971000)

1 Row Returned.
[default@Item] list user;
Using default limit of 100
null

[default@Item] list user;
Using default limit of 100
——————-
RowKey: park
=> (column=657874, value=686168616861, timestamp=1306150005971000)

1 Row Returned.[/code]
위의 예시는 서비스 운영중에 발생할수 있는 모습을 보여줍니다. Item이라는 replication_factor 3의 키스페이스가 있고 user 컬럼에는 하나의 Row가 존재합니다. 그리고 곧바로 다른 노드를 강제로 죽여보았습니다. 순간적으로 데이터가 없다고 나오네요. 그리고 이내 복구가 됩니다.