Category Archives: NoSQL

[NoSQL] Cassandra 새로운 노드 추가하기/기존의 노드 업그레이드 하기

사용자 삽입 이미지
카산드라에서의 새로운 노드를 추가하거나 기존의 노드를 업그레이드 하는 방법에 대해 간단히 기록을 해볼려고 합니다. 카산드라를 몇달 경험해 보니 도입 자체는 어렵지 않습니다만 운영이 매우 번거롭네요. 잘만들어진 GUI 툴조차 없고 노드의 수가 적을 경우 Consistency를 유지하는것 조차 어렵습니다. 작은 실수에 의해 데이터를 손실하기도 합니다. 백업이나 복구는 쉽지 않고 개발용 서버를 두고 따로 데이터를 완벽히 복제해 오는것도 쉬운일이 아닙니다. 하지만 이 모든것을 만족시킬만한 단 한가지 이유가 있다면 바로 퍼포먼스입니다. 읽기/쓰기가 기존의 RDB에서는 경험하기 힘든 모습을 보여줍니다. SQL류들을 사용하며 쿼리문을 하나짜기 위해 고민할필요도 없습니다. 하지만 그렇다고 마냥 사용하기 쉬운것은 아닌것 같긴 하지만요. 각설하고 정리를 시작해 보겠습니다.

새로운 노드 추가하기

서버의 시스템 준비

서버의 OS는 CentOS 혹은 RHEL이 적당하다고 개인적으로 생각합니다. OS의 경우에는 꼭 64비트 OS를 설치하시기 바랍니다. 메모리의 경우에는 많으면 많을수록 좋습니다. Swap은 사용하지 않습니다. 이미 Swap이 설정되어있는 머신이라면 /etc/rc.d/rc.local의 마지막에 다음의 명령을 추가하여 스왑을 꺼주시기 바랍니다.[code]swapoff -a[/code]
/etc/security/limits.conf 에 다음과 같은 내용을 추가하여 파일오픈 제한을 최대한 해제하여 줍니다.
[code]*                hard    nofile          262144
*                soft    nofile          262144[/code]
카산드라의 데이터 파일이 저장되는 공간(예:/var/lib/cassandra)의 파티션은 사실상 용량 무제한의 파일을 읽고 쓸 수 있는 xfs를 권장합니다. 적용이 힘들경우 ext4 또는 ext3로 하셔도 됩니다. 카산드라가 노드들간의 통신을 위해 사용하는 포트가 매우 동적입니다. 사실상 방화벽을 사용하시면 안됩니다. 레드햇 계열의 리눅스를 사용하실 경우 selinux를 꼭 끄셔야 합니다. 카산드라를 실행하기 위해서는 java가 필요합니다. 최신버전의 64비트용을 설치하시면 됩니다.

새로운 버전의 카산드라 다운받아 설치하기

현재 나와있는 최신버전은 0.8.4입니다. 다음과 같이 Download 페이지에서 알아낸 URL을 이용하여 원하는 바이너리를 다운받도록 합니다.
[code]wget http://mirror.apache-kr.org//cassandra/0.8.4/apache-cassandra-0.8.4-bin.tar.gz
tar -zxvf apache-cassandra-0.8.4-bin.tar.gz[/code]

cassandra-env.sh 설정하기

위의 파일에서 대표적으로 바꾸어야 하는 정보는 다음과 같습니다. [지난번글]에서 언급했듯이 MAX_HEAP_SIZE는 램의 1/2를 적용하면 되고 HEAP_NEWSIZE는 실제적인 코어 * 100M를 하시면 됩니다. java.rmi.server.hostname설정에서는 노드 자신의 아이피를 입력해 주셔야 원격지에서 모니터링 툴들이 접속할때에 발생할 문제를 사전에 차단할 수 있습니다.
[code]MAX_HEAP_SIZE=”4G”
HEAP_NEWSIZE=”400M”
JVM_OPTS=”$JVM_OPTS -Djava.rmi.server.hostname=192.168.0.10″[/code]

cassandra.yaml 설정하기

