PostgreSQL 리드·아키텍트 시스템 설계 면접

PostgreSQL 리드 · 아키텍트 (10년+) 시스템 설계 7문항 조회수 32 · 2026-08-04 (화) 15:00:41
1 파티셔닝 전략
Hard

Q. 월 10억 건의 주문 데이터가 발생하는 이커머스 시스템에서 PostgreSQL의 파티셔닝 전략을 설계해야 합니다. Range, List, Hash 파티셔닝 중 어떤 방식을 선택할 것이며, 파티션 키는 무엇으로 설정하겠습니까? 또한 파티션 관리 자동화 전략도 함께 설명해주세요.

주문 데이터의 조회 패턴(최근 데이터 위주)과 데이터 생명주기(과거 데이터 아카이빙)를 고려해보세요.

A. 모범답안

주문 데이터는 Range 파티셔닝을 선택하며, 파티션 키는 order_date로 설정합니다. 최근 데이터 조회가 빈번하고 과거 데이터는 아카이빙이 필요하므로 월별 또는 주별 파티션이 적합합니다. pg_partman 익스텐션을 활용하여 파티션 자동 생성 및 삭제를 관리하고, 최근 3개월은 핫 파티션으로 유지하며 그 이전 데이터는 압축 또는 별도 테이블스페이스로 이동합니다. 파티션 프루닝을 통해 쿼리 성능을 최적화하고, 각 파티션별로 독립적인 인덱스와 통계 정보를 유지합니다. 비즈니스 요구사항에 따라 특정 파티션만 백업하거나 복구할 수 있도록 설계합니다.

핵심 포인트
  • • Range 파티셔닝과 order_date 기준 선택의 근거
  • • pg_partman을 활용한 파티션 자동화 관리
  • • 파티션 프루닝을 통한 쿼리 성능 최적화
  • • 데이터 생명주기에 따른 계층화 전략
답변에 넣으면 좋은 키워드
Range 파티셔닝 pg_partman 파티션 프루닝 테이블스페이스 아카이빙 자동화
실무에서는

대용량 시계열 데이터를 다루는 시스템에서 파티셔닝을 통해 쿼리 성능을 유지하면서 스토리지 비용을 최적화합니다.

Follow-up 질문

파티션 테이블에서 글로벌 인덱스가 필요한 경우(예: 주문번호 조회)는 어떻게 처리하시겠습니까?

2 읽기 확장성 아키텍처
Hard

Q. PostgreSQL 기반 시스템에서 읽기 트래픽이 쓰기 대비 100:1 비율로 발생합니다. Replication 아키텍처를 설계할 때 Streaming Replication, Logical Replication, Connection Pooling, 그리고 캐싱 레이어를 어떻게 조합하여 설계하시겠습니까? 각 선택의 트레이드오프도 함께 설명해주세요.

읽기 일관성 요구사항과 레플리카 지연(lag)이 비즈니스에 미치는 영향을 먼저 분석해보세요.

A. 모범답안

Streaming Replication으로 3개 이상의 읽기 레플리카를 구성하고, PgBouncer를 통한 커넥션 풀링으로 연결 오버헤드를 줄입니다. 애플리케이션 레벨에서 쓰기는 마스터로, 읽기는 레플리카로 라우팅하되, 강한 일관성이 필요한 읽기는 마스터로 보냅니다. Redis 캐싱 레이어를 추가하여 반복적인 조회 쿼리를 캐시하고, Write-Through 패턴으로 데이터 일관성을 유지합니다. Logical Replication은 특정 테이블만 선택적으로 복제가 필요하거나, 이기종 DB 간 동기화가 필요할 때 활용합니다. 레플리카 지연 모니터링을 통해 임계값 초과 시 자동으로 해당 레플리카를 로드밸런서에서 제외하는 헬스체크를 구현합니다.

핵심 포인트
  • • Streaming Replication 기반 읽기 레플리카 구성
  • • PgBouncer를 통한 커넥션 풀링 최적화
  • • 애플리케이션 레벨 읽기/쓰기 분리와 일관성 보장
  • • Redis 캐싱 레이어 통합 및 레플리카 지연 모니터링
답변에 넣으면 좋은 키워드
Streaming Replication PgBouncer 읽기/쓰기 분리 레플리카 지연 캐싱 레이어 헬스체크
실무에서는

