5.4 replication slot 관리
replication slot은 소비자가 아직 받지 못한 WAL을 서버가 지우지 않도록 잡아 두는 PostgreSQL 장치다. HA 클러스터에서는 slot이 멤버의 생애와 함께 생기고 사라져야 하고, failover가 나면 새 primary에도 준비되어 있어야 한다. Patroni는 postgresql.use_slots(기본 true)일 때 이 생명주기를 대신 관리한다.
member slot 자동 관리
use_slots가 켜져 있으면 Patroni는 각 멤버의 streaming replication을 위해 멤버 이름에서 유도한 physical slot을 만들어 관리하고, 멤버가 사라지면 slot도 정리한다.
문제는 잠깐 내려간 멤버다. slot이 즉시 제거되면 그 사이 WAL이 지워져, 멤버가 돌아와도 따라붙지 못하고 reinit이 필요해지는 상황이 생긴다. member_slots_ttl(기본 30min, PostgreSQL 11 이상)이 이 유예 기간을 정한다. 멤버의 DCS member key가 만료된 뒤에도 해당 slot을 이 시간 동안 보존한다. 0으로 두면 member key 만료 즉시 slot을 제거하는 이전 버전의 동작으로 돌아간다.
# patronictl edit-config
member_slots_ttl: 30minpermanent slot 선언
멤버가 아닌 소비자(백업 도구, CDC, standby cluster)의 slot은 dynamic configuration의 slots hashmap으로 선언한다. permanent slot은 switchover와 failover를 거쳐도 보존되고, 없으면 Patroni가 만들어 준다.
slots:
backup_slot:
type: physical
cluster_type: primary
cdc_slot:
type: logical
database: orders
plugin: test_decodingtype은physical또는logical이다.- logical slot은
database와plugin이 필수다. - physical slot에는
cluster_type(primary또는standby)을 선택적으로 지정한다. 지정하면 해당 유형의 클러스터에서만 slot을 만들고, 유형이 다르면 만들지 않거나 기존 slot을 drop한다. - permanent slot을 쓰려면
postgresql.use_slots가 true여야 한다.
PostgreSQL 11 이상에서 permanent physical slot은 primary만이 아니라 모든 노드에 만들어지고 loop_wait초마다 위치가 전진한다. PostgreSQL 11 미만에서는 primary에만 만들어진다.
failover를 견디는 logical slot
Patroni는 permanent logical slot을 failover 후에도 이어 쓸 수 있도록 직접 동기화한다(PostgreSQL 11 이상). 동작은 이렇다.
- primary에서 만든 logical slot을 각 standby로 복사한다. 복사에는 해당 노드의 restart가 동반된다.
- 복사에는 rewind 또는 superuser credential을 쓰는 libpq 접속이 사용된다.
- 이후
loop_wait초마다 standby 쪽 slot 위치를 primary를 따라 전진시킨다. - permanent logical slot이 있으면 Patroni가
hot_standby_feedback을 자동으로 활성화한다.
flowchart TD
P["primary의<br/>permanent logical slot"] -->|restart 동반 복사| S["standby의 slot 사본"]
P -->|loop_wait마다 전진| S
P -.->|failover| NEW["standby 승격"]
NEW --> C["같은 slot으로 소비 재개"]
loop_wait 간격으로만 따라가므로, failover 직후 소비자는 이미 받았던 변경 일부를 다시 받는 경우가 있다. 공식 문서는 소비자 애플리케이션이 confirmed_flush_lsn을 추적해 중복을 걸러내기를 권장한다.ignore_slots
Patroni는 자신이 모르는 slot을 drop하므로(5.2에서 본 함정), 외부 도구가 만들고 관리하는 slot은 ignore_slots에 등록해 손대지 않게 한다. 각 항목은 name, type, database, plugin 속성의 부분집합이고, 적은 속성이 모두 일치하는 slot이 무시 대상이 된다.
ignore_slots:
- name: external_cdc
type: logical
database: orders
plugin: wal2jsonnostream tag의 영향
nostream: true인 노드는 streaming replication 대신 restore_command 기반 archive recovery와 pg_wal 폴링으로 WAL을 받는다. 이 tag는 slot 동기화에도 영향을 준다. 해당 노드와 그 아래에 붙은 cascading replica 전체에서 permanent logical slot의 복사와 동기화가 비활성화된다. primary에 설정하면 효과가 없다.
주의해야 할 두 패턴
반대로 유용한 패턴도 있다. 노드 구성이 고정된 클러스터에서 멤버 이름과 같은 physical slot을 permanent로 선언해 두는 방식이다. 이렇게 하면 그 멤버가 오래 응답이 없어도 slot이 제거되지 않아, member_slots_ttl을 넘긴 장기 다운 후에도 WAL이 보존된다. slot 이름이 자기 자신의 노드 이름과 같으면 그 노드에는 만들어지지 않으므로 자기 참조 문제는 없다. 대신 slot이 WAL을 계속 잡아 두므로 primary의 디스크 사용량 감시가 전제다.
정리
- Patroni는
use_slots(기본 true)로 멤버별 physical slot을 자동 관리하고, 멤버가 내려가도member_slots_ttl(기본 30min) 동안 slot을 보존한다. - failover를 넘어 살아남아야 하는 slot은 permanent로 선언한다. logical은
database와plugin이 필수이며, PostgreSQL 11 이상에서 standby로 복사되고loop_wait마다 전진한다. - logical 소비자는
confirmed_flush_lsn추적으로 failover 직후의 중복 수신에 대비한다. - 외부에서 관리하는 slot은
ignore_slots로 보호하고, replica에서 소비하는 permanent slot은 pg_wal 잠식 때문에 피한다.