가장 핵심이 되는 설정 파일입니다. 기본적으로 사용하기 위해서 꼭 설정해야 하는 내용은 다음과 같습니다.
[code]cluster_name: ‘My Cluster'[/code]
모든 노드가 하나로 묶이게 되는 식별자 역할을 하는 클러스터 이름입니다. 하나의 클러스터는 하나의 cluster_name을 가져야만 합니다.
[code]auto_bootstrap: false[/code]
새로운 노드가 기존의 클러스터에 참여할때 주변 노드의 데이터를 빨아들여(?) 성공적으로 클러스터에 짐을 덜어주면서 합류하게 되는데요, 이 과정을 자동으로 수행할지 여부를 결정하는 설정입니다. nodetool을 이용하여 수동으로 합류할수도 있지만 위의 설정을 true로 바꿔서 카산드라를 구동하게 되면 다음에 나올 seed설정에 의거 기존의 노드들과 gossip이라는 프로토콜을 이용하여 가장 부하가 심한 노드의 다음에 알아서 추가가 됩니다. 일단 성공적으로 합류한 이후에는 노드의 재시작과 상관없이 이 설정을 다시 false로 바꿔두시기 바랍니다. 한번 클러스터에 정상적으로 참여를 했다면 이 설정을 필요가 없습니다. 또한 자신이 클러스터의 첫번째 노드라면 이 설정을 true로 하는것은 아무런 의미가 없습니다. false로 하시기 바랍니다.
[code]- seeds: “192.168.0.10, 192.168.0.11, 192.168.0.12″[/code]
위의 설정은 현재 클러스터의 토폴로지를 익히기 위해 소통해야할 노드를 입력합니다. 여러 노드가 구동중이라면 여러노드들을 모두 기입하시면 됩니다. 여기서 주의할 점은 추가되는 노드 자신의 IP가 저기에 들어가서는 안됩니다. 예외가 있다면 자신이 클러스터의 첫번째 노드일때는 자신의 아이피를 넣어주시면 됩니다. auto_bootstrap이 true인 상태에서 seeds설정에 자신의 아이피가 있을 경우 auto_bootstrap이 동작하지 않습니다.
[code]listen_address: 192.168.0.10[/code]
카산드라 노드들과의 통신을 위한 listen주소입니다. 이상하게도 여기에는 자기 자신의 아이피를 꼭 쓰셔야 합니다. 0.0.0.0같은걸 사용하시면 안됩니다.
[code]rpc_address: 0.0.0.0[/code]
이 설정은 클라이언트와 Thrift 프로토콜을 사용하여 통신을 할때 사용할 listen주소입니다. 여기서는 위와같은 네트워크 형태의 아이피를 사용하셔도 됩니다.

jna.jar 라이브러리 추가

카산드라의 lib폴더안에 jna.jar 파일을 추가해 줍니다. 이유는 모르겠지만 라이센스 문제로 카산드라가 포함하여 배포하지 못하는것 같습니다. jna가 없을 경우 카산드라는 정상구동 되지만 일명 OOM(Out Of Memory) 문제가 발생할 수 있습니다.
[code]wget http://java.net/projects/jna/sources/svn/content/trunk/jnalib/dist/jna.jar[/code]

기존의 노드 업그레이드 하기

기존의 노드를 새로운 버전의 카산드라로 업그레이드하기 위해서는 운영중인 서비스를 중단할 필요는 없습니다. 하지만 한대씩 노드를 업그레이드 한다고 할때 클러스터 운영을 위한 최소한의 replication factor를 넘는 숫자의 노드는 운영되고 있어야 합니다. (예: replication factor가 3일 경우 전체 노드가 4대 이상이면 무중단 업그레이드 가능)

운영중인 노드 중단하기

우선 다음과 같이 Thrift 서비스를 우선적으로 중단을 하여  봅니다. 서비스에 별다른 이상이 없는지 확인을 합니다. 이경우 replication factor와 read/write consistency 설정에 대해 이해가 좀 필요한데 다음에 관련 글을 적어보도록 하겠습니다. 다음의 명령으로 Thrift를 종료합니다.
[code]nodetool -h localhost disablethrift[/code]
서비스에 별다른 문제가 발견되지 않는다면(데이터 손실/롤백등) 다음의 명령으로 노드간의 통신을 종료합니다.
[code]nodetool -h localhost disablegossip[/code]
위의 명령을 실행하게 되면 다른 노드에서는 이 노드가 죽어있는것으로 판단하게 됩니다. 여기서 다른 노드중에 특별히 문제를 보이는 노드가 있는지 확인해 봅니다. 클러스터에 문제가 있을 경우 여기서 특정 노드의 부하가 폭주하거나 하는 문제가 발생합니다. 이제 다음의 명령으로 현재 메모리에 있는 모든 정보를 SSTable로 강제 쓰기를 하도록 합니다.
[code]nodetool -h localhost drain[/code]
그리고 카산드라 프로세스를 종료합니다. (그냥 ps명령으로 pid확인후에 kill로 죽이셔도 됩니다)
[code]pkill -f ‘java.*cassandra'[/code]

새로운 버전의 카산드라 설치 후 설정 옮기기

이 부분은 상단의 새로운 노드 추가하기 내용을 참고하시면 될것 같습니다.

Cassandra 특정 노드가 부하가 심해질때 긴급 처리 방법

