래빗MQ 클러스터링 - 2. 네트워크 파티션

클러스터링과 네트워크 파티션

클러스터링을 사용해서 복제를 통한 데이터 안정성, 작업 가용성, 처리량 향상 등 여러 목표를 달성할 수 있다.
클러스터 멤버간의 네트워크 연결 실패는 데이터 일관성 및 가용성에 영향을 준다.
각각의 어플리케이션은 일관성에 대한 요구사항이 다르고, 다른 규모의 비가용성을 견디므로 다른 '파티션 처리전략'을 사용할 수 있다.


1. 네트워크 파티션 감지

노드는 다른 노드가 일정시간동안(디폴트 60초) 노드에 접속할 수 없으면 해당 노드가 작동 중지되었다고 판단한다.
두 노드가 다시 접촉하면, 두 노드가 서로 장애가 발생했다고 생각하면 노드는 파티션이 발생했는지 결정한다.
이것은 다음과 같은 형식으로 래빗MQ 로그에 기록된다.

파티션 존재여부는 서버로그, HTTP API(모니터링용) 및 CLI 명령인 rabbitmqctl cluster_status 을 통해 식별할 수 있다.
rabbitmqctl cluster_status 는 보통 partition에 대한 빈 리스트를 보여주지만, 네트워크 파티션이 발생하면 그곳에 나타난다.
HTTP API는 각 노드에 대한 파티션 정보를 반환한다. 관리UI는 파티션이 발생한 경우 개요 페이지에 경고를 표시한다.

ex) 래빗MQ 로그
=ERROR REPORT==== 15-Oct-2012::18:02:30 ===
Mnesia(rabbit@hostname): ** ERROR ** mnesia_event got
{inconsistent_database, running_partitioned_network, hare@hostname}

ex) rabbitmqctl cluster_status
# => Cluster status of node rabbit@smacmullen ...
# => [{nodes,[{disc,[hare@smacmullen,rabbit@smacmullen]}]},
# =>  {running_nodes,[rabbit@smacmullen,hare@smacmullen]},
# =>  {partitions,[{rabbit@smacmullen,[hare@smacmullen]},
# =>               {hare@smacmullen,[rabbit@smacmullen]}]}]
# => ...done.


2. 네트워크 파티션 도중

네트워크 파티션이 발생하는 동안, 클라이언트의 두개의(또는 그 이상) 사이드는 양 사이드가 충돌되었다고 생각하면서 독립적으로 돌아간다.
이 시나리오는 split-brain으로 알려져있다.
큐, 바인딩, 익스체인지는 분리되어 생성되거나 삭제될 수 있다.
파티션에 걸처 분리된 미러큐는 각각의 파티션 사이드에서 하나의 마스터 큐가 될 것이다.
설정되어 사용될 수 있는 pause_minority와 같은 '파티션 처리전략'이 없으면 분단은 네트워크 연결이 복구된 이후에도 계속될 것이다.


3. 중지와 재개에 의한 파티션


'네트워크' 파티션이라고 칭하지만, 정말 파티션은 어떤 노드장애가 발생하지 않고 통신이 중단 될 수 있는 모든 경우이다.
네트워크 실패와 더불어, 전체 OS의 중지와 재개는 실행중인 클러스터 노드에 대해서 사용할 때 파티션을 야기할 수 있다.
중지된 노드는 스스로 장애 또는 심지어 중지되었다고 생각하지 않을 것이고, 클러스터의 다른 노드들이 그럴 것이다.

노트북에서 실행중인 클러스터 노드를 뚜껑을 닫아 중지할 수도 있지만, 가장 흔한 이유는 하이퍼바이저에 의한 중지되는 가상머신에 대한 것이다.
가상화된 환경에서 래빗MQ 클러스터를 실행하는 것이 좋으나, VM이 실행중에 중지되지 않는 것을 확실히 해야한다.
하나의 호스트에서 다른 한 호스트로의 VM 마이그레이션과 같은 몇몇 가상화 기능은 VM이 일시 중단되는 경향이 있다.

일시 중단 및 재개로 인한 파티션은 비대칭적인 경향이 있다 - 중지된 노드는 다른 노드가 중단되는 걸 필수적으로 볼 수는 없으나, 나머지 클러스터는 다운된 걸로 본다.


4. split-brain으로 부터의 복구

1) split-brain에서 복구하기 위해서, 먼저 가장 신뢰하는 하나의 파티션을 선택하라.
이 파티션은 사용할 시스템의 상태를 위한 권한이 된다 : 다른 파티션에서 발생한 모든 변경은 손실된다.
2) 다른 파티션의 모든 노드를 중지하고 나서 모든 노드를 재실행하라. 그 노드들이 클러스터에 재참여할 때 신뢰되는 파티션의 상태로 복구된다.
3) 마지막으로 warning을 clear하기 위해서 신뢰하는 파티션 안의 모든 노드를 재시작해야 한다.
* 전체 클러스터를 중지하고 재시작하는 것이 더 간단할 수 있다. 시작하는 첫번째 노드가 신뢰할 수 있는 파티션에 있어야 한다.


5. 파티션 처리전략

또한 래빗MQ는 네트워크 파티션을 자동으로 처리하는 3가지 방법이 있다.
: pause-minority모드, pause-if-all-down모드, autoheal모드. 기본 동작은 ignore모드라고 한다.

1)
pause-minority모드에서 래빗MQ는 다른 노드가 다운되는걸 본 후에 minority(즉, 노드의 전체숫자의 절반보다 적거나 같은)라고 결정되는 클러스터 노드를 자동으로 중지한다.
그러니까 CAP theorem에서 가용성보다는 파티션 허용오차를 선택하는 것이다.
(CAP정리 참고링크: http://junho85.tistory.com/842)

이것은 네트워크 파티션에서 하나의 파티션이 동작하는 것을 보장한다.
minority 노드들은 파티션이 시작하자마자 멈출 것이고, 파티션이 끝나면 다시 시작할 것이다.
이 설정은 split-brain을 막고, 불일치없이 자동적으로 네트워크 파티션으로부터 복구한다.

2)
pause-if-all-down 모드에서는, 리스트된 어떤 노드에도 닿을 수 없는 클러스터 노드를 자동적으로 중지한다.
다시 말하면, 래빗MQ가 클러스터 노드를 중지하려면 리스트된 모든 노드들은 다운되어야 한다.
이것은 pause-minority모드와 비슷하지만, 관리자가 context에 의존하기 보단 선호하는 노드를 결정할 수 있게 한다.
예를 들어, 클러스터가 랙A의 노드 2개와 랙B의 노드 2개로 구성되어 랙간의 링크가 손실 된 경우 pause-minority모드는 모든 노드를 중지한다.
pause-if-all-down모드에서는 관리자가 랙A의 두 노드를 리스트해두었다면 단지 랙B의 노드만 중지될 것이다.
리스트된 노드들이 파티션의 양 사이드를 걸처 split될 수 있다: 이 상황에서 어떤 노드도 중지되지 않는다.
그래서 ignore / autoheal argument가 추가적으로 있고 파티션에서 복구하는 방법을 나타냅니다.

3)
autoheal모드에서 파티션이 발생한 것으로 보이면 래빗MQ는 자동적으로 승리 파티션을 결정한다.
그리고 승리 파티션에 있지 않은 모든 노드를 재시작한다.
pause_minority 모드와 다르게 파티션이 시작할때 보다는 끝날때 영향을 준다.
승리 파티션은 가장 많은 클라이언트가 연결된 파티션(비기면 가장 많은 노드, 또 비기면 지정되지 않은 방식으로)


cluster_partition_handling 설정 파라미터를 세팅해서 하나를 활성화할 수 있다.

autoheal
pause_minority
pause_if_all_down

pause_if_all_down을 선택하면 추가파라미터가 필요하다.
nodes - 중지할 수 없는 노드
recover - 복구동작, ignore or autoheal

ex) pause_if_all_down모드 선택한 예시
cluster_partition_handling = pause_if_all_down

## Recovery strategy. Can be either 'autoheal' or 'ignore'
cluster_partition_handling.pause_if_all_down.recover = ignore

## Node names to check
cluster_partition_handling.pause_if_all_down.nodes.1 = rabbit@myhost1
cluster_partition_handling.pause_if_all_down.nodes.2 = rabbit@myhost2


어떤 것을 선택해야 하는가?

래빗MQ가 자동으로 네트워크 파티션을 처리한다고 문제를 적게하는 건 아니라는 걸 이해하는 것이 중요하다.
네트워크 파티션은 항상 래빗MQ 클러스트에 문제를 일으킨다.
단지 어느정도 문제의 종류를 선택할 수 있는 거다.
일반적으로 신뢰할 수 없는 링크를 통해 클러스터를 구성할때는 federation이나 shovel를 써야한다.

ignore
네트워크가 안정적이다. 모든 노드가 하나의 랙에 있고, 스위치로 연결되어 있고, 스위치는 바깥 세상으로 라우팅된다.
만약 클러스터의 어떤 다른 부분이 장애가 생겨도, 클러스터를 중지하는 리스크를 감수하고 싶지 않다.(또는 두개의 노드 클러스트가 있는 경우)

pause_minority
네트워크가 덜 안정적이다. 3개의 데이터센터에 걸처 클러스터되어 있다. 한번에 하나의 데이터센터가 실패할 수 있다고 가정한다.
이 시나리오에서 남은 두개의 데이터센터는 동작을 계속하고, 장애가 생긴 데이터센터의 노드들은 데이터센터가 다시 가동 될 때 자동으로 재참여한다.
이러한 데이터 센터는 EC2의 가용 영역과 같이 서로 직접적이고 안정적으로 연결되어야 한다.

autoheal
당신의 네트워크는 안정적이지 않을 수 있다. 데이터 무결성보다 서비스의 연속성에 더 관심이 있다. 2개 노드 클러스터일 수 있다.


출처 : https://www.rabbitmq.com/

댓글

이 블로그의 인기 게시물

래빗MQ 메시지 딜리버리 확인 메커니즘 - 소비자에서 브로커로

래빗MQ 메시지 속성