본문으로 건너뛰기

5.1 number_sync_standbys

number_sync_standbys는 primary가 commit을 확정하기 전에 기다릴 standby 응답 수를 정하는 formation 설정입니다. N이 1 이상이면 PostgreSQL synchronous_standby_names의 ANY N (...)에서 N에 해당합니다. 0은 의미가 조금 다릅니다. 사용할 수 있는 quorum standby가 있으면 v2.2는 0에서도 ANY 1을 설정합니다. 따라서 0은 "standby가 없을 때 동기 복제를 풀어도 된다"는 정책 값에 가깝습니다. formation 단위 값이므로 failover로 primary가 바뀌어도 새 primary에 같은 규칙이 적용됩니다.

N+1 규칙​

v2.2 문서와 소스 주석에는 "N을 설정하려면 replication quorum에 참여하는 standby가 N+1대 등록되어 있어야 한다"고 명시되어 있습니다. standby 한 대를 잃어도 N개의 응답을 계속 받을 수 있게 하려는 정책입니다. N은 필요한 응답 수입니다. +1은 한 대의 장애를 흡수하는 여유분입니다.

0은 특별한 값입니다. 0일 때만 monitor가 standby 장애 시 primary를 wait_primary로 바꾸고 동기 복제를 끕니다. 1 이상이면 필요한 응답 수를 충족하지 못할 때 쓰기가 대기합니다. 이 차이는 5.4에서 장애 조합별로 정리합니다.

자동 조정​

노드를 추가하거나 뺄 때 monitor가 number_sync_standbys를 자동으로 바꾸기도 합니다. v2.2 소스(node_active_protocol.c)의 동작은 다음과 같습니다.

  • 노드 등록 때: 값이 0이고 새 노드가 들어온 뒤 quorum standby가 2대가 되면 1로 올림
  • 노드 삭제 때: 남은 quorum standby 수가 N+1보다 적으면 "남은 수 - 1"로 내림(최소 0). 남은 전체 노드의 quorum 수에서 primary 몫 1을 무조건 빼서 계산합니다. 따라서 primary의 replication_quorum이 false인 구성에서는 설명보다 더 내려갈 수 있습니다(RemoveNode)

자동으로 올리는 경우는 0에서 1로 바뀔 때뿐입니다. 정확한 조건은 새 노드를 등록한 뒤 quorum standby가 총 2대이고 현재 값이 0인 경우입니다. 보통 세 번째 PostgreSQL 노드가 들어올 때입니다. 다시 말해 두 번째 quorum standby가 들어오는 시점입니다. 네 번째 노드를 추가해도 2로 올라가지 않습니다. 실습에서 node3를 추가하자 값이 1이 되었습니다.

Context | Name | Setting | Value
----------+---------+---------------------------+-------------------------------------------------------------
formation | default | number_sync_standbys | 1
primary | node2 | synchronous_standby_names | 'ANY 1 (pgautofailover_standby_1, pgautofailover_standby_3)'

node3를 drop node로 제거하자 남은 quorum standby가 1대가 되었습니다. 이에 따라 값이 0으로 내려갔습니다.

formation | default | number_sync_standbys | 0
primary | node1 | synchronous_standby_names | 'ANY 1 (pgautofailover_standby_2)'

0에서도 ANY 1​

v2.2의 multi-standby 문서는 값이 0이면 synchronous_standby_names를 '*' 또는 ''로 설정한다고 설명합니다. 실습 결과는 달랐습니다. 2노드에서도 standby 이름을 명시한 ANY 1 (...)이 나왔습니다. standby 두 대에 값을 0으로 내린 3노드에서도 결과는 같았습니다.

formation | default | number_sync_standbys | 0
primary | node1 | synchronous_standby_names | 'ANY 1 (pgautofailover_standby_2, pgautofailover_standby_3)'

