티스토리 뷰

 

 

Primary-Replica 구조 다시보기

 

Primary-Replica 구조
[그림1] Primary-Replica 구조

 

설계하여 구조를 세팅하는 것은 누구나도 쉽게 할 수 있을 것입니다.

 

하지만 이 필드에서 요구하는건 이걸로 운영을 하면서 나타나는 여러가지 에러 대응을 하고 어떻게 개선해 나갈지가 중요하다고 생각합니다.

 

솔직히 말하면 이런 대규모 트래픽을 받는 서비스 기업은 극히 드물고, 거의 대부분의 개발자는 경험하지 못할 것입니다.

 

월 1000만건 이상 데이터를 관리하는 저도 이정도로 세팅하고 사용하는 건 아니라서,

아~ 대규모 트래픽을 경험할 때 이런 장애 시나리오가 날 것 같구나를 생각 및 AI에게 물어봐서 작성하게 되었습니다.

 

 

 

 

어떤 장애가 생길까?

 

이해를 돕기 위해 장애 시뮬레이션을 만들었습니다.

 

🖥️ PostgreSQL 장애 & Failover 시뮬레이터 (1 Primary, 3 Replicas)

[정상] Primary에 데이터가 쓰이면, 3대의 Replica로 즉시 안전하게 스트리밍(WAL 복제) 됩니다.
ACTIVE
Primary DB
Read / Write
 
 
 
STANDBY
Replica 1
Streaming
STANDBY
Replica 2
Streaming
STANDBY
Replica 3
Streaming
> System: 1 Primary, 3 Replicas 시뮬레이터가 정상 구동되었습니다.

 

 

 

 

장애 시나리오 1) 유령 데이터 현상 (Replication Lag)

 

증상: "어? 방금 가입했는데 왜 정보가 없죠?"

Primary DB가 초당 수천 개의 쓰기(Insert) 작업을 수행하며 일기장(WAL)을 Replica들에게 쉴 새 없이 던집니다.

하지만 Replica의 하드디스크 I/O 성능이 이를 따라가지 못하면 0.1초 ~ 0.5초 이상의 복제 지연(Lag)이 발생합니다.

사용자가 회원가입을 완료(Primary 쓰기)하고 곧바로 내 프로필 화면으로 리다이렉트(Replica 읽기)되었을 때, 아직 데이터가 Replica에 도착하지 않아 404 Not Found 에러를 만나게 됩니다.

 

방어책: Application Level Routing & Caching

인프라를 강제로 동기(Synchronous)로 바꾸면 전체 시스템이 끔찍하게 느려집니다.

 

  1. Read-Your-Own-Writes 전략 : 쓰기 작업을 수행한 사용자의 세션이나 Redis에 타임스탬프를 기록합니다. 이후 1~2초 내에 들어오는 해당 사용자의 조회 요청은 무조건 Replica가 아닌 Primary로 강제 라우팅시킵니다.
  2. 비즈니스 중요도 분리 : 결제 내역, 포인트 잔액 등 0.1초의 지연도 용납할 수 없는 핵심 데이터는 처음부터 무조건 Primary에서만 읽도록 @Transactional(readOnly = false)로 고정합니다.

 

 

 

 

장애 시나리오 2) 대장님의 죽음 (Primary SPOF)

 

Master-Slave 구조의 태생적이고 치명적인 약점은, 세상에 데이터를 쓸 수 있는(Write) 대장(Primary) 노드가 단 1대뿐이라는 점입니다. 이를 단일 장애점(SPOF: Single Point of Failure)이라고 부릅니다.

증상: 모든 쓰기 마비 (Connection Refused)

하드웨어 결함, 네트워크 단절, 메모리 누수 등으로 Primary DB가 뻗어버리는 상황입니다.

뒤에 멀쩡한 Replica가 3대나 살아있어도, 이들은 읽기 전용'모드이기 때문에 데이터를 쓸 수 없습니다.

사용자가 결제를 시도하거나 글을 작성하려 하면 서버는 무기력하게 에러를 뱉어냅니다.

 

방어책: 자동 장애 조치 (Auto Failover)

엔지니어가 새벽에 알람을 듣고 일어나 수동으로 복구할 때까지 기다릴 순 없습니다.

 

  1. Primary의 상태가(Health Check) 멈춘 것을 감지하면, 즉시 데이터 최신화 상태가 가장 좋은 Replica 중 하나를 새로운 Primary로 승격시킵니다.
  2. 프록시(HAProxy)나 가상 IP(VIP)를 통해 스프링 서버가 새로운 Primary를 바라보도록 자동으로 트래픽을 전환합니다.

 

 

 

 

장애 시나리오 3.)침묵의 살인자 (Replica 단절과 Disk Full)

 

PostgreSQL 운영 중 가장 어이없고 허무하게 전체 장애를 유발하는 케이스입니다.

방어 로직 없이 물리적 복제(Replication Slot)를 맺어두었을 때 발생합니다.

증상: "죽은 부하가 대장을 길동무로 데려가다"

Replica 3번 서버가 랜선이 뽑히거나 하드웨어 고장으로 죽었다고 가정해 봅시다.

Primary 노드는 무척이나 착해서, 죽어버린 Replica 3번이 다시 살아돌아올 때 전달해 주기 위해 그동안 발생한 모든 WAL로그를 지우지 않고 자신의 디스크에 무한정 쌓기 시작합니다.

엔지니어가 이 사실을 늦게 알아채면, Primary의 디스크 용량이 99%...

결국 100%가 되며 'Disk Full' 에러와 함께 멀쩡하던 Primary마저 뻗어버립니다.

 

방어책: 비정한 끊어내기 설정

PostgreSQL의 postgresql.conf 파일에 생명줄 같은 옵션을 추가해야 합니다.

  • max_slot_wal_keep_size = 50GB
  • "Replica가 죽어서 WAL을 보관해 주긴 할 건데, 딱 50GB까지만 기다려준다. 그 용량을 넘어가면 그냥 복제를 끊고 일기장을 지워버려서 내 디스크(Primary)부터 살리겠다!" 라는 안전장치입니다.

 

 

감사합니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함