대규모 트래픽을 처리하는 서비스에서 읽기 성능을 스케일아웃하면서도 데이터 일관성을 보장하는 아키텍처를 구성합니다.

Follow-up 질문

레플리카 지연이 5초 이상 발생했을 때 애플리케이션에서는 어떻게 대응해야 할까요?

3 인덱스 전략
Hard

Q. 수백만 사용자의 활동 로그를 저장하는 테이블에서 다양한 조회 패턴(시간대별, 사용자별, 이벤트 타입별, 복합 조건)을 지원해야 합니다. B-tree, GiST, GIN, BRIN 인덱스 중 어떤 조합을 선택하고, 각 인덱스의 유지보수 비용과 쿼리 성능 간 트레이드오프를 어떻게 관리하시겠습니까?

각 조회 패턴의 빈도와 데이터의 카디널리티, 그리고 테이블의 업데이트 패턴을 고려해보세요.

A. 모범답안

타임스탬프 컬럼에는 BRIN 인덱스를 적용하여 시계열 데이터의 물리적 정렬 특성을 활용하고 인덱스 크기를 최소화합니다. 사용자 ID와 같이 카디널리티가 높은 컬럼은 B-tree 인덱스를 사용하며, 복합 조건 조회가 빈번한 경우 (user_id, timestamp) 복합 인덱스를 생성합니다. 이벤트 타입처럼 JSONB 필드나 배열을 검색하는 경우 GIN 인덱스를 활용합니다. 파티셔닝과 결합하여 각 파티션별로 필요한 인덱스만 유지하고, pg_stat_user_indexes를 모니터링하여 사용되지 않는 인덱스는 제거합니다. 인덱스 생성 시 CONCURRENTLY 옵션을 사용하여 서비스 영향을 최소화하고, autovacuum 설정을 최적화하여 인덱스 블로트를 방지합니다.

핵심 포인트
  • • 데이터 특성에 맞는 인덱스 타입 선택 (BRIN for 시계열, B-tree for 높은 카디널리티)
  • • 복합 인덱스와 GIN 인덱스의 적절한 활용
  • • pg_stat_user_indexes 기반 인덱스 사용률 모니터링
  • • CONCURRENTLY 옵션과 autovacuum 최적화
답변에 넣으면 좋은 키워드
BRIN B-tree GIN 복합 인덱스 pg_stat_user_indexes CONCURRENTLY autovacuum
실무에서는

대용량 로그 분석 시스템에서 다양한 쿼리 패턴을 지원하면서도 인덱스 유지보수 비용을 최적화합니다.

Follow-up 질문

인덱스 블로트가 심각해져서 쿼리 성능이 저하되었다면 어떻게 해결하시겠습니까?

4 트랜잭션 격리 수준
Hard

Q. 금융 결제 시스템에서 동시성 제어가 중요한 상황입니다. PostgreSQL의 MVCC 아키텍처를 고려할 때, Read Committed, Repeatable Read, Serializable 중 어떤 격리 수준을 선택하시겠습니까? 각 격리 수준에서 발생할 수 있는 동시성 이슈와 성능 트레이드오프, 그리고 애플리케이션 레벨의 보완 전략을 설명해주세요.

결제 시스템에서 중복 결제 방지, 잔액 일관성, 처리량 간의 균형을 고려해보세요.

A. 모범답안

기본적으로 Repeatable Read를 사용하여 트랜잭션 내에서 일관된 스냅샷을 보장하고, 팬텀 리드를 방지합니다. 중복 결제 방지를 위해 idempotency key를 유니크 제약조건으로 설정하고, 잔액 업데이트 시 SELECT FOR UPDATE를 활용하여 명시적 락을 획득합니다. Serializable은 가장 강한 보장을 제공하지만 직렬화 오류로 인한 재시도가 빈번하여 처리량이 감소하므로, 크리티컬한 특정 트랜잭션에만 선택적으로 적용합니다. Read Committed는 non-repeatable read 문제가 있어 금융 시스템에는 부적합합니다. 애플리케이션 레벨에서는 낙관적 락(버전 컬럼)과 재시도 로직을 구현하고, 트랜잭션 타임아웃을 설정하여 장기 트랜잭션을 방지합니다. 데드락 발생 시 자동 재시도 정책을 수립하고, pg_stat_database를 통해 트랜잭션 충돌을 모니터링합니다.

