Skip to content

[RabbitMQ] Cluster 구성하기

2012/02/24

[RabbitMQ] Cluster 구성하기(http://www.rabbitmq.com/clustering.html)

Clustering Guide

RabbitMQ broker는  로직적으로 그룹화된 한개 이상의 Erlang 노드들입니다. 각 노드들은 RabbitMQ 어플리케이션을 운영하고 사용자, virtual hosts, exchanges 등을 공유합니다. 그리고 이 노드들의 묶음을 cluster라고 부릅니다.

RabbitMQ broker가 작동에 필요한 모든 데이터/상태는 전체 ACID 특성, 안정성(reliability) 및 확장(scaling)을 위해, 모든 노드간에 복제됩니다. 하지만 기본적으로 message queues 만큼은 예외적으로 동작하여, 다른 모든 노드에서 접근하거나 볼수 있지만 복제되지는 않습니다. 만약 클러스터 안에 노드들간 queue들의 복제를 원한다면, 고가용성(high availability)에 대한 페이지를 참고하시기 바랍니다.

RabbitMQ 클러스터는 네트워크 파티션을 잘 지원하지 못하기 때문에 WAN을 넘어서는 사용하지 않는것이 좋습니다. 대신 shovelfederation plugin 들은 WAN 간에 broker들의 접속을 더 잘 지원해 줍니다.

기본 클러스터 config 파일을 사용하여 자동 설정을 이용하면 클러스터를 쉽게 구성할수 있습니다.

클러스터의 구성은 동적으로 변할 수 있습니다. 그래서 모든 RabbitMQ broker들은 단일 노드로 시작하여, 클러스터에 참여하거나 다시 개별 노드로 돌아갈수 있습니다.

RabbitMQ broker들은 개별 노드들이 죽어도 정상동작하기 때문에 의지에 의해 시작되거나 멈출수 있습니다.

노드에는 RAM 노드나 disk 노드가 있습니다. RAM 노드들은 그들의 상태(state)를 오직 메모리에 저장해 놀고 있습니다.(durable queue들의persistent contents같은 경우는 예외적으로 disk에 안전하게 보관됩니다.) Disk 노드들은 메모리와 디스크에 상태를 가지고 있습니다. 그래서 램 노드 같은 경우 디스크 노드 만큼 디스크에 쓰는 작업이 없기 때문에 성능이 더 좋을수 있습니다. 상태는 클러스터 안에 모든 노드에 복제되기 때문에 클러스터의 상태를 안전하게 저장하기 위해서는 한개의 디스크 노드만 있어도 됩니다. 하지만 RabbitMQ에서는 오직 RAM 노드로만 클러스터를 만드는 것을 막지 않을 것 입니다. 대신 그렇게 했을경우 전체 클러스터에 정전이 발생한다면, 모든 메시지를 포함하여 전체 클러스터의 상태를 잃어 버릴수 있다는 것을 알아야 합니다.

Clustering 구성방법

세개의 물리적으로 다른 장비들(rabbit1, rabbit2, rabbit3)간에 클러스터를 구현하는 방법을 알아보겠습니다. 이때 두개의 장비는 램과 디스크에 데이터를 복제하고, 한대의 장비에서는 램에만 복제할 것입니다.

기본 셋업

Erlang 노드들은 서로 간에 커뮤니케이션을 할때 cookie를 이용해서 인증하고 있습니다. 그래서 두 노드간에 커뮤니케이션을 하기 위해서는 같은 cookie를 가지고 있어여 합니다.

cookie는 단순히 alphanumeric character 로된 String 이며, 길이는 길게던 짧게던 지정할수 있습니다.

Erlang은 RabbitMQ server가 시작할때 자동적으로 랜덤한 값으로 cookie 파일을 만들어 줍니다. 보통 Unix 시스템에서는 /var/lib/rabbitmq/.erlang.cookie 에 있습니다.

Tip. Documentation에는 분명 /var/lib/rabbitmq/에 있다고 써있으나 실제로 find -name “*.erlang.cookie”로 찾아보면 “./root/.erlang.cookie” 에 있습니다.

그리고 .erlang.cookie 가 “-r——–” 가 아니면 “Cookie file /root/.erlang.cookie must be accessible by owner only”,[]} 로그를 내며 에러가 납니다.

