CI/CD 리드·아키텍트 데이터베이스 기술면접
새 면접Q. 대규모 전자상거래 플랫폼에서 주문 데이터가 월 1억 건 이상 발생합니다. 주문 테이블을 단일 테이블로 유지할 것인지, 파티셔닝 할 것인지, 아니면 별도 아카이빙 전략을 사용할 것인지 각각의 트레이드오프를 설명하고 어떤 기준으로 결정하시겠습니까?
데이터 접근 패턴, 쿼리 성능, 운영 복잡도, 비용 측면에서 각 전략을 비교해보세요.
단일 테이블은 구조가 단순하지만 인덱스 크기 증가로 쓰기 성능이 저하되고 풀스캔 시 비효율적입니다. 파티셔닝(날짜 기준)은 최근 데이터 조회가 빠르고 오래된 파티션 삭제가 용이하지만 파티션 간 조인이 비효율적이고 파티션 키 선택이 중요합니다. 아카이빙은 운영 DB 크기를 최소화하고 성능을 최적화하지만 별도 스토리지 비용과 과거 데이터 조회 시 복잡도가 증가합니다. 결정 기준은 최근 3개월 데이터의 조회 비율이 90% 이상이면 아카이빙, 전체 기간 분석 쿼리가 빈번하면 파티셔닝, 데이터 증가율이 낮으면 단일 테이블을 선택합니다. CI/CD 파이프라인에서는 파티셔닝 전략 변경 시 무중단 마이그레이션 스크립트와 롤백 계획이 필수입니다.
- • 각 전략의 성능 특성과 운영 복잡도 이해
- • 데이터 접근 패턴 기반 의사결정
- • 마이그레이션 리스크와 롤백 전략 고려
대용량 서비스에서 데이터 증가에 따른 성능 저하를 예방하고 스토리지 비용을 최적화하는 아키텍처 설계 시 활용됩니다.
파티셔닝에서 아카이빙으로 전환해야 한다면 어떤 단계로 진행하시겠습니까?
Q. 복합 인덱스(Composite Index)를 설계할 때 컬럼 순서를 결정하는 원칙은 무엇이며, 실제 프로덕션 환경에서 인덱스 순서가 잘못 설계되어 있는지 어떻게 판단하고 개선하시겠습니까?
카디널리티, 쿼리 패턴, 인덱스 선택도를 고려하고 실행 계획 분석 방법을 생각해보세요.
복합 인덱스 컬럼 순서는 첫째로 WHERE 절의 등호(=) 조건 컬럼을 우선하고, 둘째로 높은 카디널리티 컬럼을 앞에 배치하며, 셋째로 범위 조건(<, >) 컬럼을 마지막에 둡니다. 실제 환경에서는 슬로우 쿼리 로그와 실행 계획(EXPLAIN)을 분석하여 인덱스 스캔 범위가 넓거나 Using filesort가 발생하는지 확인합니다. 인덱스 사용 통계(sys.schema_unused_indexes)로 미사용 인덱스를 파악하고, 쿼리 패턴 변화에 따라 인덱스를 재설계합니다. 개선 시에는 새 인덱스를 먼저 생성하고 충분한 모니터링 후 기존 인덱스를 삭제하며, 인덱스 생성 시 ONLINE DDL을 사용하여 서비스 중단을 방지합니다. CI/CD 파이프라인에 인덱스 변경 스크립트를 포함하고 카나리 배포로 성능 영향을 검증합니다.
- • 카디널리티와 쿼리 패턴 기반 컬럼 순서 결정
- • 실행 계획과 슬로우 쿼리 로그 분석
- • 무중단 인덱스 변경 전략
쿼리 성능 최적화와 DB 리소스 효율화를 위해 인덱스 전략을 지속적으로 개선하는 상황에서 활용됩니다.
인덱스가 많아질수록 쓰기 성능이 저하되는데, 인덱스 개수의 적정 기준을 어떻게 설정하시겠습니까?
Q. MSA 환경에서 여러 마이크로서비스가 동일한 데이터베이스를 공유할 때, 각 서비스마다 다른 트랜잭션 격리 수준을 사용하면 어떤 문제가 발생할 수 있으며, 이를 어떻게 관리하시겠습니까?
격리 수준 간 상호작용과 데이터 일관성, 그리고 서비스 간 의존성 관점에서 생각해보세요.
서비스별로 다른 격리 수준을 사용하면 한 서비스는 READ COMMITTED로 커밋되지 않은 데이터를 보지 않지만, 다른 서비스는 READ UNCOMMITTED로 더티 리드를 허용하여 데이터 일관성 문제가 발생합니다. REPEATABLE READ 서비스는 팬텀 리드를 방지하지만 SERIALIZABLE 서비스와 락 경합이 발생하여 데드락 가능성이 높아집니다. 관리 방법으로는 첫째, 조직 전체에 표준 격리 수준(일반적으로 READ COMMITTED)을 정의하고 예외는 아키텍처 리뷰를 거칩니다. 둘째, DB 공유 대신 Database per Service 패턴으로 전환하고 Saga 패턴으로 분산 트랜잭션을 관리합니다. 셋째, 공유가 불가피하면 스키마 레벨로 분리하고 서비스 간 직접 테이블 접근을 금지하며 API를 통해서만 통신하도록 강제합니다.
- • 격리 수준 불일치로 인한 데이터 일관성 문제 이해
- • 조직 차원의 표준화와 거버넌스
- • Database per Service 패턴으로 근본적 해결
레거시 모놀리스를 MSA로 전환하는 과정에서 DB 분리 전략을 수립하고 데이터 일관성을 보장하는 상황에서 활용됩니다.
Saga 패턴을 도입할 때 보상 트랜잭션(Compensating Transaction) 설계 원칙은 무엇입니까?
Q. 프로덕션 환경에서 데드락이 주기적으로 발생하고 있습니다. 데드락의 근본 원인을 파악하는 방법과 재발 방지를 위한 아키텍처 수준의 해결 방안을 제시해주세요.
데드락 로그 분석, 락 획득 순서, 그리고 비관적 락 대신 낙관적 락 사용을 고려해보세요.
데드락 원인 파악은 SHOW ENGINE INNODB STATUS로 최근 데드락 로그를 확인하고, 어떤 트랜잭션들이 어떤 순서로 락을 획득하려 했는지 분석합니다. 일반적으로 서로 다른 순서로 여러 테이블이나 로우를 락하려 할 때 발생합니다. 해결 방안으로 첫째, 모든 트랜잭션이 동일한 순서로 테이블과 로우에 접근하도록 코드를 표준화합니다. 둘째, 트랜잭션 범위를 최소화하고 긴 트랜잭션을 여러 작은 트랜잭션으로 분리합니다. 셋째, 비관적 락(SELECT FOR UPDATE) 대신 버전 컬럼을 사용한 낙관적 락으로 전환하여 락 경합을 줄입니다. 넷째, 재고 차감 같은 경합이 심한 작업은 Redis나 메시지 큐로 직렬화합니다. 다섯째, 데드락 재시도 로직을 애플리케이션에 구현하되 최대 재시도 횟수를 제한합니다.
- • 데드락 로그 분석과 락 획득 순서 표준화
- • 트랜잭션 범위 최소화와 낙관적 락 활용
- • 경합이 심한 작업의 직렬화 또는 분산 처리
동시 접속이 많은 이커머스나 예약 시스템에서 재고 관리, 좌석 예약 등 경합이 발생하는 비즈니스 로직을 안정적으로 처리하는 상황에서 활용됩니다.
낙관적 락을 사용할 때 충돌 빈도가 높아지면 오히려 성능이 저하될 수 있는데, 어떤 기준으로 비관적 락과 낙관적 락을 선택하시겠습니까?
Q. N+1 쿼리 문제가 발생하는 레거시 코드를 발견했습니다. 이 문제를 식별하는 방법, 즉시 적용할 수 있는 해결책, 그리고 장기적인 아키텍처 개선 방안을 각각 설명해주세요.
쿼리 로깅, Eager Loading, 그리고 CQRS 패턴을 고려해보세요.
N+1 문제 식별은 APM 도구나 ORM 쿼리 로깅을 활성화하여 동일한 패턴의 쿼리가 반복 실행되는지 확인하고, 특정 API 응답 시간이 데이터 건수에 비례하여 증가하는지 모니터링합니다. 즉시 해결책으로는 ORM의 Eager Loading(JPA의 fetch join, N+1 방지 어노테이션)을 사용하거나 배치 쿼리로 변환합니다. 쿼리 결과를 애플리케이션에서 조인하는 방법도 고려합니다. 장기적으로는 CQRS 패턴을 도입하여 조회용 비정규화 테이블이나 Read Model을 별도로 구성하고, 복잡한 조인이 필요한 데이터는 Materialized View나 캐시 레이어에 저장합니다. GraphQL DataLoader 같은 배치 로딩 패턴을 적용하거나, 마이크로서비스 환경에서는 BFF(Backend for Frontend)에서 데이터를 조합하여 제공합니다.
- • APM과 쿼리 로깅을 통한 N+1 문제 식별
- • Eager Loading과 배치 쿼리로 즉시 해결
- • CQRS와 비정규화로 장기적 아키텍처 개선
ORM을 사용하는 레거시 애플리케이션에서 성능 문제를 해결하고 대규모 트래픽을 처리할 수 있도록 아키텍처를 개선하는 상황에서 활용됩니다.
CQRS 패턴을 도입할 때 Command와 Query 모델 간의 데이터 동기화는 어떻게 보장하시겠습니까?
Q. 정규화와 비정규화의 트레이드오프를 설명하고, 실무에서 어떤 상황에 각각을 적용하는 것이 적절한지 판단 기준을 제시해주세요.
데이터 일관성, 쿼리 성능, 스토리지 비용 측면에서 비교해보세요.
정규화는 데이터 중복을 제거하여 일관성을 보장하고 갱신 이상을 방지하지만, 조인이 많아져 읽기 성능이 저하됩니다. 비정규화는 조인을 줄여 읽기 성능을 향상시키지만 데이터 중복으로 스토리지 비용이 증가하고 갱신 시 일관성 유지가 어렵습니다. 적용 기준으로 OLTP 시스템에서 쓰기가 빈번하고 데이터 일관성이 중요하면 정규화를 우선하고, OLAP이나 분석 시스템처럼 읽기 중심이고 복잡한 조인이 필요하면 비정규화합니다. 실시간 대시보드나 검색 기능처럼 응답 속도가 중요한 경우 비정규화하되, 원본 데이터는 정규화 상태로 유지하고 비정규화 데이터는 캐시나 Materialized View로 구성합니다. 마이크로서비스에서는 서비스 내부는 정규화하고 서비스 간 데이터 공유는 비정규화된 이벤트나 API 응답으로 처리합니다.
- • 정규화는 일관성 우선, 비정규화는 성능 우선
- • 시스템 특성(OLTP/OLAP)과 요구사항에 따른 선택
- • 하이브리드 접근: 정규화 원본 + 비정규화 캐시
신규 서비스 설계 시 데이터 모델을 결정하거나, 성능 문제로 기존 모델을 개선할 때 비즈니스 요구사항과 기술적 제약을 균형있게 고려하는 상황에서 활용됩니다.
비정규화된 데이터의 일관성을 보장하기 위한 동기화 전략에는 어떤 것들이 있습니까?
Q. 커버링 인덱스(Covering Index)가 무엇인지 설명하고, 실제 프로덕션 환경에서 이를 적용할 때 주의해야 할 점은 무엇입니까?
인덱스만으로 쿼리를 처리할 수 있는 조건과 인덱스 크기 증가의 영향을 생각해보세요.
커버링 인덱스는 쿼리에 필요한 모든 컬럼이 인덱스에 포함되어 있어 테이블 접근 없이 인덱스만으로 결과를 반환할 수 있는 인덱스입니다. SELECT와 WHERE 절의 모든 컬럼이 인덱스에 있으면 실행 계획에서 Using index가 표시되며 성능이 크게 향상됩니다. 주의점으로 첫째, 인덱스에 컬럼을 추가하면 인덱스 크기가 증가하여 메모리 사용량이 늘어나고 쓰기 성능이 저하됩니다. 둘째, 자주 변경되는 컬럼을 인덱스에 포함하면 인덱스 갱신 비용이 증가합니다. 셋째, VARCHAR나 TEXT 같은 큰 컬럼은 인덱스 크기를 급격히 증가시키므로 신중히 판단합니다. 넷째, 쿼리 패턴이 변경되면 커버링 인덱스가 불필요해질 수 있으므로 주기적으로 사용 통계를 모니터링하고 정리합니다.
- • 인덱스만으로 쿼리 처리하여 테이블 접근 제거
- • 인덱스 크기 증가와 쓰기 성능 저하 트레이드오프
- • 쿼리 패턴 변화에 따른 주기적 검토 필요
자주 실행되는 조회 쿼리의 성능을 최적화하면서도 전체 시스템의 쓰기 성능과 리소스 사용을 균형있게 관리하는 상황에서 활용됩니다.
인덱스 크기가 메모리보다 커지면 어떤 문제가 발생하며 이를 어떻게 해결하시겠습니까?
Q. 분산 트랜잭션 환경에서 2PC(Two-Phase Commit)의 한계점과 이를 대체할 수 있는 패턴들을 비교하여 설명해주세요. 각 패턴의 적용 시나리오도 함께 제시해주세요.
2PC의 블로킹 문제와 Saga, TCC, Event Sourcing 패턴을 고려해보세요.
2PC는 준비 단계와 커밋 단계로 나뉘어 원자성을 보장하지만, 코디네이터 장애 시 참여자들이 무한정 대기하는 블로킹 문제가 있고 성능이 저하되며 가용성이 낮아집니다. Saga 패턴은 각 서비스가 로컬 트랜잭션을 실행하고 실패 시 보상 트랜잭션으로 롤백하며, 이벤트 기반으로 느슨한 결합을 유지하지만 일시적 불일치 상태를 허용해야 합니다. 주문-결제-배송 같은 비즈니스 프로세스에 적합합니다. TCC(Try-Confirm-Cancel)는 리소스를 예약하고 확정하거나 취소하는 방식으로 일관성을 높이지만 비즈니스 로직이 복잡해지며, 좌석 예약이나 재고 예약에 적합합니다. Event Sourcing은 상태 변경을 이벤트로 저장하여 완전한 이력 추적이 가능하지만 쿼리 복잡도가 증가하며, 감사 로그가 중요한 금융 시스템에 적합합니다.
- • 2PC의 블로킹 문제와 성능 저하 이해
- • Saga, TCC, Event Sourcing 패턴의 특징과 트레이드오프
- • 비즈니스 요구사항에 따른 패턴 선택
마이크로서비스 아키텍처에서 여러 서비스에 걸친 비즈니스 트랜잭션을 안정적으로 처리하면서도 시스템 가용성을 유지하는 상황에서 활용됩니다.
Saga 패턴에서 보상 트랜잭션이 실패하면 어떻게 처리해야 합니까?
Q. 실행 계획(Execution Plan)을 분석할 때 가장 중요하게 봐야 할 지표들과 각 지표가 의미하는 바를 설명하고, 실제 튜닝 우선순위를 어떻게 결정하시겠습니까?
스캔 방식, 조인 타입, 예상 행 수와 실제 행 수 차이를 중심으로 생각해보세요.
실행 계획에서 첫째, 스캔 방식(type)을 확인하여 ALL(풀 테이블 스캔)이나 index(인덱스 풀 스캔)는 개선 대상이고, ref나 range는 적절하며, const나 eq_ref가 이상적입니다. 둘째, rows(예상 스캔 행 수)가 실제 결과보다 훨씬 크면 불필요한 데이터를 읽는 것이므로 인덱스 추가나 쿼리 재작성이 필요합니다. 셋째, Extra 필드에서 Using filesort나 Using temporary는 디스크 I/O를 유발하므로 인덱스로 정렬을 처리하도록 개선합니다. 넷째, 조인 순서와 조인 타입을 확인하여 작은 테이블을 먼저 읽고 Nested Loop보다 Hash Join이 효율적인지 판단합니다. 튜닝 우선순위는 실행 빈도가 높고 응답 시간이 긴 쿼리를 먼저 개선하며, 스캔 행 수가 많은 순서대로 처리하고, 비즈니스 임팩트가 큰 API부터 최적화합니다.
- • 스캔 방식과 예상 행 수로 비효율 식별
- • Using filesort, Using temporary 제거
- • 실행 빈도와 비즈니스 임팩트 기반 우선순위 결정
슬로우 쿼리를 분석하고 개선하여 시스템 전체 성능을 향상시키고 DB 부하를 줄이는 상황에서 활용됩니다.
옵티마이저가 잘못된 인덱스를 선택하는 경우 어떻게 대응하시겠습니까?
Q. 대규모 테이블에 컬럼을 추가하거나 인덱스를 생성해야 하는 상황에서 서비스 중단 없이 안전하게 스키마 변경을 수행하는 전략을 설명해주세요. CI/CD 파이프라인과의 통합 방안도 함께 제시해주세요.
Online DDL, pt-online-schema-change, 그리고 배포 전략을 고려해보세요.
MySQL 5.6 이상의 Online DDL을 사용하면 대부분의 스키마 변경을 잠금 없이 수행할 수 있지만, 테이블 크기가 크면 복제 지연이 발생할 수 있습니다. Percona의 pt-online-schema-change나 gh-ost 같은 도구는 새 테이블을 생성하고 트리거로 변경사항을 복제한 후 원자적으로 테이블을 교체하여 안전합니다. 전략으로 첫째, 변경 전 충분한 테스트 환경에서 실행 시간과 복제 지연을 측정합니다. 둘째, 피크 시간을 피해 트래픽이 낮은 시간대에 실행하고 모니터링을 강화합니다. 셋째, 컬럼 추가 시 NOT NULL 제약은 나중에 추가하고, 처음엔 NULL 허용으로 생성 후 데이터 마이그레이션 후 제약을 추가합니다. CI/CD 통합은 스키마 변경을 별도 마이그레이션 스크립트로 관리하고, Flyway나 Liquibase로 버전 관리하며, 배포 파이프라인에서 Blue-Green 배포나 카나리 배포와 함께 단계적으로 적용합니다. 롤백 스크립트를 항상 준비하고 변경 전후 데이터 정합성을 검증합니다.
- • Online DDL과 pt-online-schema-change 도구 활용
- • 트래픽 패턴 고려한 실행 시간 선택
- • CI/CD 파이프라인에 마이그레이션 스크립트 통합과 롤백 계획
프로덕션 DB의 스키마를 안전하게 변경하면서 서비스 가용성을 보장하고 배포 리스크를 최소화하는 상황에서 활용됩니다.
스키마 변경 중 복제 지연이 임계치를 넘으면 어떻게 대응하시겠습니까?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!