사용자 삽입 이미지
카산드라 서버를 운영하다 보면 매우 가끔씩 특정 노드가 혼자서 미친듯이 폭주하더니 이내 뻗어버리는 현상이 발생합니다. 이경우 잘 대처하지 않고 방치해 두면 마치 전염병처럼 다른 노드까지 영향을 미치곤 합니다. 매우 간단하게 시도해 볼 수 있는 방법을 정리해 보겠습니다.

문제 파악

1. 특정 노드가 폭주를 하게 될 경우 서버의 로드가 10을 넘어 30혹은 더 높은 수치까지 치솟습니다.
2. /var/log/cassandra/system.log 파일에 다음과 같은 StatusLogger가 지속적으로 출력됩니다.
[code]INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.NodeIdInfo
INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.IndexInfo
INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.LocationInfo
INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.Migrations
INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.HintsColumnFamily
INFO [ScheduledTasks:1] 2011-08-09 17:52:56,601 StatusLogger.java (line 88) system.Schema[/code]
3. 구동중인 어플리케이션에서 다음과 같은 접속불가를 나타내는 Thrift 에러가 발생합니다.
[code]TSocket: Could not connect to 123.123.123.123:9160 (Connection timed out [110])[/code]

해결 방법 – 데이터가 꼬여있을(Conflict) 경우

[code]nodetool -h localhost disablethrift
nodetool -h localhost disablegossip[/code]
위와 같은 명령을 사용하여 현재 운영중인 서비스에서 제외시킵니다. thrift를 비활성화 할 경우 어플리케이션에 응답하지 않으면 gossip을 끌 경우 노드들간의 통신을 하지 않으며 결과적으로 다른 노드들에서 보기엔 이 노드가 Down된것처럼 인식이 됩니다.
[code]nodetool -h localhost flush[/code]
위의 명령을 사용하여 현재 메모리에 올라가 있는 데이터를 강제로 SSTable에 쓰기를 합니다. 비정상적인 종료가 일어날 경우 데이터 손실로 이어질수도 있으므로 일단 데이터를 파일형태의 디비로 옮기는 작업을 합니다.
[code]nodetool -h localhost scrub[/code]
위의 명령은 SSTable을 새로 생성을 하는 명령입니다. 모든 데이터를 점검하여 새로운 SSTable을 생성합니다.  /var/log/cassandra/system.log에 데이터 관련된 Fatal에러가 발생할 경우에도 문제가 수정이 됩니다.
[code]nodetool -h localhost enablegossip[/code]
위의 명령을 실행하여 gossip을 구동합니다. 다시 클러스터에 참여를 하게 되며 다른 노드들과의 통신을 시작합니다. 이상태에서 top명령등을 사용하여 노드의 상태를 확인합니다. 정상으로 돌아왔다면 잠시 폭주하는듯 하다가 이내 안정화 됩니다.
[code]nodetool -h localhost enablethrift[/code]
모든것이 정상이라면 다시 서비스에 참여시켜야 겠죠?

해결방법 – 메모리가 부족한 상황

모든 해결 방법이 위의 경우와 동일합니다만 scrub을 사용하지 않고 compact를 사용합니다. 기본적으로 카산드라는 Compaction이라는 과정을 주기적으로 실행하며 SSTable을 병합 및 규모를 축소하는 작업을 지속적으로 하게 됩니다. 하지만 어쩐일인지 정상적으로 정리 정돈이 이루어지지 않아 서버의 부하로 이어지는 경우가 있습니다. 이 경우 튜닝이 필요하겠지만 급한대로 compact명령을 통해 강제로 Compaction을 할 수 있습니다.
[code]nodetool -h localhost disablethrift
nodetool -h localhost disablegossip
nodetool -h localhost flush
nodetool -h localhost compact
nodetool -h localhost enablegossip
nodetool -h localhost enablethrift[/code]

주의할점

별것은 아니지만 서비스 운영중에 왠만하면 피해야 하는 명령이 하나 있습니다.
[code]nodetool -h localhost repair[/code]
노드가 이상해졌다면 위와 같은 명령이 호감이 가게 됩니다. 무언가 지금의 상황을 고쳐줄것만 같은 명령입니다. 하지만 repair는 데이터를 교정해 주는 명령으로 주변 노드들과의 데이터 비교를 통하여 신뢰할 수 있는 값으로 교정을 해주는 명령입니다. 하지만 이 과정에서 메모리를 더 잡아먹게 되며 결과적으로 SSTable이 기하급수적으로 확장되는 과정을 거칩니다. 그냥 결론만 말하자면 서비스중에 이 명령을 사용하지 마십시오. 기본적으로 Cassandra는 기본 운영중에 끊임없이 데이터의 무결성을 검증하고 교정하게 됩니다. 경험상 repair는 정기점검때와 같이 서비스가 중단된 상태가 아닌 데이터가 계속해서 변화하는 상황에서 실행했을때 좋은 상황을 맞이한적이 없군요. 조심하시길 바랍니다.