# 동시 접속 20, 60초 수행
pgbench -c 20 -j 4 -T 60 -r sbtest
결과: 약 707 TPS K3s 홈 서버 환경임을 고려할 때, 쓰기(Write)가 포함된 트랜잭션에서 700대 TPS는 상당히 준수한 수치다. 이것이 우리 서버의 기준점(Baseline)이 된다.
root@pgbench-client:/# pgbench -c 20 -j 4 -T 60 -r sbtest
pgbench (14.20 (Debian 14.20-1.pgdg13+1), server 17.6)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 50
query mode: simple
number of clients: 20
number of threads: 4
duration: 60 s
number of transactions actually processed: 42595
latency average = 28.255 ms
initial connection time = 30.840 ms
tps = 707.839182 (without initial connection time)
statement latencies in milliseconds:
0.001 \set aid random(1, 100000 * :scale)
0.000 \set bid random(1, 1 * :scale)
0.000 \set tid random(1, 10 * :scale)
0.000 \set delta random(-5000, 5000)
1.379 BEGIN;
4.807 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
1.748 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
2.045 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
4.299 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
1.666 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
12.270 END;
3. 시나리오 2: Replica 읽기 분산과 트러블슈팅
이제 읽기 전용(Read-Only) 부하를 Replica로 보내 성능을 테스트할 차례다. PGHOST를 Read 서비스로 변경하고 테스트를 돌렸는데… 멈췄다.
이슈: 무한 대기와 WAL 누락
아무리 기다려도 응답이 없어서 Replica 파드의 로그를 확인해보니 충격적인 에러가 찍혀 있었다.
FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 00000001...10 has already been removed
원인 분석: 데이터 초기화 단계(-i -s 50)에서 대량의 데이터를 너무 빠르게 밀어 넣는 바람에, Replica가 동기화하기도 전에 Master가 디스크 공간 확보를 위해 오래된 WAL(Write-Ahead Log) 파일을 지워버린 것이다. “형, 나 10번 파일 줘” 했는데 형이 “야, 그거 이미 지웠어”라고 하는 상황.
해결 방법: Replica가 처음부터 다시 데이터를 받아오도록(Base Backup) Pod와 PVC(디스크)를 모두 삭제하여 초기화했다.
# 1. 파드 삭제
kubectl delete pod postgresql-read-0 -n data
# 2. PVC 삭제 (핵심! 이걸 지워야 데이터가 날아가서 처음부터 다시 받아온다)
kubectl delete pvc data-postgresql-read-0 -n data
이후 Replica가 정상적으로 Running 상태가 된 것을 확인하고 재시도했다. Replica 테스트 시에는 -n (No Vacuum) 옵션이 필수다. (Replica는 읽기 전용이라 Vacuum을 수행할 수 없기 때문)
pgbench -n -c 20 -j 4 -T 60 -S -r sbtest
결과: 약 656 TPS Master(707 TPS)와 거의 대등한 읽기 성능을 보여주었다. 복제가 성능 저하 없이 잘 동작함을 확인했다.
root@pgbench-client:/# pgbench -n -c 20 -j 4 -T 60 -S -r sbtest
pgbench (14.20 (Debian 14.20-1.pgdg13+1), server 17.6)
transaction type: <builtin: select only>
scaling factor: 50
query mode: simple
number of clients: 20
number of threads: 4
duration: 60 s
number of transactions actually processed: 39442
latency average = 30.454 ms
initial connection time = 356.658 ms
tps = 656.733215 (without initial connection time)
statement latencies in milliseconds:
0.001 \set aid random(1, 100000 * :scale)
30.248 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
4. 시나리오 3: HPA 오토스케일링의 위력
마지막으로 가장 기대했던 Horizontal Pod Autoscaler (HPA) 테스트다. 트래픽이 몰리면 Replica 파드가 자동으로 늘어나서 성능이 좋아지는지 보고 싶었다.
이슈: HPA가 생성이 안 된다?
values.yaml에 분명 autoscaling: enabled: true를 넣었는데 kubectl get hpa를 쳐보니 아무것도 없었다.
알고 보니 내가 사용한 차트는 bitnami/postgresql-ha가 아니라 일반 bitnami/postgresql 차트였다. 일반 차트는 버전이나 설정에 따라 HPA 템플릿이 내장되어 있지 않아 설정이 무시된 것이다.
해결: 수동으로 hpa.yaml을 작성하여 적용했다. (테스트를 위해 CPU 임계치를 50%로 낮춤)
테스트 도중 backend died 에러가 일부 발생했다. 급격한 스케일 아웃 과정에서 리소스(메모리) 부족으로 인한 OOM 혹은 커넥션 재분배 과정의 드랍으로 추정된다. 아래 사진과 같이 복제된 파드가 종료가 되는 것을 확인할 수 있다.
하지만 최종 결과는 놀라웠다.
변경 전: 656 TPS (Pod 1개)
변경 후:2,424 TPS (Pod 3개)
약 3.7배의 성능 향상을 기록했다. HPA가 동작하여 파드가 3개로 늘어났고, 로드밸런서가 트래픽을 적절히 분산해주었기 때문이다.
pgbench (14.20 (Debian 14.20-1.pgdg13+1), server 17.6)
pgbench: error: client 5 aborted in command 1 (SQL) of script 0; perhaps the backend died while processing
pgbench: error: client 10 aborted in command 1 (SQL) of script 0; perhaps the backend died while processing
pgbench: error: client 20 aborted in command 1 (SQL) of script 0; perhaps the backend died while processing
pgbench: error: client 2 aborted in command 1 (SQL) of script 0; perhaps the backend died while processing
pgbench: error: client 13 aborted in command 1 (SQL) of script 0; perhaps the backend died while processing
...
transaction type: <builtin: select only>
scaling factor: 50
query mode: simple
number of clients: 40
number of threads: 10
duration: 300 s
number of transactions actually processed: 727652
latency average = 16.497 ms
initial connection time = 359.488 ms
tps = 2424.754928 (without initial connection time)
statement latencies in milliseconds:
0.001 \set aid random(1, 100000 * :scale)
14.276 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
pgbench: fatal: Run was aborted; the above results are incomplete.
참고: 부하 테스트가 끝난 후 CPU 사용량이 5%대로 떨어졌지만 파드는 바로 줄어들지 않았다. 이는 Kubernetes HPA의 Stabilization Window(기본 5분) 정책 때문이다. 트래픽이 잠시 줄었다고 바로 파드를 죽이면 “Flapping(널뛰기)” 현상이 발생하기 때문에, 일정 시간 동안 낮은 부하가 유지되어야 Scale In이 발생한다.
아래 사진과 같이 테스트가 마친 후에는 파드가 내려가는 것을 확인할 수 있다.
5. 결론
이번 테스트를 통해 홈 서버 K3s 환경에서도 엔터프라이즈급 HA 구성과 오토스케일링이 완벽하게 동작함을 검증했다.
HA 구성: Master 장애나 부하 시에도 Replica를 통해 읽기 성능을 확장할 수 있다.
트러블슈팅: 대량 데이터 적재 시 wal_keep_size 튜닝이나 PVC 초기화가 필요함을 배웠다.
HPA: 트래픽에 따라 유연하게 파드가 늘어나며, 실제 처리량(TPS)이 선형적으로 증가함을 확인했다.