핵심 포인트
  • • Repeatable Read를 기본으로 한 일관된 스냅샷 보장
  • • SELECT FOR UPDATE를 통한 명시적 락과 idempotency key 활용
  • • Serializable의 선택적 적용과 성능 트레이드오프
  • • 낙관적 락, 재시도 로직, 타임아웃 설정 등 애플리케이션 레벨 보완
답변에 넣으면 좋은 키워드
MVCC Repeatable Read SELECT FOR UPDATE idempotency key 낙관적 락 직렬화 오류 데드락
실무에서는

금융 결제나 재고 관리 시스템에서 동시성 제어와 성능 사이의 균형을 맞추며 데이터 일관성을 보장합니다.

Follow-up 질문

Serializable 격리 수준에서 직렬화 오류가 빈번하게 발생한다면 어떻게 최적화하시겠습니까?

5 캐싱 전략
Hard

Q. PostgreSQL 기반 API 시스템에서 캐싱 레이어를 설계합니다. Query Result Cache, Materialized View, Redis Cache를 어떻게 조합하여 사용하시겠습니까? 각 캐시 레이어의 TTL 전략, 캐시 무효화 정책, 그리고 캐시 미스 시 DB 부하 방지 전략을 포함하여 설명해주세요.

데이터의 변경 빈도, 조회 빈도, 일관성 요구사항에 따라 계층적으로 접근해보세요.

A. 모범답안

3단계 캐싱 전략을 적용합니다. 첫째, 애플리케이션 레벨에서 Redis를 활용한 쿼리 결과 캐싱으로 가장 빈번한 조회(상품 상세, 사용자 프로필)를 처리하며 TTL은 5-10분으로 설정합니다. 둘째, 복잡한 집계 쿼리는 Materialized View로 사전 계산하고, pg_cron이나 트리거를 통해 주기적 또는 이벤트 기반으로 REFRESH합니다. 셋째, PostgreSQL의 shared_buffers와 effective_cache_size를 적절히 설정하여 DB 레벨 캐싱을 최적화합니다. 캐시 무효화는 Write-Through 패턴으로 데이터 변경 시 즉시 캐시를 갱신하거나 삭제하며, 이벤트 기반 무효화를 위해 PostgreSQL의 NOTIFY/LISTEN을 활용합니다. Cache Stampede 방지를 위해 확률적 조기 만료(Probabilistic Early Expiration)나 락 기반 갱신을 구현하고, Circuit Breaker 패턴으로 캐시 장애 시 DB를 보호합니다.

핵심 포인트
  • • Redis, Materialized View, DB 레벨 캐시의 3단계 전략
  • • 데이터 특성에 따른 차별화된 TTL 및 갱신 전략
  • • Write-Through 패턴과 NOTIFY/LISTEN 기반 캐시 무효화
  • • Cache Stampede 방지 및 Circuit Breaker 패턴
답변에 넣으면 좋은 키워드
Redis Materialized View TTL Write-Through NOTIFY/LISTEN Cache Stampede Circuit Breaker
실무에서는

대규모 트래픽을 처리하는 API 시스템에서 다층 캐싱을 통해 DB 부하를 줄이고 응답 속도를 최적화합니다.

Follow-up 질문

Materialized View의 REFRESH 중에도 조회가 가능하도록 하려면 어떻게 해야 할까요?

6 API 아키텍처
Hard

Q. PostgreSQL을 백엔드로 사용하는 RESTful API에서 페이지네이션을 구현합니다. OFFSET/LIMIT, Cursor-based, Keyset Pagination 중 어떤 방식을 선택하시겠습니까? 각 방식의 성능 특성과 대용량 데이터셋에서의 문제점, 그리고 실시간 데이터 추가 시 일관성 이슈를 어떻게 해결할지 설명해주세요.

수백만 건 이상의 데이터에서 깊은 페이지로 이동할 때의 성능과 데이터 일관성을 고려해보세요.

A. 모범답안

