본문으로 건너뛰기

2.1 monitor와 keeper

monitor와 keeper는 서로 반대 방향으로 두 번 연결합니다. keeper는 monitor에 접속해 자신의 상태를 보고하고 목표 상태를 받습니다. monitor는 keeper가 관리하는 PostgreSQL에 접속해 정상 작동 여부를 확인합니다. 두 연결 중 하나만 끊겨도 판정이 달라집니다. 이 장에서는 각 연결이 어떤 정보를 전달하고 어떤 주기로 동작하는지 정리합니다.

node_active 프로토콜​

keeper의 주 루프는 1초마다 monitor에서 pgautofailover.node_active() 함수를 호출합니다. 소스 defaults.h의 PG_AUTOCTL_KEEPER_SLEEP_TIME이 1초입니다. v2.2 keeper가 보내는 인자는 다음 8개입니다(monitor.c의 monitor_node_active).

인자내용
formationformation 이름
node id등록 때 monitor가 준 id
group idgroup 번호
current statekeeper가 도달한 현재 상태
pgIsRunning로컬 PostgreSQL이 실행 중인지
current TLI현재 timeline
current LSN현재 WAL 위치
pgsrSyncStatepg_stat_replication.sync_state 값

monitor는 이 보고를 pgautofailover.node 테이블에 기록합니다. 이어서 group의 상태 머신을 한 단계 진행하고 해당 노드의 목표 상태를 반환합니다. 목표 상태가 현재 상태와 다르면 keeper는 전이 함수를 실행하고, 다음 호출에서 변경된 현재 상태를 보고합니다.

반대 방향의 두 번째 연결은 health check입니다. monitor의 background worker가 등록된 각 노드의 PostgreSQL에 연결을 시도합니다. 판정 규칙은 2.3에서 다룹니다.

keeper의 프로세스 트리​

pg_autoctl run(또는 create ... --run)으로 시작한 keeper는 supervisor 프로세스입니다. v2.2 소스(service_keeper.c의 start_keeper)는 두 하위 서비스를 영구(permanent) 서비스로 등록합니다.

  • postgres: pg_autoctl do service postgres. PostgreSQL을 자식으로 실행하고 감시
  • node-active: pg_autoctl do service node-active. 위 node_active() 루프

실습 로그에서도 이 구조를 확인할 수 있습니다.

05:05:42 7 INFO Started pg_autoctl postgres service with pid 9
05:05:42 9 INFO /usr/bin/pg_autoctl do service postgres --pgdata /var/lib/pgaf/data -v
05:05:42 7 INFO Started pg_autoctl node-active service with pid 10
05:05:42 10 INFO Registered node 2 "node2" (node2:5432) in formation "default", group 0, state "wait_standby"

supervisor는 하위 서비스가 종료되면 다시 실행합니다. 운영 문서에 따르면 node-active가 monitor extension 버전 불일치로 5번 재시작하면 pg_autoctl 전체가 멈춥니다. PostgreSQL도 함께 종료됩니다. 업그레이드 순서가 중요한 이유입니다(6.7).

monitor 쪽 프로세스​

monitor도 pg_autoctl이 관리하는 PostgreSQL 인스턴스입니다. service_monitor.c는 postgres 서비스와 listener 서비스로 구성됩니다. 상태 머신 자체는 pgautofailover extension 안의 SQL 함수와 health check background worker로 구현되어 있습니다. health check worker는 노드의 health 값을 갱신하고 알림만 보냅니다. 이후 keeper가 node_active()를 호출하거나 관리 함수를 호출할 때 상태 머신 전이가 일어납니다.

05:04:44 7 INFO Started pg_autoctl postgres service with pid 33
05:04:44 7 INFO Started pg_autoctl listener service with pid 34

LISTEN/NOTIFY 채널​

monitor는 두 채널로 NOTIFY를 보냅니다(notifications.c). 두 채널은 서로 독립적입니다. 상태가 바뀌면 NotifyStateChange()가 state 알림을 보내고 pgautofailover.event에 기록을 남깁니다. LogAndNotifyMessage()는 log 채널로만 보냅니다.

채널내용
state노드 상태 변경. perform switchover, enable maintenance 같은 명령이 이 채널을 듣고 진행 표를 출력
log사람이 읽는 메시지. event 테이블에 모두 남는 것은 아님

외부 도구가 primary 변경을 빠르게 감지해야 한다면 monitor에 접속해 LISTEN state를 실행할 수 있습니다. NOTIFY는 현재 상태를 보존하지 않습니다. 따라서 연결 전이나 재접속 중에 발생한 알림은 놓칩니다. LISTEN을 실행한 뒤 pgautofailover.node를 한 번 조회해야 합니다. 재접속할 때마다 다시 조회해 상태를 맞춰야 합니다. PgBouncer 설정 갱신에 이를 쓰는 방법은 8.2에서 다룹니다.

-- monitor의 pg_auto_failover DB에서
LISTEN state;
SELECT eventtime, nodename, reportedstate, goalstate, description
FROM pgautofailover.event
ORDER BY eventid DESC
LIMIT 5;
노트

monitor에 접속하는 기본 사용자 autoctl_node는 테이블 조회 권한과 pg_autoctl이 사용하는 함수의 실행 권한을 받습니다. 이 함수에는 failover, promotion, maintenance, 노드 삭제도 포함되므로 권한 범위가 넓습니다(8.3). 실습에서는 편의를 위해 monitor 컨테이너 안에서 로컬 소켓으로 접속했습니다.

monitor가 멈추면​

keeper는 node_active() 호출에 실패해도 현재 상태를 유지합니다. PostgreSQL은 계속 실행되고 streaming replication도 유지됩니다. 실습에서 monitor를 멈춘 40초 동안 쓰기 실패는 0건이었습니다. 다만 primary keeper는 monitor 연결이 끊기면 standby가 여전히 연결되어 있는지 확인하기 시작합니다. standby 연결도 확인할 수 없으면 스스로 PostgreSQL을 내립니다(2.5). monitor와 standby를 동시에 잃으면 쓰기도 멈춘다는 뜻입니다.

05:33:57 11 WARN We lost the monitor, but still have a standby: we're not in a network partition, continuing.

정리​

keeper는 1초마다 상태를 보고하고 명령을 받습니다. monitor는 5초마다 노드를 확인하고 결정을 내립니다. 결정은 pgautofailover.node와 pgautofailover.event 테이블, 그리고 state와 log 채널에 남습니다. 두 방향의 연결이 각각 끊겼을 때 나타나는 동작은 Part VII 장애 시나리오의 출발점입니다.