소스에서 이 결과를 확인할 수 있습니다. v2.2의 synchronous_standby_names() 함수는 2노드 group에서 특정 조건을 만족하면 ANY 1 (pgautofailover_standby_N)을 반환합니다. 해당 조건은 standby의 목표 상태가 secondary이고 quorum에 참여하는 경우입니다. 3노드 이상에서는 값이 0일 때 N을 1로 바꿔 ANY 1 (...)을 만듭니다. group에 노드가 하나뿐이면 빈 문자열이 됩니다. quorum standby가 없거나 primary가 wait_primary일 때도 같습니다. CHANGELOG의 v1.5.1 항목 "Avoid using synchronous standby name wildcard"가 이 변화의 출발점입니다. 문서는 갱신되지 않은 것으로 보입니다.

노트

3노드 이상에서는 상태와 관계없이 quorum에 참여하는 standby가 모두 목록에 들어갑니다. 2노드 경로는 다르게 동작합니다. standby의 goal state가 secondary일 때만 이름을 넣습니다. maintenance나 catchingup이면 빈 문자열을 반환합니다. 실습에서 node3를 maintenance로 보낸 뒤에도 synchronous_standby_names에 pgautofailover_standby_3가 남아 있었습니다. ANY 1이므로 다른 standby가 응답하는 동안 쓰기는 대기하지 않았습니다.

값 바꾸기​

pg_autoctl set formation number-sync-standbys 1
pg_autoctl get formation number-sync-standbys

실행 위치에 따라 필요한 옵션이 다릅니다. 데이터 노드에서는 keeper 설정에 있는 monitor URI를 사용합니다. monitor 노드에서는 실습상 --monitor URI를 지정하는 편이 안전했습니다. monitor 컨테이너에서 URI 없이 실행하자 값 자체를 거부하는 오류가 발생했습니다. v2.2 소스에서는 PGDATA의 monitor 설정으로 로컬 접속 문자열을 만들 수 있습니다. 따라서 이 오류가 monitor 역할의 제약 때문인지 인자 파싱 문제 때문인지는 확인하지 못했습니다.

05:39:14 3371 ERROR number-sync-standbys value 2 is not valid. Expected a non-negative integer value.

--monitor를 지정하자 규칙 검사까지 정상적으로 진행되었습니다. quorum standby가 2대인 상태에서 2를 요청하면 N+1 규칙에 걸립니다.

pg_autoctl set formation number-sync-standbys \
--monitor 'postgres://autoctl_node@localhost:5432/pg_auto_failover' 2
05:40:21 4602 ERROR Monitor ERROR: invalid value for number_sync_standbys: "2"
05:40:21 4602 ERROR Monitor DETAIL: At least 3 standby nodes are required, and only 2 are currently participating in the replication quorum

값이 바뀌면 monitor는 primary에 apply_settings 목표 상태를 지정합니다. primary는 synchronous_standby_names를 다시 쓴 뒤 primary로 돌아옵니다(3.5).

경고

primary가 primary나 wait_primary 상태가 아니면 설정 변경이 거부됩니다. 실습에서 설정을 연달아 변경하다가 The primary node so must be in state "primary" or "wait_primary" to be able to apply configuration changes to its synchronous_standby_names setting 오류를 받았습니다. 앞선 변경이 끝날 때까지 기다린 뒤 다시 실행합니다.

정리​

number_sync_standbys가 1 이상이면 commit이 기다릴 standby 응답 수를 뜻합니다. 이 값을 설정하려면 quorum standby가 N+1대 있어야 합니다. monitor는 두 번째 quorum standby가 들어올 때 0을 1로 올립니다. 노드가 빠지면 남은 수에 맞춰 값을 내립니다. v2.2는 0에서도 ANY 1 (...)을 사용합니다. 문서의 '*' 설명은 현재 동작과 다릅니다. 실습에서는 monitor 노드에서 값을 바꿀 때 --monitor URI를 지정해야 성공했습니다.