Keyset Pagination(Seek Method)을 우선 선택합니다. WHERE id > last_seen_id ORDER BY id LIMIT 100 형태로 구현하여 인덱스를 효율적으로 활용하고, 깊은 페이지에서도 일정한 성능을 보장합니다. OFFSET/LIMIT은 구현이 간단하지만 OFFSET이 클수록 스캔해야 할 행이 많아져 성능이 선형적으로 저하되므로 피합니다. Cursor-based는 Base64 인코딩된 커서를 사용하여 페이지 상태를 캡슐화하며, 타임스탬프와 ID를 조합한 복합 키로 정렬 순서를 보장합니다. 실시간 데이터 추가로 인한 중복/누락 문제는 스냅샷 타임스탬프를 포함하여 해결하거나, 클라이언트에게 새 데이터 알림을 별도로 제공합니다. 총 개수가 필요한 경우 정확한 COUNT 대신 EXPLAIN을 파싱하거나 근사치를 제공하여 성능을 개선합니다. 인덱스는 (order_column, id) 형태로 생성하여 커버링 인덱스 효과를 극대화합니다.

핵심 포인트
  • • Keyset Pagination을 통한 일정한 성능 보장
  • • OFFSET/LIMIT의 성능 문제와 대안
  • • 스냅샷 타임스탬프를 활용한 데이터 일관성 보장
  • • 복합 인덱스를 통한 쿼리 최적화
답변에 넣으면 좋은 키워드
Keyset Pagination Cursor-based OFFSET/LIMIT 커버링 인덱스 스냅샷 타임스탬프 Seek Method
실무에서는

대용량 목록 조회 API에서 사용자 경험을 해치지 않으면서도 DB 부하를 최소화하는 페이지네이션을 구현합니다.

Follow-up 질문

정렬 기준이 여러 개이고 NULL 값이 포함된 경우 Keyset Pagination을 어떻게 구현하시겠습니까?

7 레거시 전환 전략
Hard

Q. 10년간 운영된 모놀리식 시스템의 PostgreSQL 데이터베이스를 마이크로서비스 아키텍처로 전환해야 합니다. 데이터베이스 분리 전략(Database per Service vs Shared Database), 트랜잭션 경계 재설계, 데이터 일관성 보장 방법, 그리고 무중단 마이그레이션 계획을 포함하여 전환 전략을 설계해주세요.

한 번에 전환하는 Big Bang 방식보다는 점진적 전환과 양방향 동기화를 고려해보세요.

A. 모범답안

Strangler Fig 패턴으로 점진적 전환을 수행합니다. 먼저 도메인 경계를 분석하여 강하게 결합된 테이블 그룹을 식별하고, 각 마이크로서비스별로 독립적인 데이터베이스를 할당하는 Database per Service 원칙을 따릅니다. 초기에는 Logical Replication으로 기존 DB와 신규 서비스 DB 간 양방향 동기화를 구축하여 롤백 가능성을 확보합니다. 서비스 간 트랜잭션은 Saga 패턴(Choreography 또는 Orchestration)으로 재설계하고, 보상 트랜잭션을 통해 최종 일관성을 보장합니다. 서비스 간 조인이 필요한 경우 CQRS 패턴으로 읽기 모델을 별도로 구성하거나, API Composition으로 애플리케이션 레벨에서 처리합니다. Foreign Key 제약조건은 애플리케이션 레벨 검증으로 대체하고, 참조 데이터는 이벤트 기반으로 동기화합니다. 전환 과정에서 Feature Toggle과 카나리 배포를 활용하여 리스크를 최소화하고, 모니터링을 강화하여 데이터 불일치를 조기에 감지합니다.

핵심 포인트
  • • Strangler Fig 패턴과 Database per Service 원칙
  • • Logical Replication 기반 양방향 동기화
  • • Saga 패턴을 통한 분산 트랜잭션 관리
  • • CQRS, API Composition, 이벤트 기반 동기화
답변에 넣으면 좋은 키워드
Strangler Fig Database per Service Logical Replication Saga 패턴 CQRS 보상 트랜잭션 최종 일관성
실무에서는

레거시 모놀리식 시스템을 마이크로서비스로 전환하면서 비즈니스 연속성을 보장하고 리스크를 관리합니다.

Follow-up 질문

Saga 패턴에서 보상 트랜잭션이 실패하는 경우는 어떻게 처리해야 할까요?

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!