그래서 한쪽에서 자동으로 만든 .erlang.cookie 파일의 내용을 복사해서 다른 node에 복사해주면 됩니다.

개별 노드로의 실행

클러스터 구성을 하기전에 개별 노드로 띄워서 상태를 보면 다음과 같습니다.

rabbit1$ rabbitmq-server -detached

rabbit1$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]
...done.

클러스터 만들기

만약 bunny1@i-4195-21799과 bunny2@i-4195-21799 두개의 노드가 실행중 이라면, 클러스터를 구성하기 위해서 다음과 같이 실행합니다.

[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 stop_app //bunny2의 rabbitmq를 정지
Stopping node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 reset //bunny2의 클러스터 구성을 초기화
Resetting node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 start_app //bunny2의 rabbitmq를 재시작
Starting node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status //bunny2의 
Cluster status of node 'bunny2@i-4195-21799-VM' ...        //클러스터 구성상태를 확인합니다.
[{nodes,[{disc,['bunny2@i-4195-21799-VM']}]},              //disc 모드로 동작중
 {running_nodes,['bunny2@i-4195-21799-VM']}]               //bunny2 혼자 동작하고 있습니다.
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 stop_app      //다시 정지
Stopping node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster bunny1@i-4195-21799-VM
Clustering node 'bunny2@i-4195-21799-VM' with ['bunny1@i-4195-21799-VM'] ...
...done.                                                   //bunny1과 클러스터 구성
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status //클러스터 구성을 확인
Cluster status of node 'bunny2@i-4195-21799-VM' ...
[{nodes,[{unknown,['bunny2@i-4195-21799-VM']}]},{running_nodes,[]}]  //start_app을 안해서 
...done.                                           //동작하고 있는 node가 없는걸로 나옵니다.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 start_app   //bunny2를 시작합니다.
Starting node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status  //클러스터 구성을 확인
Cluster status of node 'bunny2@i-4195-21799-VM' ... //bunny1은 disc로, bunny2는 ram 타입
[{nodes,[{disc,['bunny1@i-4195-21799-VM']},{ram,['bunny2@i-4195-21799-VM']}]}, 
 {running_nodes,['bunny1@i-4195-21799-VM','bunny2@i-4195-21799-VM']}]
...done.
 

이때 보면 node는 두가지 타입을 가지게 됩니다. disc와 ram 타입 입니다. disc와 ram 타입은 cluster 명령을 수행할때 다음과 같이 결정됩니다.

[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status
Cluster status of node 'bunny2@i-4195-21799-VM' ...
[{nodes,[{disc,['bunny1@i-4195-21799-VM']},{ram,['bunny2@i-4195-21799-VM']}]}, //bunny1은 disc
 {running_nodes,['bunny1@i-4195-21799-VM','bunny2@i-4195-21799-VM']}]     //bunny2는 ram 타입
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 stop_app  //bunny2의 rabbitmq를 정지
Stopping node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster bunny1@i-4195-21799-VM bunny2@i-4195-21799-VM
Clustering node 'bunny2@i-4195-21799-VM' with ['bunny1@i-4195-21799-VM', //클러스터를 구성
 'bunny2@i-4195-21799-VM'] ...                             //이때 bunny2를 같이 적어 줍니다.
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 start_app  //bunny2의 rabbitmq를 재시작
Starting node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status
Cluster status of node 'bunny2@i-4195-21799-VM' ...
[{nodes,[{disc,['bunny2@i-4195-21799-VM','bunny1@i-4195-21799-VM']}]}, //bunny1,bunny2가 
 {running_nodes,['bunny1@i-4195-21799-VM','bunny2@i-4195-21799-VM']}]  //disc타입으로 동작
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 stop_app        //다시 bunny2를 멈추고
Stopping node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster bunny1@i-4195-21799-VM
Clustering node 'bunny2@i-4195-21799-VM' with ['bunny1@i-4195-21799-VM'] ...  
...done.                                            //bunny2를 빼고 cluster 명령어를 실행
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 start_app     //bunny2를 실행하면
Starting node 'bunny2@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny2 cluster_status
Cluster status of node 'bunny2@i-4195-21799-VM' ...
[{nodes,[{disc,['bunny1@i-4195-21799-VM']},{ram,['bunny2@i-4195-21799-VM']}]},
 {running_nodes,['bunny1@i-4195-21799-VM','bunny2@i-4195-21799-VM']}]      
...done.                                            //bunny2는 ram타입으로 실행합니다.

즉, cluster 명령어 실행시에 자기자신은 넣어서 실행하면 disc 타입으로 빼면 ram 타입으로 동작하게 됩니다. 그리고 클러스터에 join하기 위해서는 클러스터중 아무 노드 중 한개이상을 cluster 명령에 넣어주면 되지만 만약 그중 한개의 노드라도 down된 상태라면 join할수 없습니다. 대신 force_cluster 명령어를 사용한다면 down된 노드는 무시하고 cluster를 구성합니다.

추가적으로 한번 join 되었던 노드의 경우 reset을 해주기 전까지는 서버가 완전히 죽었어도 다시 살아나면 이전 cluster의 노드로 동작하게 됩니다.
그리고 reset을 하면 cluster에서 빠지는 것과 함께 최초 config 설정으로 초기화 합니다.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 cluster_status
Cluster status of node 'bunny3@i-4195-21799-VM' ...
[{nodes,[{disc,['bunny2@i-4195-21799-VM','bunny1@i-4195-21799-VM']},
 {ram,['bunny3@i-4195-21799-VM']}]},
 {running_nodes,['bunny2@i-4195-21799-VM','bunny1@i-4195-21799-VM',
 'bunny3@i-4195-21799-VM']}]
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 list_users
Listing users ...
redbunny []                // bunny1 에서 만든 계정으로 클러스터에 join해서 생긴 계정
guest [administrator]                    // config 파일에의해 기본으로 생성하는 계정
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 stop_app
Stopping node 'bunny3@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 reset  //reset 실행
Resetting node 'bunny3@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 start_app
Starting node 'bunny3@i-4195-21799-VM' ...
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 cluster_status
Cluster status of node 'bunny3@i-4195-21799-VM' ...
[{nodes,[{disc,['bunny3@i-4195-21799-VM']}]},         //기존 클러스터에서 out됨
 {running_nodes,['bunny3@i-4195-21799-VM']}]
...done.
[root@i-4195-21799-VM bin]# ./rabbitmqctl -n bunny3 list_users
Listing users ...
guest [administrator]                            //redbunny는 없고 guest만 남음
...done.

단일 장비에서 클러스터 구성하기

여러 개발장비가 없는(저 같이..ㅠ_ㅠ 지금은 ucloude가 1달무료 행사중이라 기생하고 있죠..ㅋㅋ) 경우 한대의 장비에서 여러 노드를 실행하고 클러스터 환경을 테스트 할수 있습니다.
간단하게 스크립트로 만들어 공유합니다.
#!/bin/sh
RABBITMQ_NODE_PORT=$1 RABBITMQ_NODENAME=$2 \
RABBITMQ_MNESIA_DIR=/home/…/rabbitmq/mnesia-$2 \
RABBITMQ_LOG_BASE=/home/…/rabbitmq/log-$2 \
/usr/lib/rabbitmq/bin/rabbitmq-server -detached

$ ./start_node.sh 5672 bunny1

$ ./start_node.sh 5673 bunny2

$ ./start_node.sh 5674 bunny3

이때 주의할 점은 각 노드의 포트와 이름은 유니크해야 합니다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: