2.5 DCS 장애와 failsafe mode
2.4의 self-demotion 규칙은 노드 하나가 고립됐을 때만 작동하는 것이 아닙니다. DCS 자체가 응답 불능이 되어도 똑같이 작동합니다. Patroni는 클러스터에 대한 모든 판단을 DCS에 저장된 상태에 근거해 내리므로, DCS가 응답하지 않으면 현재 read/write 노드를 demote합니다. 결과적으로 데이터베이스 노드들이 전부 멀쩡해도 DCS 장애만으로 클러스터 전체가 read-only가 됩니다. failsafe mode는 이 시나리오를 완화하기 위해 Patroni 3.0.0에서 도입된 기능으로, 일시적인 DCS 장애를 클러스터가 견디게 해 줍니다.
켜는 방법
failsafe_mode는 dynamic configuration이며 기본값은 false입니다. patronictl edit-config 또는 REST API의 PATCH /config로 켭니다.
patronictl -c /etc/patroni.yml edit-config -s failsafe_mode=true
전제 조건이 둘 있습니다. 노드 간에 REST API 통신이 가능해야 하고, 공식 문서는 켜기 전에 모든 멤버의 Patroni 버전이 최신인지 확인하라고 요구합니다. 일부 멤버만 이 기능을 이해하는 상태로 켜면 안 된다는 뜻입니다.
동작 방식
평상시에 leader는 DCS에 /failsafe라는 permanent key를 유지합니다. 여기에는 그 시점에 알려진 클러스터의 전체 멤버 목록이 담깁니다. 2.3의 키 표에 있던 그 failsafe 키입니다.
DCS가 불능이 되면 primary는 leader lock 갱신 대신 다른 경로로 자격을 증명합니다. /failsafe key에 있는 모든 멤버에게 POST /failsafe REST API 요청을 보내고, 전원이 응답한 경우에만 primary를 유지합니다. 하나라도 응답하지 않으면 강등합니다. 이 확인은 매 loop_wait 사이클 반복됩니다.
replica 쪽에서는 이 요청이 다른 의미를 가집니다. 들어오는 POST /failsafe 요청 자체가 primary가 살아 있다는 신호이고, replica는 이 정보를 ttl 초 동안 캐시합니다. 그래서 DCS의 leader lock이 만료되어도 replica는 primary 생존을 인지한 상태라 leader race를 시작하지 않습니다.
왜 quorum이 아니라 전원인가
과반 응답이면 충분하지 않은가 하는 의문이 자연스럽습니다. 공식 문서의 답은 quorum에 대한 시각이 DCS와 Patroni에서 서로 다를 수 있다는 것입니다. DCS 노드의 다수파가 형성된 구역과 Patroni 멤버들이 배치된 구역이 일치한다는 보장이 없습니다. 가용 영역에 걸쳐 배치된 클러스터라면 장애가 어느 조합으로 갈라질지 예측하기 어렵습니다. 그래서 다른 모든 멤버를 확인하는 방법만이 이런 불일치 상황을 감지하게 해 준다는 것이 설계의 근거입니다. 안전하게 확인되지 않으면 강등한다는 원칙을 지키기 위해 조건을 가장 엄격하게 잡은 것입니다.
한계
전원 응답이라는 조건은 그대로 한계가 됩니다.
- DCS 장애 중에 primary까지 죽으면 failover가 일어나지 않습니다. leader race를 중재할 DCS가 없으므로 새 leader를 뽑을 방법이 없습니다.
- DCS 장애 중에 멤버가 하나라도 내려가면 전원 응답 조건이 깨져 primary는 강등됩니다.
/failsafekey에 없는 멤버는 leader election에 참여하지 못합니다. DCS 장애 중에 새로 만든 replica는 promote 대상이 아닙니다.
failsafe mode는 일시적인 DCS 장애를 견디기 위한 장치이지, DCS 없이 상시 운영하기 위한 수단이 아닙니다. DCS 장애가 길어질수록 위 한계에 해당하는 사건(멤버 다운, primary 장애)이 겹칠 확률이 커지므로, failsafe mode가 버텨 주는 동안 DCS 복구를 서두르는 것이 올바른 대응입니다.
정리
failsafe_mode는 DCS의 일시 장애와 다른 장애가 겹치지 않는다는 가정 위에서 primary를 지킵니다. 그 가정이 깨지면, 즉 장애 중에 멤버가 내려가거나 primary가 죽으면 동작은 안전한 쪽인 강등과 failover 보류로 기웁니다.