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를 지정해야 성공했습니다.