PostgreSQL 시니어 시스템 설계 면접
새 면접Q. PostgreSQL의 4가지 트랜잭션 격리 수준(Read Uncommitted, Read Committed, Repeatable Read, Serializable)의 차이점을 설명하고, 금융 거래 시스템에서 동시성 제어와 성능 사이의 트레이드오프를 고려하여 어떤 격리 수준을 선택하시겠습니까? 또한 Serializable 격리 수준에서 발생할 수 있는 Serialization Failure를 애플리케이션 레벨에서 어떻게 처리해야 하는지 설명해주세요.
Read Committed는 커밋된 데이터만 읽지만 Phantom Read가 발생할 수 있고, Repeatable Read는 스냅샷 격리로 일관된 읽기를 보장하지만 Write Skew가 가능하며, Serializable은 SSI(Serializable Snapshot Isolation)로 완전한 직렬화를 보장하지만 성능 오버헤드가 있습니다. 금융 거래 시스템에서는 계좌 잔액 업데이트와 같은 핵심 트랜잭션에 Serializable을 사용하고, 조회 쿼리는 Repeatable Read를 사용하는 혼합 전략이 효과적입니다. Serialization Failure 발생 시 재시도 로직을 구현하되, 최대 재시도 횟수를 제한하고 지수 백오프를 적용하며, 트랜잭션을 짧게 유지하여 충돌 가능성을 최소화해야 합니다.
- • 각 격리 수준의 이상 현상(Dirty Read, Non-repeatable Read, Phantom Read, Write Skew) 이해
- • PostgreSQL의 SSI 메커니즘과 성능 영향 분석
- • 비즈니스 요구사항에 따른 격리 수준 선택 전략
- • Serialization Failure 처리를 위한 재시도 로직과 백오프 전략
SELECT FOR UPDATE와 SELECT FOR SHARE의 차이점과 각각을 사용해야 하는 상황을 설명하고, NOWAIT과 SKIP LOCKED 옵션의 활용 사례를 제시해주세요.
Q. 대규모 마이크로서비스 아키텍처에서 각 서비스가 독립적으로 PostgreSQL에 연결할 때 발생할 수 있는 연결 고갈 문제를 설명하고, PgBouncer와 같은 연결 풀러의 3가지 풀링 모드(Session, Transaction, Statement)의 차이점과 적합한 사용 사례를 제시해주세요. 또한 max_connections 설정과 애플리케이션 레벨 연결 풀 크기를 결정하는 기준을 설명해주세요.
마이크로서비스 환경에서 각 서비스 인스턴스가 독립적인 연결 풀을 유지하면 PostgreSQL의 max_connections를 초과하여 연결 거부가 발생할 수 있습니다. PgBouncer의 Session 모드는 클라이언트당 하나의 연결을 유지하고, Transaction 모드는 트랜잭션 단위로 연결을 재사용하며, Statement 모드는 각 쿼리마다 연결을 반환합니다. Transaction 모드가 가장 일반적이며, Prepared Statement를 사용하지 않고 짧은 트랜잭션이 많은 경우 적합합니다. max_connections는 서버 메모리를 고려하여 설정하되(각 연결당 약 10MB), 실제 동시 활성 연결 수를 기준으로 결정하고, 애플리케이션 연결 풀은 CPU 코어 수의 2-3배 정도로 설정하는 것이 일반적입니다.
- • 연결당 메모리 오버헤드와 max_connections의 관계
- • PgBouncer 풀링 모드별 특징과 트레이드오프
- • 마이크로서비스 환경에서의 연결 풀 설계 전략
- • 애플리케이션 연결 풀 크기 산정 공식과 모니터링 지표
Prepared Statement를 사용하는 애플리케이션에서 PgBouncer Transaction 모드를 사용할 때 발생하는 문제점과 해결 방법을 설명해주세요.
Q. 전자상거래 플랫폼에서 상품, 주문, 재고를 관리하는 데이터베이스 스키마를 설계할 때, 동시에 여러 사용자가 같은 상품을 주문하는 상황에서 재고 부족 문제를 방지하기 위한 전략을 제시해주세요. SELECT FOR UPDATE, Optimistic Locking, Pessimistic Locking의 차이점과 각각의 장단점을 설명하고, 높은 동시성 환경에서 어떤 접근 방식을 선택하시겠습니까?
SELECT FOR UPDATE는 행 수준 잠금으로 트랜잭션이 완료될 때까지 다른 트랜잭션의 접근을 차단하는 Pessimistic Locking 방식이며, 재고 차감 시 데이터 일관성을 보장하지만 대기 시간이 발생합니다. Optimistic Locking은 version 컬럼을 사용하여 UPDATE 시 버전을 확인하고, 충돌 시 재시도하는 방식으로 읽기 작업이 많을 때 유리합니다. 높은 동시성 환경에서는 SELECT FOR UPDATE SKIP LOCKED를 활용한 작업 큐 패턴이나, 재고를 별도 테이블로 분리하고 UPDATE 문에서 직접 재고를 차감하는 방식(UPDATE inventory SET quantity = quantity - 1 WHERE product_id = ? AND quantity >= 1)이 효과적입니다. 추가로 Redis와 같은 인메모리 캐시로 재고를 관리하고 비동기로 PostgreSQL에 반영하는 하이브리드 전략도 고려할 수 있습니다.
- • Pessimistic vs Optimistic Locking의 트레이드오프
- • SELECT FOR UPDATE SKIP LOCKED를 활용한 동시성 제어
- • 원자적 UPDATE 문을 통한 재고 차감 패턴
- • 캐시 계층을 활용한 하이브리드 재고 관리 전략
재고가 음수로 내려가는 것을 방지하기 위한 CHECK 제약조건과 애플리케이션 레벨 검증의 차이점을 설명하고, 분산 트랜잭션 환경에서 재고 일관성을 보장하는 방법을 제시해주세요.
Q. PostgreSQL의 고가용성을 위한 아키텍처 구성 시 Synchronous Replication과 Asynchronous Replication의 차이점을 설명하고, synchronous_commit 파라미터의 다양한 설정값(on, remote_write, remote_apply, local, off)이 성능과 데이터 안정성에 미치는 영향을 분석해주세요. 또한 Primary 장애 시 자동 Failover를 구현하기 위한 방법과 Split-brain 문제를 방지하는 전략을 제시해주세요.
Synchronous Replication은 Primary가 Standby의 복제 확인을 기다린 후 커밋을 완료하여 데이터 손실을 방지하지만 네트워크 지연에 영향을 받고, Asynchronous는 즉시 커밋하여 성능이 우수하지만 장애 시 데이터 손실 가능성이 있습니다. synchronous_commit의 on은 WAL이 디스크에 기록될 때까지, remote_write는 Standby OS 버퍼에 도달할 때까지, remote_apply는 Standby에서 적용될 때까지 대기하며, local은 로컬 디스크만, off는 대기하지 않습니다. 자동 Failover는 Patroni, repmgr, Stolon 같은 HA 솔루션을 사용하여 구현하며, etcd나 Consul 같은 분산 합의 시스템으로 리더 선출을 관리합니다. Split-brain 방지를 위해 Fencing 메커니즘(STONITH)을 구현하고, 쿼럼 기반 의사결정을 통해 과반수 노드의 합의를 요구해야 합니다.
- • 동기/비동기 복제의 성능과 안정성 트레이드오프
- • synchronous_commit 설정값별 WAL 처리 동작 차이
- • Patroni 등 HA 솔루션과 분산 합의 시스템 활용
- • Split-brain 방지를 위한 Fencing과 쿼럼 메커니즘
Cascading Replication 구조에서 중간 Standby 서버가 장애 발생했을 때의 영향을 설명하고, Quorum-based Synchronous Replication을 설정하는 방법을 제시해주세요.
Q. PostgreSQL에서 멀티테넌트 SaaS 애플리케이션을 구축할 때 데이터 격리를 위한 전략으로 Schema 분리, Database 분리, Row Level Security(RLS)의 장단점을 비교하고, 각각 어떤 상황에서 적합한지 설명해주세요. 또한 RLS를 구현할 때 성능 최적화를 위해 고려해야 할 사항과 인덱스 설계 전략을 제시해주세요.
Database 분리는 완전한 격리와 독립적인 백업/복원이 가능하지만 관리 오버헤드가 크고 테넌트 수에 제한이 있으며, Schema 분리는 중간 수준의 격리를 제공하고 관리가 용이하지만 search_path 설정이 필요합니다. RLS는 단일 테이블에서 정책 기반으로 행을 필터링하여 운영이 간단하지만 복잡한 쿼리에서 성능 저하가 발생할 수 있습니다. 소규모 고가용 테넌트는 Database 분리, 중대규모는 Schema 분리, 대규모 저비용 테넌트는 RLS가 적합합니다. RLS 성능 최적화를 위해서는 tenant_id 컬럼을 모든 인덱스의 첫 번째 컬럼으로 포함시키고, 파티셔닝과 결합하여 테넌트별로 물리적 분리를 구현하며, EXPLAIN ANALYZE로 정책이 올바르게 적용되는지 확인해야 합니다.
- • 멀티테넌트 데이터 격리 전략별 특징과 적용 시나리오
- • RLS 정책 구현 방법과 성능 영향
- • tenant_id 기반 인덱스 설계와 파티셔닝 결합
- • 보안과 성능 사이의 균형을 고려한 아키텍처 선택
RLS와 함께 Application-level 필터링을 중복으로 구현하는 것의 장단점을 설명하고, PostgreSQL의 GRANT/REVOKE 시스템과 RLS의 관계를 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!