postgresql 을 이전에 이중화를 해보려고 글을 쓴적이 있다.
당시.. pgpool2 로 진행하다가 실패했다.
성공을 못한건 아니었지만 운영을 해보았더니.. 자동 failover 가 문제가 있었고..
실제 장애가 나서 처리하는데 애를 꽤 먹었다.
그래서 현재 운영중인 서비스는 단일 구성에 하루 2회 백업을 진행하고 있다.
몇년이 지난 지금 검색을 해보니 그때와는 다르게 HA 구성을 하는 듯 하여 다른 방법으로 도전을 해보려고 한다.
일단 이번에는 patroni 라는 솔루션을 사용해보려고 한다.

먼저 사용자 입장에서 접근을 한다고 생각해 보자.
사용자는 일단 app 서버에 접근할것이다.
참고로 내 서버는 nestjs 에 prisma orm 을 사용하였다.
그다음 아무런 HA구성이 없다면 DB url을 찾아 바로 접속할 것이고..
여기서 HA구성을 했다고 친다면..
특히 postgresql 처럼 N개의 노드중 primary 는 Read / Write 를 담당하고 , 나머지는 Read 만 한다고 가정을 하면..
앱서버가 DB에 연결할때 어디로 가지??
CURD 중에서 R를 제외하면 무조건 Primary 로 가야할 것이다.
그리고 나머지는 어디로 가도 상관이 없을 것이고...
그렇다면 용도에 맞게 잘 분배를 해야할것이다. 이거는 단순 로드밸런싱이 아니라 쿼리 종류에 따라 다르게 서버를 연결해야 한다는 것이다.
그러면 두가지를 고려해볼수 있다.
1. Application 레벨에서 두개의 용도를 분기해서 호출한다.
2. Application 은 그대로 두고 요청을 분석해서 알아서 분기해준다.
이때 1번의 경우는 기존의 Application 을 모두 수정해야 한다.
왜냐.. 개발자가 현재 api 가 쓰기용인지 읽기용인지 코드로 분기해서 골라줘야 한다는 것이다.
이미 만들어진 서비스에 적용하기에는 상당히 번거롭다.
2번의 경우는 .. 개발자에게 너무 행복하다.
솔루션이 알아서 해줄테니까... 일전에 시도해 보았던 pgpool2 가 이런역할을 한다. 이것을 Query-based routing 이라고 한다고 한다.
GPT를 통해서 물어보니.. 역시나 pgpool 이 가장 먼저 언급되었고 유일한 솔루션이라고 한다.
그런데 계속 검색을 해보니... Odyssey 라는 것이 있다고 한다. 차세대 pgool 이라고 하네???
일단 나는 이번 포스팅에 Odyssey 기반으로 해보려고 한다.
그런데 포스팅이 별로 없다. GPT를 이용해 일단 해본다.
Postgresql 설치 (2개노드)
https://www.postgresql.org/download/linux/ubuntu/
PostgreSQL: Linux downloads (Ubuntu)
Linux downloads (Ubuntu) PostgreSQL is available in all Ubuntu versions by default. However, Ubuntu "snapshots" a specific version of PostgreSQL that is then supported throughout the lifetime of that Ubuntu version. The PostgreSQL project maintains an Apt
www.postgresql.org
공식사이트에서 확인하고 설치한다.
음..그냥 기본 명령으로 된다고 한다.
$ sudo apt install postgresql
[sudo] password for gglabadmin:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
libcommon-sense-perl libjson-perl libjson-xs-perl libllvm17t64 libpq5 libtypes-serialiser-perl postgresql-16 postgresql-client-16
postgresql-client-common postgresql-common ssl-cert
Suggested packages:
postgresql-doc postgresql-doc-16
The following NEW packages will be installed:
libcommon-sense-perl libjson-perl libjson-xs-perl libllvm17t64 libpq5 libtypes-serialiser-perl postgresql postgresql-16 postgresql-client-16
postgresql-client-common postgresql-common ssl-cert
0 upgraded, 12 newly installed, 0 to remove and 41 not upgraded.
Need to get 43.6 MB of archives.
After this operation, 175 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
블라블라~
Running kernel seems to be up-to-date.
No services need to be restarted.
No containers need to be restarted.
No user sessions are running outdated binaries.
No VM guests are running outdated hypervisor (qemu) binaries on this host.
gglabadmin@postgresql2:~$ psql -V
psql (PostgreSQL) 16.11 (Ubuntu 16.11-0ubuntu0.24.04.1)
우와 설치가....1분이 안걸린다.
회사에서 사용하는 mssql 에 비교하면... 이건 정말 축복인것 같다.
16버전이 설치 되었다. 이거면 됐다.
로케일 설정
sudo apt-get install -y language-pack-ko
sudo locale-gen ko_KR.UTF-8
sudo update-locale
계정설정
$ sudo -u postgres psql
# 슈퍼유저 계정 비번설정
ALTER USER postgres WITH PASSWORD '비밀번호';
# 복제용 계정
CREATE ROLE rep_user WITH REPLICATION LOGIN PASSWORD '비밀번호';
DB설정
Patroni가 복제를 위해 rep_user로 접속할 수 있도록 pg_hba.conf 파일에 접근을 허용
$ sudo vi /etc/postgresql/16/main/pg_hba.conf
# 복제 사용자 접근 허용 (DB 서버 IP 대역)
host replication rep_user 10.34.1.0/24 md5
host replication rep_user 127.0.0.1/32 md5
sudo systemctl restart postgresql
파일 마지막에 상기 내용을 추가하고 재시작
DCS 설치
다음은 Distributed Configuration Store 를 설치할 차례..
이것이 뭐냐면.. patroni 라는 HA 관리자가 나의 상태를 저장할 저장소
서버 N대중.. 누가 primary 이고 아닌지.. 이런 상태값을 저장하여 HA구성을 할수 있도록 해주는 것...
이런것이 왜 필요할까? DB서버에 직접하면.. 하나가 장애나면 그 저장소를 잃어버리니까...
일종의 공유 스토리지 역할을 하는것 같다.
안내에 따르면.. 3대를 설치하라고 한다. DCS 자체도 HA 구성을 해야한다는 것이다.
나는 다른 서버를 설치하고 싶지 않은데....
왜 3대나 필요한지 GPT선생님과 많은 대화를 했다.
일단 patroni 는 정합성을 보장한 설정 데이터를 요구한다고 한다.
데이터를 확실하게 믿어야 하는 상황을 무조건 만들어야 한다는건데
DCS 3대가 있고 각각이 동일한 데이터를 가지고 있을것이다.
홀수가 필요한 이유는 데이터를 저장하고 있는 3개의 노드가 서로 내 데이터가 맞다고 주장할시에 합의를 통해 정확한 데이터만 남길수 있다는 것이다. 2대만 하면 서로 내 데이터가 맞아! 라고 하면 누가 맞는지 중재를 할수 없다는 것이다.
이 Quorum 이라고 한다.
음.. 처음엔 2대에만 설치하려고 했는데 기존에 설치해두었던 k3s 를 사용해보면 어떨까 싶다.
k3s 에는 기본적으로 etcd 가 설치되어 있어서 바로 활용 가능할 것 같다.
이미 쿼럼 Quorum 구조를 갖추고 있으니 연결만 하면 바로 사용할듯 하다.
그래서.. 일단 시도를 해봤는데 쉽게 되지는 않는다.
내장 etcd 를 외부에서 호출하는 것을 추천하지 않고 인증때문에 간단히 셋팅이안되는 것 같다.
그럼. 결국 k3s 서버 노드 3개를 활용하여 개별 설치를 해야겠다.
consul 이라는 툴로 해보자.
서버간 방화벽 열기
sudo ufw allow 8300/tcp
sudo ufw allow 8301/tcp
sudo ufw allow 8301/udp
sudo ufw allow 8500/tcp
sudo ufw allow 8600/tcp
sudo ufw allow 8600/udp
sudo ufw reload
필요 디렉토리 만들기
sudo mkdir -p /var/lib/consul
sudo chown -R consul:consul /var/lib/consul
sudo chmod 750 /var/lib/consul
k3s 각노드에서 consul 설치
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install consul
gglabadmin@k3s-node1:~$ sudo systemctl status consul
○ consul.service - "HashiCorp Consul - A service mesh solution"
Loaded: loaded (/usr/lib/systemd/system/consul.service; disabled; preset: enabled)
Active: inactive (dead)
Docs: https://developer.hashicorp.com/
gglabadmin@k3s-node1:~$ consul --version
Consul v1.22.1
Revision 3831febf
Build Date 2025-11-26T05:53:08Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
consul 설정 (3개 노드 모두 설정)
sudo mv /etc/consul.d/consul.hcl /etc/consul.d/consul.hcl.old
consul keygen <== 아래 encrypt 부분에 넣어준다.
sudo vi /etc/consul.d/consul.hcl
server = true
bootstrap_expect = 3
datacenter = "dc1" # 3개 노드 모두 동일하게
data_dir = "/var/lib/consul"
# 모든 인터페이스 허용
client_addr = "0.0.0.0"
bind_addr = "{{ GetInterfaceIP \"eth0\" }}"
retry_join = [
"10.34.1.151",
"10.34.1.152",
"10.34.1.153"
]
ui = true
encrypt = "<여기에 gossip_encryption_key # 3개 노드 모두 동일한 값으로
설치가 다 끝나면 아래처럼 나온다.
gglabadmin@k3s-node3:~$ consul members
Node Address Status Type Build Protocol DC Partition Segment
k3s-node1 10.34.1.151:8301 alive server 1.22.1 2 dc1 default <all>
k3s-node2 10.34.1.152:8301 alive server 1.22.1 2 dc1 default <all>
k3s-node3 10.34.1.153:8301 alive server 1.22.1 2 dc1 default <all>
Patroni 설치
두 서버 모두에서 설치를 한다.
Python, pip, PostgreSQL 클라이언트 개발 파일 설치 (OS에 따라 다를 수 있음)
gglabadmin@postgresql2:~$ sudo apt install -y python3 python3-pip python3-dev libpq-dev
[sudo] password for gglabadmin:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3 is already the newest version (3.12.3-0ubuntu2.1).
python3 set to manually installed.
The following additional packages will be installed:
binutils binutils-common binutils-x86-64-linux-gnu build-essential bzip2 cpp cpp-13 cpp-13-x86-64-linux-gnu cpp-x86-64-linux-gnu dpkg-dev
fakeroot g++ g++-13 g++-13-x86-64-linux-gnu g++-x86-64-linux-gnu gcc gcc-13 gcc-13-base gcc-13-x86-64-linux-gnu gcc-x86-64-linux-gnu
javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan8 libatomic1 libbinutils libcc1-0
libctf-nobfd0 libctf0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libgcc-13-dev libgomp1 libgprofng0 libhwasan0 libisl23
libitm1 libjs-jquery libjs-sphinxdoc libjs-underscore liblsan0 libmpc3 libpython3-dev libpython3.12-dev libquadmath0 libsframe1 libssl-dev
libstdc++-13-dev libtsan2 libubsan1 lto-disabled-list make python3-wheel python3.12-dev zlib1g-dev
Suggested packages:
binutils-doc gprofng-gui bzip2-doc cpp-doc gcc-13-locales cpp-13-doc debian-keyring g++-multilib g++-13-multilib gcc-13-doc gcc-multilib
autoconf automake libtool flex bison gdb gcc-doc gcc-13-multilib gdb-x86-64-linux-gnu apache2 | lighttpd | httpd bzr postgresql-doc-16
libssl-doc libstdc++-13-doc make-doc
The following NEW packages will be installed:
binutils binutils-common binutils-x86-64-linux-gnu build-essential bzip2 cpp cpp-13 cpp-13-x86-64-linux-gnu cpp-x86-64-linux-gnu dpkg-dev
fakeroot g++ g++-13 g++-13-x86-64-linux-gnu g++-x86-64-linux-gnu gcc gcc-13 gcc-13-base gcc-13-x86-64-linux-gnu gcc-x86-64-linux-gnu
javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan8 libatomic1 libbinutils libcc1-0
libctf-nobfd0 libctf0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libgcc-13-dev libgomp1 libgprofng0 libhwasan0 libisl23
libitm1 libjs-jquery libjs-sphinxdoc libjs-underscore liblsan0 libmpc3 libpq-dev libpython3-dev libpython3.12-dev libquadmath0 libsframe1
libssl-dev libstdc++-13-dev libtsan2 libubsan1 lto-disabled-list make python3-dev python3-pip python3-wheel python3.12-dev zlib1g-dev
0 upgraded, 61 newly installed, 0 to remove and 41 not upgraded.
Need to get 78.6 MB of archives.
After this operation, 283 MB of additional disk space will be used.
블라블라~
Processing triggers for libc-bin (2.39-0ubuntu8.6) ...
Scanning processes...
Scanning linux images...
Running kernel seems to be up-to-date.
No services need to be restarted.
No containers need to be restarted.
No user sessions are running outdated binaries.
No VM guests are running outdated hypervisor (qemu) binaries on this host.
Python 가상 환경 (venv) 생성 및 활성화
gglabadmin@postgresql1:~$ sudo apt install python3.12-venv -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
python3-pip-whl python3-setuptools-whl
The following NEW packages will be installed:
python3-pip-whl python3-setuptools-whl python3.12-venv
0 upgraded, 3 newly installed, 0 to remove and 41 not upgraded.
Need to get 2,429 kB of archives.
After this operation, 2,777 kB of additional disk space will be used.
Get:1 http://kr.archive.ubuntu.com/ubuntu noble-updates/universe amd64 python3-pip-whl all 24.0+dfsg-1ubuntu1.3 [1,707 kB]
Get:2 http://kr.archive.ubuntu.com/ubuntu noble-updates/universe amd64 python3-setuptools-whl all 68.1.2-2ubuntu1.2 [716 kB]
Get:3 http://kr.archive.ubuntu.com/ubuntu noble-updates/universe amd64 python3.12-venv amd64 3.12.3-1ubuntu0.9 [5,674 B]
Fetched 2,429 kB in 0s (7,165 kB/s)
Selecting previously unselected package python3-pip-whl.
(Reading database ... 92801 files and directories currently installed.)
Preparing to unpack .../python3-pip-whl_24.0+dfsg-1ubuntu1.3_all.deb ...
Unpacking python3-pip-whl (24.0+dfsg-1ubuntu1.3) ...
Selecting previously unselected package python3-setuptools-whl.
Preparing to unpack .../python3-setuptools-whl_68.1.2-2ubuntu1.2_all.deb ...
Unpacking python3-setuptools-whl (68.1.2-2ubuntu1.2) ...
Selecting previously unselected package python3.12-venv.
Preparing to unpack .../python3.12-venv_3.12.3-1ubuntu0.9_amd64.deb ...
Unpacking python3.12-venv (3.12.3-1ubuntu0.9) ...
Setting up python3-setuptools-whl (68.1.2-2ubuntu1.2) ...
Setting up python3-pip-whl (24.0+dfsg-1ubuntu1.3) ...
Setting up python3.12-venv (3.12.3-1ubuntu0.9) ...
Scanning processes...
Scanning linux images...
Running kernel seems to be up-to-date.
No services need to be restarted.
No containers need to be restarted.
No user sessions are running outdated binaries.
No VM guests are running outdated hypervisor (qemu) binaries on this host.
gglabadmin@postgresql1:~$ sudo mkdir -p /opt/patroni_venv
gglabadmin@postgresql1:~$ sudo chown gglabadmin:gglabadmin /opt/patroni_venv
gglabadmin@postgresql1:~$ cd /opt/patroni_venv
gglabadmin@postgresql1:/opt/patroni_venv$ python3 -m venv venv_patroni
gglabadmin@postgresql1:/opt/patroni_venv$ source venv_patroni/bin/activate
(venv_patroni) gglabadmin@postgresql1:/opt/patroni_venv$
Patroni 및 의존성 설치
pip3 install patroni[consul,psycopg2]
Patroni 설정 디렉토리 생성
# 설정 디렉토리 생성
sudo mkdir -p /etc/patroni
# postgres 사용자가 접근할 수 있도록 권한 설정
sudo chown -R postgres:postgres /etc/patroni
Patroni 설정 파일 (patroni.yml) 작성
# 1. 클러스터 기본 설정
scope: postgres-cluster # 클러스터 이름 (두 노드 동일)
name: postgresql1 # 서버 이름 (hostname과 일치시킵니다)
# use_sname_as_hostname: true # name 필드를 사용하여 hostname을 오버라이드할 경우 사용
# 2. REST API 설정
restapi:
listen: 0.0.0.0:8008 # Patroni 관리 API 포트
# 3. DCS (Distributed Configuration Store) 설정
consul:
# 여러 Consul 서버 주소를 콤마로 구분하여 입력합니다.
host: 10.34.1.151:8500,10.34.1.152:8500,10.34.1.153:8500
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
# PostgreSQL 초기화 설정 (Patroni가 PostgreSQL 클러스터를 처음 구성할 때 사용)
initdb:
- encoding: UTF8
- locale: ko_KR.UTF-8
- data-checksums
# pg_hba.conf 설정 (Patroni가 자동으로 설정합니다)
pg_hba:
- host replication rep_user 10.34.1.0/24 md5
- host all all 0.0.0.0/0 md5
- host all all ::/0 md5
# Patroni가 관리할 사용자 정보 (초기 DB 생성 시 사용)
users:
rep_user:
password: '' # <<<--- 복제 사용자 비밀번호
options:
- replication
- bypassrls
admin:
password: '' # <<<--- Patroni 관리용 슈퍼유저 비밀번호
options:
- superuser
- createdb
- createrole
# 4. PostgreSQL 인스턴스 설정
postgresql:
# 이 노드의 IP와 Port를 명시합니다.
listen: 10.34.1.111:5432 # 👈 **postgresql1의 IP**
connect_address: 10.34.1.111:5432 # 👈 **postgresql1의 IP**
port: 5432
bin_dir: /usr/lib/postgresql/16/bin
data_dir: /var/lib/postgresql/16/main
parameters:
unix_socket_directories: '/tmp'
# Patroni가 postgres 계정으로 DB에 접속하기 위한 인증 정보
authentication:
replication:
username: rep_user
password: ''
superuser:
username: postgres
password: '' # <<<--- 기존 postgres 사용자 비밀번호
설정 파일을 서비스로 등록
[Unit]
Description=Patroni PostgreSQL High Availability
After=network.target
Wants=network-online.target
[Service]
User=patroni
Group=patroni
Type=simple
WorkingDirectory=/etc/patroni
ExecStart=/opt/patroni_venv/venv_patroni/bin/patroni /etc/patroni/patroni.yaml
Restart=always
Environment="PATH=/opt/patroni_venv/venv_patroni/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
RestartSec=5
# Patroni가 종료될 때 PostgreSQL도 정상 종료되도록 함
TimeoutStopSec=30
KillMode=process
[Install]
WantedBy=multi-user.target
Patroni 설정 파일 권한 점검
sudo chown -R patroni:patroni /etc/patroni
# postgre 의 main 이 최초 비어 있어야 한다고 한다.
sudo rm -rf /var/lib/postgresql/16/main
sudo mkdir -p /var/lib/postgresql/16/main
sudo chown -R patroni:patroni /var/lib/postgresql/16
sudo chmod -R 700 /var/lib/postgresql/16
Patroni 실행
sudo systemctl daemon-reload
sudo systemctl status patroni
○ patroni.service - Patroni PostgreSQL High Availability
Loaded: loaded (/etc/systemd/system/patroni.service; disabled; preset: enabled)
Active: inactive (dead)
sudo systemctl enable patroni
sudo systemctl start patroni
여기까지 여러 오류들이 있었고 해결하면서 상위 코드들을 일부 보완하였다.
특히 consul 연결이 가장 오래 걸렸는데...
curl -X DELETE http://10.34.1.151:8500/v1/kv/service/postgres-cluster?recurse
이미 시도된 정보가 남아 있어서 상기와 같이 정보를 날려주고 다시 하니까 되는 경우가 종종있었다.
1번 서버가 정상 동작시 아래와 같은 로그가 찍힌다.
(venv_patroni) gglabadmin@postgresql1:~$ sudo journalctl -u patroni -f
Dec 06 23:34:30 postgresql1 patroni[20506]: 2025-12-06 23:34:30,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:34:40 postgresql1 patroni[20506]: 2025-12-06 23:34:40,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:34:50 postgresql1 patroni[20506]: 2025-12-06 23:34:50,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:00 postgresql1 patroni[20506]: 2025-12-06 23:35:00,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:10 postgresql1 patroni[20506]: 2025-12-06 23:35:10,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:20 postgresql1 patroni[20506]: 2025-12-06 23:35:20,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:30 postgresql1 patroni[20506]: 2025-12-06 23:35:30,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:40 postgresql1 patroni[20506]: 2025-12-06 23:35:40,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:35:50 postgresql1 patroni[20506]: 2025-12-06 23:35:50,302 INFO: no action. I am (postgresql1), the leader with the lock
Dec 06 23:36:00 postgresql1 patroni[20506]: 2025-12-06 23:36:00,302 INFO: no action. I am (postgresql1), the leader with the lock
^C
2번서버가 잘 동작할때는 아래와 같이 나왔다.
gglabadmin@postgresql2:/usr/lib/postgresql/16/bin$ journalctl -u patroni -f
Dec 06 23:32:54 postgresql2 systemd[1]: patroni.service: Main process exited, code=exited, status=1/FAILURE
Dec 06 23:32:54 postgresql2 systemd[1]: patroni.service: Failed with result 'exit-code'.
Dec 06 23:32:55 postgresql2 systemd[1]: Stopped patroni.service - Patroni PostgreSQL High Availability.
Dec 06 23:33:04 postgresql2 systemd[1]: Started patroni.service - Patroni PostgreSQL High Availability.
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,894 INFO: No PostgreSQL configuration items changed, nothing to reload.
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,896 INFO: Systemd integration is not supported
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,897 INFO: Lock owner: postgresql1; I am postgresql2
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,916 INFO: trying to bootstrap from leader 'postgresql1'
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,920 INFO: Lock owner: postgresql1; I am postgresql2
Dec 06 23:33:04 postgresql2 patroni[22557]: 2025-12-06 23:33:04,930 INFO: bootstrap from leader 'postgresql1' in progress
Dec 06 23:33:14 postgresql2 patroni[22557]: 2025-12-06 23:33:14,918 INFO: Lock owner: postgresql1; I am postgresql2
Dec 06 23:33:14 postgresql2 patroni[22557]: 2025-12-06 23:33:14,919 INFO: bootstrap from leader 'postgresql1' in progress
Dec 06 23:33:24 postgresql2 patroni[22557]: 2025-12-06 23:33:24,918 INFO: Lock owner: postgresql1; I am postgresql2
Dec 06 23:33:24 postgresql2 patro
consul l에 의해서 slave 로 patroni 클러스터 참여되어 1번을 복제중이라는 의미로 보인다.
db서버 상호간 방화벽 열기 및 patroni 계정에 db 폴더 사용권한 주기
sudo ufw allow from 10.34.1.0/24 to any port 5432
sudo ufw reload
sudo chown -R patroni:patroni /var/lib/postgresql/16
sudo chmod 700 /var/lib/postgresql/16
여기까지 조정하니 아래와 같이 잘 설정 되었다.
Dec 06 23:45:31 postgresql2 patroni[23184]: 10.34.1.112:5432 - accepting connections
Dec 06 23:45:31 postgresql2 patroni[22557]: 2025-12-06 23:45:31,567 INFO: Lock owner: postgresql1; I am postgresql2
Dec 06 23:45:31 postgresql2 patroni[22557]: 2025-12-06 23:45:31,567 INFO: establishing a new patroni heartbeat connection to postgres
Dec 06 23:45:31 postgresql2 patroni[22557]: 2025-12-06 23:45:31,634 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:45:41 postgresql2 patroni[22557]: 2025-12-06 23:45:41,805 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:45:51 postgresql2 patroni[22557]: 2025-12-06 23:45:51,757 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:46:02 postgresql2 patroni[22557]: 2025-12-06 23:46:02,068 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:46:11 postgresql2 patroni[22557]: 2025-12-06 23:46:11,931 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:46:21 postgresql2 patroni[22557]: 2025-12-06 23:46:21,614 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
1번 서버의 네트워크를 잠깐 내려봤다.
Dec 06 23:56:41 postgresql2 patroni[22557]: 2025-12-06 23:56:41,655 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:56:51 postgresql2 patroni[22557]: 2025-12-06 23:56:51,952 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:57:01 postgresql2 patroni[22557]: 2025-12-06 23:57:01,700 INFO: no action. I am (postgresql2), a secondary, and following a leader (postgresql1)
Dec 06 23:57:10 postgresql2 patroni[22557]: 2025-12-06 23:57:10,288 INFO: establishing a new patroni restapi connection to postgres
Dec 06 23:57:10 postgresql2 patroni[22557]: 2025-12-06 23:57:10,306 INFO: Got response from postgresql1 http://0.0.0.0:8008/patroni: {"state": "running", "postmaster_start_time": "2025-12-06 23:45:30.568628+00:00", "role": "replica", "server_version": 160011, "xlog": {"received_location": 50331976, "replayed_location": 50331976, "replayed_timestamp": null, "paused": false}, "timeline": 1, "replication_state": "streaming", "cluster_unlocked": true, "dcs_last_seen": 1765065430, "database_system_identifier": "7580890216573599783", "patroni": {"version": "4.1.0", "scope": "postgres-cluster", "name": "postgresql2"}}
Dec 06 23:57:10 postgresql2 patroni[22557]: 2025-12-06 23:57:10,334 INFO: promoted self to leader by acquiring session lock
Dec 06 23:57:10 postgresql2 patroni[23251]: server promoting
Dec 06 23:57:10 postgresql2 patroni[23180]: 2025-12-06 23:57:10.335 UTC [23180] LOG: received promote request
Dec 06 23:57:10 postgresql2 patroni[23181]: 2025-12-06 23:57:10.336 UTC [23181] FATAL: terminating walreceiver process due to administrator command
Dec 06 23:57:10 postgresql2 patroni[23180]: 2025-12-06 23:57:10.337 UTC [23180] LOG: invalid record length at 0/3000148: expected at least 24, got 0
Dec 06 23:57:10 postgresql2 patroni[23180]: 2025-12-06 23:57:10.337 UTC [23180] LOG: redo done at 0/3000110 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 699.72 s
Dec 06 23:57:10 postgresql2 patroni[23180]: 2025-12-06 23:57:10.347 UTC [23180] LOG: selected new timeline ID: 2
Dec 06 23:57:10 postgresql2 patroni[23180]: 2025-12-06 23:57:10.416 UTC [23180] LOG: archive recovery complete
Dec 06 23:57:10 postgresql2 patroni[23178]: 2025-12-06 23:57:10.430 UTC [23178] LOG: checkpoint starting: force
Dec 06 23:57:10 postgresql2 patroni[23176]: 2025-12-06 23:57:10.431 UTC [23176] LOG: database system is ready to accept connections
Dec 06 23:57:10 postgresql2 patroni[23178]: 2025-12-06 23:57:10.478 UTC [23178] LOG: checkpoint complete: wrote 2 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.010 s, sync=0.005 s, total=0.049 s; sync files=2, longest=0.003 s, average=0.003 s; distance=0 kB, estimate=14745 kB; lsn=0/30001B0, redo lsn=0/3000178
Dec 06 23:57:11 postgresql2 patroni[22557]: 2025-12-06 23:57:11,362 INFO: no action. I am (postgresql2), the leader with the lock
10초만에 2번에서 감지하고 리더로 올라온것이 보인다.
1번서버를 다시 살렸더니...
안되길래. 아래와 같이 reinit 을 해야한다고 한다.
gglabadmin@postgresql1:~$ sudo /opt/patroni_venv/venv_patroni/bin/patronictl -c /etc/patroni/patroni.yaml reinit postgres-cluster postgresql1
+ Cluster: postgres-cluster (7580890216573599783) ---+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------------+-------------+---------+---------+----+-------------+-----+------------+-----+
| postgresql1 | 10.34.1.111 | Replica | running | 1 | 0/3000148 | 0 | 0/30001C0 | 0 |
| postgresql2 | 10.34.1.112 | Leader | running | 2 | | | | |
+-------------+-------------+---------+---------+----+-------------+-----+------------+-----+
Are you sure you want to reinitialize members postgresql1? [y/N]:y
Success: reinitialize for member postgresql1
gglabadmin@postgresql1:~$
잘 설정 된것 같다.
gglabadmin@postgresql1:~$ sudo journalctl -u patroni -f
Dec 07 00:06:23 postgresql1 patroni[20506]: 2025-12-07 00:06:23,365 INFO: establishing a new patroni heartbeat connection to postgres
Dec 07 00:06:23 postgresql1 patroni[20506]: 2025-12-07 00:06:23,403 INFO: no action. I am (postgresql1), a secondary, and following a leader (postgresql2)
Dec 07 00:06:33 postgresql1 patroni[20506]: 2025-12-07 00:06:33,413 INFO: no action. I am (postgresql1), a secondary, and following a leader (postgresql2)
Dec 07 00:06:43 postgresql1 patroni[20506]: 2025-12-07 00:06:43,059 INFO: no action. I am (postgresql1), a secondary, and following a leader (postgresql2)
Dec 07 00:06:53 postgresql1 patroni[20506]: 2025-12-07 00:06:53,551 INFO: no action. I am (postgresql1), a secondary, and following a leader (postgresql2)
Dec
그런데 1번이 왜 다시 올라오지 못했나?
로그를 보면 1번에서 자동으로 스스로를 secondary 로 인식까지는 잘 했다.
그런데 스스로가 죽었던 타임라인과 2번이 새로 리더가 되면서 만들어진 타임라인이 달라서 강제로 데이터를 쓰지 않기 위해서 스스로 reinit 을 하지 않는다고 한다.
혹시모를 1번 서버의 데이터를 지키기 위해서 인것 같다.
일단 failover 가 잘되고 무엇보다 일전에 해봣던 pgpool 보다는 간편하다.
다만, 이제 쿼리에 따른 자동 분기를 해야하는데 오디세이라는 툴이 가능한지 이어서 연습을 해야겠다.
'DB > Postgresql' 카테고리의 다른 글
| (연습) postgresql 이중화 (Failover) (0) | 2025.12.07 |
|---|---|
| pgpool 4.1.4 auto fail-over, fail-back (2) | 2021.06.20 |
| pgpool II 4.1.4 load balance (0) | 2021.06.19 |
| postgresql replication 수동 fail-over / fail-back (0) | 2021.06.19 |
| vultr 가상화 + ubuntu 21.04 + postgresql 13 replication (0) | 2021.06.16 |
