시스템 설계 예상문제 (중급)
Backend Engineering · Intermediate Practice
시스템 설계 예상문제 · 중급 정답
중급 시스템 설계 문제에 대한 하나의 답변 예시입니다. 정답을 암기하기보다 가정, 판단 근거, 대안과 실제 경험을 자신의 언어로 설명하는 데 활용하세요.
한정 수량 공동구매 서비스
상황
조건
규모와 시스템 구성
- 회원 500만 명, 행사 동시 접속 20만 명
- 상품별 수량 1천~1만 개
- Spring Boot, MySQL, Redis 구성
현재 문제와 제약
- Traffic행사 시작 시 조회·주문 집중
- Stock동시 주문으로 초과 판매
- Timeout결제 실패 후 재고 미반환
꼬리 질문
조회 요청과 주문 요청을 구분해 어디부터 확장하겠습니까? 캐시, 서버 증설, DB 튜닝의 우선순위와 그 이유를 설명해 주세요.
답변 예시 보기
진단과 접근
조회와 주문은 병목의 성격이 다릅니다. 상품 설명처럼 자주 바뀌지 않는 조회는 캐시와 CDN으로 흡수하고, 주문은 재고 정합성을 지켜야 하므로 처리량을 제한하며 DB까지 도달하는 요청 수를 관리하는 것이 먼저입니다.
설계와 운영
- 상품 상세·이미지는 CDN과 Redis에 캐시하고 TTL에 지터를 주어 행사 시작 시 동시 만료를 줄입니다.
- 주문 API는 별도 서버 풀과 커넥션 풀을 사용하고 대기열 또는 rate limit으로 DB 처리량 이상의 요청을 받지 않습니다.
- 캐시 적중률, DB 커넥션 사용률, 주문 p95, 오류율을 함께 보고 병목이 실제로 이동했는지 확인합니다.
서버만 늘리면 조회 처리량은 늘어도 하나의 재고 행에 대한 경쟁은 해결되지 않습니다. 먼저 부하 테스트로 조회와 주문의 최대 처리량을 따로 측정하고, 가장 먼저 포화되는 자원부터 개선하는 순서가 안전합니다.
여러 사용자가 마지막 한 개를 동시에 주문할 때 초과 판매를 막는 방법을 제시해 주세요. DB 조건부 갱신과 Redis 재고 관리 중 무엇을 선택할지도 설명해 주세요.
답변 예시 보기
진단과 접근
핵심 불변식은 성공한 주문 수가 재고를 넘지 않는 것입니다. DB를 기준 원장으로 사용한다면 재고 조회와 차감을 분리하지 말고 조건부 갱신 한 번으로 처리해 경쟁 조건을 막을 수 있습니다.
설계와 운영
- 예를 들어 UPDATE 상품 SET stock=stock-1 WHERE id=? AND stock>0의 영향 행 수가 1일 때만 예약을 성공시킵니다.
- Redis를 사용한다면 Lua로 확인과 차감을 원자적으로 처리하고, reservationId와 멱등키를 함께 기록합니다.
- DB unique constraint와 주문별 idempotency key를 마지막 안전장치로 두어 재시도가 두 번 차감하지 않게 합니다.
DB 조건부 갱신은 단순하고 신뢰하기 쉽지만 인기 상품 한 행에 쓰기가 집중됩니다. Redis는 처리량이 높지만 DB 반영·장애 복구가 추가되므로 현재 규모와 팀 운영 역량을 근거로 선택합니다.
주문 후 10분 안에 결제하지 않으면 재고를 반환해야 합니다. 예약 상태와 만료 작업을 어떻게 설계하고, 중복 실행이나 서버 장애에 어떻게 대응하겠습니까?
답변 예시 보기
진단과 접근
재고 확보와 판매 완료를 하나의 상태로 표현하면 만료 작업과 결제 완료가 충돌합니다. 주문을 RESERVED, PAID, EXPIRED 같은 상태로 관리하고 허용된 상태 전이만 조건부로 수행해야 합니다.
설계와 운영
- 예약 시 expiresAt을 저장하고 지연 큐나 주기 작업이 만료 후보를 찾습니다.
- 만료 처리는 WHERE status=RESERVED AND expiresAt<=now 조건으로 EXPIRED 전환에 성공한 경우에만 재고를 반환합니다.
- 결제 완료도 RESERVED 상태에서만 PAID로 전환하며 같은 주문번호 재호출은 기존 결과를 반환합니다.
지연 큐 하나에만 의존하면 메시지 유실 시 좌석이 남을 수 있으므로 DB의 만료 상태를 다시 훑는 보정 배치를 함께 두는 것이 좋습니다. 만료 지연 건수와 오래된 RESERVED 수를 알림 지표로 둡니다.
사내 URL 단축 서비스
상황
조건
규모와 시스템 구성
- 하루 10만 링크 생성, 3천만 리다이렉트
- 기본 보존 기간 3년
- 사용자 지정 별칭은 선택 기능
현재 문제와 제약
- Collision짧은 키 중복 가능성
- Read Heavy조회가 생성보다 훨씬 많음
- Expiry만료·차단 상태 처리
꼬리 질문
짧은 키를 어떤 방식으로 만들고 중복을 어떻게 막겠습니까? 같은 생성 요청이 재시도될 때 결과가 달라지지 않게 하는 방법도 설명해 주세요.
답변 예시 보기
진단과 접근
단축 키는 유일하고 발급 후 다른 URL로 바뀌지 않아야 합니다. 자동 생성 키와 사용자 별칭의 생성 정책을 먼저 구분하고 DB unique constraint를 최종 방어선으로 둡니다.
설계와 운영
- DB sequence나 분산 ID를 Base62로 변환하면 충돌 검사가 단순하며, 랜덤 키는 충돌 시 재시도가 필요합니다.
- 생성 요청에 idempotency key를 받아 응답 유실 후 같은 요청이 와도 기존 키를 반환합니다.
- 사용자 별칭은 별도 예약 API와 unique index로 중복을 막고 삭제 후 재사용 정책을 명확히 합니다.
예측 가능한 키가 보안상 문제라면 충분히 긴 랜덤 키가 더 적합합니다. 어떤 방식을 택하든 생성 성공 직후 유일성, 재시도, 동시 요청을 테스트해야 합니다.
리다이렉트 응답을 빠르게 하기 위해 캐시를 어디에 적용하고, 캐시에 값이 없을 때 어떤 흐름으로 조회하겠습니까?
답변 예시 보기
진단과 접근
리다이렉트는 읽기가 압도적으로 많고 매핑이 거의 변하지 않으므로 cache-aside가 적합합니다. 요청은 애플리케이션 캐시 또는 Redis를 먼저 보고 miss일 때 DB에서 읽어 캐시에 넣습니다.
설계와 운영
- 인기 링크는 CDN 또는 edge cache까지 올려 애플리케이션에 도달하는 요청을 줄입니다.
- 동시에 같은 키가 miss되면 한 요청만 DB를 조회하도록 요청 병합을 적용합니다.
- 없는 키도 짧게 negative cache하여 무작위 키 요청이 DB를 반복 조회하지 않게 합니다.
TTL을 길게 하면 적중률은 좋아지지만 만료·차단 반영이 늦습니다. 매핑과 정책 상태의 TTL을 다르게 두고 cache hit ratio, DB QPS, p99를 측정합니다.
링크가 만료되거나 악성 링크로 차단됐을 때 오래된 캐시 때문에 계속 열리는 문제를 어떻게 줄이겠습니까?
답변 예시 보기
진단과 접근
링크 목적지와 운영 상태를 분리해 관리하는 편이 좋습니다. 매핑은 긴 TTL로 캐시하더라도 만료·차단 상태는 짧은 TTL 또는 변경 이벤트로 빠르게 갱신합니다.
설계와 운영
- 차단 변경 시 linkId와 정책 version을 담은 무효화 이벤트를 각 서버와 CDN에 전파합니다.
- 리다이렉트 시 최신 차단 목록 또는 짧은 정책 캐시를 확인해 오래된 목적지 캐시만으로 열리지 않게 합니다.
- 전파 실패를 대비해 주기적으로 정책 버전을 비교하고 차단 반영 시간과 실패 노드를 관측합니다.
모든 캐시를 즉시 완벽하게 지우기 어렵기 때문에 보안 차단은 별도 deny-list로 우선 적용하는 전략이 현실적입니다. 오탐 해제와 롤백 절차도 같은 수준으로 준비합니다.
멀티채널 알림 발송 서비스
상황
조건
규모와 시스템 구성
- 평균 초당 5천 건, 캠페인 시 5만 건
- 문자·이메일·앱 푸시 3개 채널
- 발송 결과 30일 보관
현재 문제와 제약
- Coupling외부 장애가 업무 API에 전파
- Duplicate재시도 중 중복 발송
- Priority긴급·일반 알림 경쟁
꼬리 질문
알림 요청을 받은 시점부터 외부 공급자에게 발송할 때까지의 비동기 흐름과 주요 컴포넌트를 설명해 주세요.
답변 예시 보기
진단과 접근
업무 API가 외부 공급자를 직접 호출하면 공급자 지연이 주문 처리에 전파됩니다. 요청 접수와 실제 발송을 분리하고, 접수 성공 이후에는 notificationId로 상태를 추적하는 비동기 구조가 적합합니다.
설계와 운영
- 업무 서비스는 알림 요청을 DB나 메시지 큐에 안전하게 기록하고 즉시 접수 결과를 반환합니다.
- 채널별 worker가 템플릿과 수신 동의를 검증한 뒤 공급자 adapter를 호출합니다.
- 상태는 ACCEPTED, SENDING, SENT, FAILED로 저장하고 지연 시간·실패율·큐 적체를 관측합니다.
큐에 넣었다는 것은 사용자에게 전달됐다는 의미가 아닙니다. API 계약에서 접수 성공과 최종 발송 성공을 구분하고, 필요한 업무에는 webhook이나 조회 API를 제공합니다.
외부 문자 공급자가 타임아웃을 반환했지만 실제 발송 여부를 알 수 없을 때 재시도 정책을 어떻게 정하겠습니까?
답변 예시 보기
진단과 접근
타임아웃은 실패가 아니라 결과를 모르는 상태입니다. 무조건 재시도하면 중복 문자가 발생할 수 있으므로 공급자의 idempotency key나 발송 결과 조회 기능을 먼저 확인해야 합니다.
설계와 운영
- notificationId를 공급자 요청 키로 전달하고 동일 키 재요청 시 중복 발송하지 않도록 합니다.
- 일시 오류만 지수 백오프로 제한 재시도하고 잘못된 번호 같은 영구 오류는 즉시 실패 처리합니다.
- 결과 불명 건은 별도 상태로 두고 공급자 조회 API나 운영 확인 후 재처리합니다.
OTP는 늦은 중복 발송의 피해가 커 재시도를 보수적으로 할 수 있고, 주문 안내는 누락보다 중복이 덜 치명적일 수 있습니다. 업무 종류별 정책을 나누는 것이 핵심입니다.
마케팅 캠페인이 몰려도 OTP와 보안 알림을 빠르게 보내기 위해 큐와 작업자를 어떻게 분리하겠습니까?
답변 예시 보기
진단과 접근
긴급 알림과 대량 캠페인이 같은 큐와 worker를 사용하면 선착순 처리 때문에 OTP가 늦어집니다. 중요도별 처리 자원을 논리적 또는 물리적으로 분리해야 합니다.
설계와 운영
- 긴급·업무·마케팅 topic을 나누고 각각 독립 consumer 수와 rate limit을 둡니다.
- 공급자 한도 중 일부를 긴급 알림용으로 예약하고 캠페인은 큐 지연이 커지면 자동 감속합니다.
- 등급별 oldest message age와 발송 SLO를 관측하고 긴급 큐 적체 시 캠페인을 일시 중단합니다.
우선순위 큐 하나로도 시작할 수 있지만 대규모 캠페인이 메모리나 연결을 점유할 수 있습니다. 장애 격리가 중요해지면 worker pool과 공급자 계정까지 분리합니다.
고객 상담 실시간 채팅
상황
조건
규모와 시스템 구성
- 동시 연결 10만, 초당 메시지 2만 건
- 대화 이력 1년 보관
- 상담원 한 명당 최대 10개 대화
현재 문제와 제약
- Reconnect재접속 시 누락·중복
- Status전송·수신·읽음 의미 혼재
- History대화 이력 조회 지연
꼬리 질문
WebSocket 연결 서버와 메시지 저장 서버의 역할을 어떻게 나누고, 연결된 사용자를 어떻게 찾아 메시지를 전달하겠습니까?
답변 예시 보기
진단과 접근
연결 서버는 WebSocket과 heartbeat를 관리하고 메시지 서버는 대화 이력을 영속화해야 합니다. 연결 서버 메모리에만 메시지를 두면 재시작 시 유실되므로 저장 후 전달하는 흐름이 필요합니다.
설계와 운영
- 접속 시 userId-deviceId와 gatewayId를 TTL이 있는 연결 레지스트리에 등록합니다.
- 메시지는 conversationId 기준 로그에 저장한 뒤 상대 사용자의 현재 gateway로 전달합니다.
- gateway 전송 실패 시 메시지는 저장소에 남겨 두고 상대가 재접속할 때 마지막 수신 순번 이후를 조회합니다.
연결 레지스트리는 잠시 오래된 값을 가질 수 있으므로 정확한 원장으로 보지 않습니다. 잘못된 gateway 전송이 실패해도 메시지 저장과 재동기화로 복구되는 구조가 중요합니다.
메시지 ID와 순번을 어떻게 사용해 재접속 시 빠진 메시지만 다시 받고 중복을 화면에서 제거하겠습니까?
답변 예시 보기
진단과 접근
각 메시지에 서버가 확정한 messageId와 대화방 순번을 부여하고 클라이언트가 마지막으로 받은 순번을 저장하면 누락 구간을 계산할 수 있습니다.
설계와 운영
- 클라이언트는 임시 ID로 보낸 뒤 서버 ACK에서 확정 ID와 순번을 받아 화면 상태를 바꿉니다.
- 재접속 시 lastSequence를 보내고 서버는 그 이후 메시지만 페이지로 반환합니다.
- 같은 messageId가 재전달되면 클라이언트와 서버 소비 이력이 중복 삽입을 무시합니다.
클라이언트 시각은 기기마다 다르므로 정렬 기준으로 사용하지 않는 편이 안전합니다. 전역 순서보다 대화방 안에서 납득 가능한 순서를 보장한다고 범위를 좁힙니다.
서버 장애나 느린 상담원 때문에 전달이 늦어질 때 어떤 상태를 사용자에게 보여주고 어떤 지표를 관찰하겠습니까?
답변 예시 보기
진단과 접근
전송 성공, 서버 저장, 단말 수신, 사용자 읽음은 서로 다른 상태입니다. 한 가지 체크 표시로 모두 표현하면 장애 때 잘못된 기대를 만들 수 있습니다.
설계와 운영
- 서버 저장 ACK 전에는 전송 중, 저장 후에는 전송됨, 상대 단말 ACK 후에는 수신됨으로 구분합니다.
- 느린 상담원은 읽음 cursor만 늦어질 뿐 메시지 전달 큐 전체를 막지 않도록 사용자별 상태를 분리합니다.
- gateway 연결 수, 메시지 저장 지연, 전달 지연, 재접속률, 미확인 메시지 age를 관측합니다.
모든 상태를 영구 보존하면 쓰기가 크게 늘 수 있으므로 읽음은 메시지별 boolean보다 대화방 cursor로 관리할 수 있습니다. 제품이 실제로 필요한 상태만 저장합니다.
대용량 파일 업로드 서비스
상황
조건
규모와 시스템 구성
- 하루 50만 파일, 평균 100MB
- Object Storage와 PostgreSQL 사용
- 악성코드 검사 후 다운로드 허용
현재 문제와 제약
- Large FileAPI 서버 자원 고갈
- Resume중단 후 전체 재전송
- Partial메타데이터와 파일 상태 불일치
꼬리 질문
파일을 여러 조각으로 나누어 직접 Object Storage에 올리는 업로드 흐름과 API를 설계해 주세요.
답변 예시 보기
진단과 접근
API 서버가 파일 바이트를 중계하지 않고 업로드 세션만 관리하며 클라이언트가 Object Storage에 직접 조각을 올리도록 구성하면 서버 자원 사용을 줄일 수 있습니다.
설계와 운영
- 서버가 uploadId, chunk 크기, 만료 시각과 pre-signed URL 목록을 발급합니다.
- 클라이언트는 완료된 chunk 번호와 checksum을 저장하고 재접속 시 빠진 조각만 전송합니다.
- 모든 조각 업로드 후 complete API가 manifest를 검증하고 파일 상태를 UPLOADED로 전환합니다.
조각이 너무 작으면 요청 수와 메타데이터가 늘고 너무 크면 재전송 비용이 커집니다. 평균 네트워크와 파일 크기를 기준으로 정하고 동시 업로드 수를 제한합니다.
모든 조각이 올라간 뒤 파일 완료를 확정할 때 누락·중복 조각과 잘못된 파일을 어떻게 검증하겠습니까?
답변 예시 보기
진단과 접근
완료 요청은 클라이언트의 주장만 믿지 않고 서버가 Object Storage의 조각 목록과 크기, checksum을 확인해야 합니다.
설계와 운영
- chunkNumber와 ETag/checksum을 manifest에 기록하고 누락·중복 번호를 검사합니다.
- complete API는 uploadId 기준 멱등하게 만들어 재호출 시 이미 생성된 fileId를 반환합니다.
- 파일 전체 hash나 예상 크기를 비교한 뒤 바이러스 검사 상태로 넘기고, 검사 완료 전에는 다운로드를 막습니다.
전체 파일 hash 계산은 큰 파일에서 비용이 있으므로 조각 checksum과 최종 manifest를 조합할 수 있습니다. 무결성 수준은 계약서와 일반 미디어처럼 파일 중요도에 따라 정합니다.
파일은 저장됐지만 DB 저장에 실패하거나 반대 상황이 생겼을 때 어떤 상태와 정리 작업으로 복구하겠습니까?
답변 예시 보기
진단과 접근
파일 저장과 DB 메타데이터 저장은 하나의 트랜잭션이 아니므로 중간 상태를 인정하고 복구 가능하게 만드는 것이 현실적입니다.
설계와 운영
- 메타데이터를 UPLOADING으로 먼저 만들고 임시 경로에 파일을 올린 뒤 검증 성공 시 READY로 전환합니다.
- DB 확정 실패로 남은 임시 객체는 uploadId와 생성 시각을 기준으로 정리 작업이 삭제합니다.
- DB에는 READY인데 객체가 없는 경우를 대사 작업이 탐지해 ERROR로 전환하고 운영 알림을 보냅니다.
즉시 삭제하면 늦게 도착한 완료 요청과 충돌할 수 있으므로 유예 기간 후 정리합니다. orphan 수, UPLOADING age, 검증 실패율을 운영 지표로 둡니다.
팔로우 기반 최신 게시물 피드
상황
조건
규모와 시스템 구성
- DAU 300만, 하루 게시물 500만 건
- 일반 사용자는 평균 200명 팔로우
- 첫 화면 20개, 커서 기반 다음 페이지
현재 문제와 제약
- Fan-out인기 작성자의 쓰기 폭증
- Paging중복 없는 다음 페이지
- Delete삭제·차단 반영
꼬리 질문
글을 쓸 때 팔로워 피드에 미리 넣는 방식과 읽을 때 모으는 방식의 장단점을 비교하고 이 서비스에 맞는 방식을 선택해 주세요.
답변 예시 보기
진단과 접근
일반 사용자는 글 작성 시 팔로워 timeline에 미리 넣으면 읽기가 빠릅니다. 그러나 팔로워 100만 명인 작성자는 한 게시물마다 100만 번 쓰기가 발생하므로 동일 전략이 적합하지 않습니다.
설계와 운영
- 일반 작성자는 fan-out on write로 follower timeline을 비동기 갱신합니다.
- 인기 작성자는 author timeline에만 저장하고 사용자가 읽을 때 다른 피드와 합칩니다.
- 팔로워 수와 활성 사용자 비율, 게시 빈도를 기준으로 두 방식을 전환하고 피드 생성 지연을 관측합니다.
초기 규모가 작다면 읽을 때 모으는 단순 구현으로 시작할 수 있습니다. 읽기 빈도가 늘면 사전 계산을 추가하되 유명인 예외를 둔 hybrid가 현실적입니다.
새 글이 추가되는 중에도 중복이나 누락을 줄이는 커서 페이지네이션을 어떻게 구성하겠습니까?
답변 예시 보기
진단과 접근
offset 페이지는 앞에 새 글이 추가되면 같은 글이 다시 보이거나 일부가 건너뛰어질 수 있습니다. 마지막으로 본 정렬 키를 기준으로 다음 페이지를 조회하는 cursor 방식이 적합합니다.
설계와 운영
- createdAt과 postId를 함께 정렬 키로 사용해 같은 시각의 글도 안정적으로 순서를 정합니다.
- 다음 요청은 마지막 (createdAt, postId)보다 오래된 항목을 조회합니다.
- 첫 페이지 조회 시점을 cursor에 포함하면 페이지 이동 중 새 글을 별도로 표시할 수 있습니다.
개인화 순위처럼 점수가 자주 바뀌면 cursor 안정성이 더 어려워집니다. 이 중급 사례에서는 시간순이라는 요구를 활용해 계약을 단순화합니다.
이미 피드 캐시에 들어간 글이 삭제되거나 작성자가 차단됐을 때 어떤 단계에서 필터링하고 정리하겠습니까?
답변 예시 보기
진단과 접근
모든 timeline에서 삭제된 글을 즉시 찾아 제거하면 쓰기 비용이 큽니다. 조회할 때 원본 글 상태와 차단 목록을 최종 확인하고 비동기로 캐시를 정리하는 조합이 안전합니다.
설계와 운영
- 게시물 삭제 시 tombstone 또는 deleted 상태를 먼저 기록해 원본 조회가 내용을 반환하지 않게 합니다.
- 삭제 이벤트로 timeline 캐시와 검색 인덱스를 비동기 정리합니다.
- 차단 목록은 사용자별 짧은 캐시로 조회 경로에서 필터링하고 변경 시 무효화합니다.
조회 시 필터는 정확하지만 비용이 들고 비동기 정리는 빠르지만 지연될 수 있습니다. 둘을 함께 사용하고 삭제 반영 시간과 필터 누락을 측정합니다.
주문 모놀리스의 MSA 분리
상황
조건
규모와 시스템 구성
- 일 주문 100만 건, 피크 초당 500건
- Java 모놀리스와 MySQL 공유 DB
- 주문·결제팀과 배송팀이 별도 조직
현재 문제와 제약
- Boundary서비스 경계 불명확
- Shared DB여러 서비스의 직접 수정
- Migration한 번에 전환하기 어려움
꼬리 질문
배송 서비스를 어떤 기준으로 분리하고 주문 서비스와 어떤 데이터·API 계약을 맺겠습니까? 테이블 기준 분리의 문제도 설명해 주세요.
답변 예시 보기
진단과 접근
서비스 경계는 테이블 개수보다 업무 책임과 변경 이유로 정해야 합니다. 배송은 운송장, 배송 상태, 택배사 연동을 소유하고 주문은 구매 계약과 주문 상태를 소유하도록 구분할 수 있습니다.
설계와 운영
- 주문이 배송 생성을 요청할 때 orderId, 배송지 snapshot, 상품 정보를 명시적 API나 이벤트 계약으로 전달합니다.
- 배송 서비스가 주문 테이블을 직접 수정하지 않고 배송 상태 변경 이벤트를 발행합니다.
- 계약 version과 소유 팀을 문서화하고 consumer contract test로 변경 영향을 확인합니다.
너무 잘게 나누면 호출과 운영 복잡도가 늘고 너무 크게 두면 독립 배포의 이점이 줄어듭니다. 함께 변경되는 업무와 팀 책임을 기준으로 시작해 실제 변경 패턴으로 조정합니다.
초기에는 배송 서비스가 기존 주문 DB를 읽어야 한다면 어떤 임시 단계를 거쳐 데이터 소유권을 옮기겠습니까?
답변 예시 보기
진단과 접근
초기 공유 DB 접근은 전환을 위한 임시 단계로 사용할 수 있지만 읽기 전용과 종료 시점을 명확히 해야 합니다. 신규 서비스가 계속 기존 테이블을 직접 쓰면 데이터 소유권은 바뀌지 않습니다.
설계와 운영
- 1단계에서 배송 서비스는 adapter를 통해 기존 조회만 수행하고 모든 신규 배송 코드는 한 경로로 모읍니다.
- 2단계에서 CDC나 이벤트로 배송 DB에 필요한 read model을 만들고 shadow 비교로 누락을 확인합니다.
- 3단계에서 배송 쓰기를 신규 DB로 전환하고 기존 테이블에는 호환용 결과만 동기화한 뒤 의존을 제거합니다.
이중 쓰기는 한쪽만 성공할 수 있으므로 오래 유지하지 않습니다. 각 단계마다 단일 writer를 정하고 데이터 건수·상태별 대사와 rollback 조건을 둡니다.
기존 경로와 신규 배송 서비스를 함께 운영하면서 트래픽을 점진적으로 전환하고 문제가 생기면 어떻게 되돌리겠습니까?
답변 예시 보기
진단과 접근
Gateway 또는 기존 모놀리스 내부 라우터에서 사용자나 주문 ID를 기준으로 안정적으로 신규 경로를 선택하면 같은 요청이 경로를 오가는 문제를 줄일 수 있습니다.
설계와 운영
- 사내 사용자와 테스트 주문부터 시작해 1%, 5%, 20% 순으로 확대합니다.
- 구·신 경로 응답과 상태 변화를 shadow 비교하고 오류율, 지연, 배송 생성 성공률을 확인합니다.
- 신규 경로를 끄는 feature flag와 DB 호환성을 유지해 수 분 안에 기존 경로로 돌아갈 수 있게 합니다.
쓰기 요청을 구·신 시스템에 동시에 실행하면 중복 배송이 생길 수 있으므로 shadow는 읽기 또는 부작용 없는 검증에만 사용합니다. 단일 writer 원칙을 유지합니다.
MSA 동기 호출 연쇄 장애
상황
조건
규모와 시스템 구성
- 상품 조회 초당 1만 건
- 내부 서비스 호출 4~7회
- 응답 목표 p95 300ms
현재 문제와 제약
- Cascade느린 호출이 전체 장애로 확대
- Timeout서비스마다 제각각인 제한 시간
- Tracing요청 흐름 추적 어려움
꼬리 질문
전체 응답 시간 300ms 안에서 각 내부 호출의 timeout을 어떻게 정하고 필수·선택 데이터를 어떻게 구분하겠습니까?
답변 예시 보기
진단과 접근
전체 300ms를 각 호출에 그대로 주면 마지막 단계에서 시간 예산이 사라집니다. 호출의 중요도와 예상 지연을 기준으로 전체 deadline을 나누고 선택 기능은 더 짧게 제한합니다.
설계와 운영
- 상품·가격·재고를 필수 데이터로, 추천을 선택 데이터로 분류합니다.
- 병렬 호출 가능한 서비스는 동시에 요청하고 전체 deadline의 남은 시간을 downstream에 전달합니다.
- 서비스별 p95와 오류율을 보고 timeout을 조정하며 timeout 횟수와 전체 응답 시간의 관계를 관측합니다.
timeout이 너무 짧으면 정상 요청도 실패하고 너무 길면 스레드가 고갈됩니다. 평균값이 아니라 tail latency와 사용자 허용 시간을 기준으로 설정합니다.
추천 서비스 장애 시 timeout, circuit breaker, fallback을 어떤 순서로 적용하고 사용자에게 어떤 결과를 보여주겠습니까?
답변 예시 보기
진단과 접근
추천은 선택 데이터이므로 장애 시 핵심 상품 조회를 실패시키지 않는 것이 우선입니다. 짧은 timeout 후 circuit breaker가 열리면 즉시 fallback을 반환합니다.
설계와 운영
- 일정 실패율 이상이면 회로를 열고 추천 호출을 잠시 중단해 느린 서비스와 호출자의 자원을 함께 보호합니다.
- fallback은 빈 추천, 최근 인기 상품, 캐시된 결과 중 제품 요구에 맞게 선택합니다.
- half-open 상태에서 소량 요청으로 복구를 확인하고 자동으로 정상 호출을 재개합니다.
모든 오류에 동일 정책을 적용하지 않습니다. 잘못된 인증처럼 재시도로 회복되지 않는 오류는 즉시 실패시키고 일시 장애만 제한적으로 재시도합니다.
분산 로그, metric, trace에 어떤 공통 식별자와 정보를 남겨 연쇄 장애의 시작점을 찾겠습니까?
답변 예시 보기
진단과 접근
한 요청에 공통 traceId를 부여하고 서비스가 다른 서비스를 호출할 때 전달해야 전체 흐름을 연결할 수 있습니다. 로그, metric, trace가 같은 서비스명과 오류 분류를 사용해야 분석이 쉬워집니다.
설계와 운영
- 각 span에 서비스명, API, 소요 시간, 상태 코드, timeout 여부와 downstream 이름을 기록합니다.
- 개인정보나 전체 요청 본문은 남기지 않고 orderId 같은 업무 키도 정책에 맞게 마스킹합니다.
- 전체 p95뿐 아니라 downstream별 지연, circuit 상태, timeout 비율을 대시보드로 묶습니다.
모든 요청을 100% 상세 추적하면 비용이 크므로 오류 요청과 느린 요청을 우선 보존하고 정상 요청은 샘플링할 수 있습니다.
레거시 주문 조회 API 분리
상황
조건
규모와 시스템 구성
- 주문 이력 5년, 30억 행
- Oracle 기반 모놀리스
- 조회 API p95 3초 → 목표 500ms
현재 문제와 제약
- Contract기존 응답 형식 유지
- Read Load운영 DB 조회 부하
- Rollback신규 경로 장애 시 복귀
꼬리 질문
API Gateway나 BFF를 이용해 기존 클라이언트 요청을 신규 조회 서버로 점진 전환하는 방법을 설명해 주세요.
답변 예시 보기
진단과 접근
클라이언트 계약은 유지하고 Gateway가 같은 URL을 구·신 서버 중 하나로 라우팅하게 하면 앱 변경 없이 전환할 수 있습니다. 사용자 ID 해시로 경로를 고정하면 비교와 문제 재현이 쉽습니다.
설계와 운영
- 사내 계정부터 신규 서버로 보내고 오류율과 p95를 확인한 뒤 비율을 단계적으로 높입니다.
- 신규 서버 장애 시 route weight를 0으로 만드는 빠른 rollback 절차를 준비합니다.
- 인증, rate limit은 Gateway 공통 정책으로 두고 복잡한 업무 변환은 신규 서비스 adapter가 담당합니다.
무작위 요청 단위 분배는 한 사용자가 매번 다른 결과를 볼 수 있습니다. sticky routing을 사용하고 전환 비율별 관찰 시간을 정합니다.
신규 서버의 응답을 기존 앱 형식으로 맞출 때 누락 필드, null 값, 오류 코드 차이를 어떻게 검증하겠습니까?
답변 예시 보기
진단과 접근
기존 응답을 계약으로 보고 실제 사례를 모아 contract test를 만드는 것이 먼저입니다. 필드명만 아니라 null, 빈 배열, 날짜 형식, 오류 코드처럼 클라이언트가 의존하는 세부 동작도 비교해야 합니다.
설계와 운영
- 운영 응답을 익명화해 정상·취소·부분배송 등 golden dataset을 만듭니다.
- 신규 내부 모델은 anti-corruption adapter가 기존 응답 DTO로 변환합니다.
- shadow 요청으로 구·신 응답의 의미 있는 필드를 비교하고 차이를 배포 전에 분류합니다.
잘못된 기존 동작도 클라이언트가 의존하면 바로 고치기 어렵습니다. 외부 계약은 유지하고 내부에서 개선한 뒤 별도 API version으로 정리하는 방법이 안전합니다.
신규 조회 DB를 만든다면 원본 Oracle과 어떤 방식으로 동기화하고 데이터가 늦거나 누락되는 문제를 어떻게 찾겠습니까?
답변 예시 보기
진단과 접근
Oracle 변경을 읽기 모델로 전달하려면 애플리케이션 이벤트 또는 CDC를 사용할 수 있습니다. Stored Procedure가 직접 테이블을 바꾸는 환경에서는 DB 로그 기반 CDC가 변경을 놓칠 가능성이 낮습니다.
설계와 운영
- 기준 시점 snapshot을 적재하고 같은 SCN 이후 변경 이벤트를 이어 적용합니다.
- orderId와 변경 version으로 멱등 upsert하고 실패 이벤트는 DLQ에 보관합니다.
- 건수, 최종 수정 시각, 상태별 합계를 주기적으로 비교하고 특정 주문을 재구축하는 도구를 둡니다.
조회 데이터는 수 초 늦을 수 있다는 제품 합의가 필요합니다. 배송지 변경 직후처럼 최신성이 중요한 화면은 원본 확인 또는 사용자 안내를 추가합니다.
레거시 야간 배치 현대화
상황
조건
규모와 시스템 구성
- 일 거래 2천만 건
- 배치 단계 35개
- 완료 목표 오전 7시
현재 문제와 제약
- Restart실패 시 전체 재실행
- Visibility단계별 상태 확인 불가
- Rewrite업무 규칙 누락 위험
꼬리 질문
현재 배치의 단계와 데이터 의존성을 어떻게 파악하고, 무엇부터 분리할지 우선순위를 정하겠습니까?
답변 예시 보기
진단과 접근
코드를 옮기기 전에 현재 실행 순서와 데이터 의존성을 관찰해야 합니다. 작업 로그, 프로시저 호출, 입출력 테이블을 수집해 DAG로 정리하고 실패 영향과 실행 시간을 기준으로 우선순위를 정합니다.
설계와 운영
- 읽기 전용 집계나 독립적인 파일 생성처럼 부작용이 적은 단계부터 분리합니다.
- 각 단계의 입력 기준일, 출력 테이블, 선행 작업, 재실행 가능 여부와 소유 팀을 문서화합니다.
- 가장 느린 단계만 먼저 병렬화하기보다 정산 정확성과 검증 가능성을 함께 고려합니다.
한 번에 전체를 재작성하면 숨은 규칙을 놓칠 가능성이 큽니다. wrapper로 관측성을 먼저 만들고 작은 단계부터 교체하는 접근이 안전합니다.
각 단계를 재시작 가능하게 만들기 위해 작업 상태, 체크포인트, 멱등성을 어떻게 적용하겠습니까?
답변 예시 보기
진단과 접근
작업 실행을 STARTED, SUCCEEDED, FAILED 상태로 기록하고 businessDate와 stepName을 멱등키로 사용하면 실패 단계부터 다시 시작할 수 있습니다.
설계와 운영
- 단계 시작 전 이미 SUCCEEDED인지 확인하고 성공 결과가 있으면 건너뜁니다.
- 대량 처리는 일정 구간마다 checkpoint를 저장해 마지막 완료 구간 이후부터 재개합니다.
- 중간 결과는 임시 테이블에 쓰고 완료 후 교체해 부분 결과가 다음 단계에 노출되지 않게 합니다.
멱등하게 만들기 어려운 외부 송금 같은 단계는 요청 키와 결과 조회를 사용하거나 운영 승인 후 재실행하도록 별도 처리합니다.
Stored Procedure를 Java 코드로 옮길 때 기존 결과와 신규 결과가 같은지 어떤 데이터와 절차로 비교하겠습니까?
답변 예시 보기
진단과 접근
기존 결과를 사실상 기준 동작으로 보고 동일 입력에 대한 결과를 비교하는 characterization test가 필요합니다. 대표 사례만으로는 부족하므로 실제 기간 데이터를 사용해 경계 조건을 포함합니다.
설계와 운영
- 기존 프로시저와 신규 코드를 같은 snapshot 입력에 실행하고 건수·금액·상태별 결과를 비교합니다.
- 순서나 생성 시각처럼 의미 없는 차이는 정규화하고 금액 불일치는 0원이어야 하는지 허용 범위를 합의합니다.
- 일정 기간 shadow 실행 후 차이 원인을 모두 분류하고 feature flag로 일부 업무부터 전환합니다.
새 구현이 더 합리적으로 보여도 기존 정산 계약과 다르면 장애가 될 수 있습니다. 의도된 변경은 별도 요구사항으로 승인받고 migration과 리팩터링을 분리합니다.
Kafka 기반 주문 이벤트 처리
상황
조건
규모와 시스템 구성
- 일 주문 이벤트 1천만 건
- Kafka topic partition 24개
- 결제·배송·알림 3개 consumer group
현재 문제와 제약
- Publish GapDB 커밋과 발행 사이 유실
- Duplicate재전달로 중복 처리
- Ordering같은 주문의 상태 순서
꼬리 질문
주문 DB 저장과 Kafka 이벤트 발행 사이의 유실을 막기 위해 Transactional Outbox를 어떻게 적용하겠습니까?
답변 예시 보기
진단과 접근
주문 데이터 저장과 이벤트 발행을 별도 작업으로 하면 둘 사이에 프로세스가 종료되는 실패 구간이 생깁니다. 주문 변경과 outbox 행 삽입을 같은 DB 트랜잭션으로 커밋해야 합니다.
설계와 운영
- outbox에는 eventId, orderId, eventType, payload, 생성 시각을 저장합니다.
- 별도 relay나 CDC가 미발행 행을 Kafka로 보내고 성공 후 상태를 갱신합니다.
- 발행 지연, 오래된 outbox, 실패 횟수를 관측하고 재처리 도구를 제공합니다.
relay가 Kafka 발행 후 상태 갱신 전에 종료되면 같은 이벤트가 다시 발행될 수 있습니다. Outbox는 유실을 줄이지만 중복은 남으므로 소비자 멱등성이 함께 필요합니다.
같은 주문 이벤트가 두 번 전달됐을 때 배송 생성이나 알림 발송이 중복되지 않도록 소비자를 어떻게 만들겠습니까?
답변 예시 보기
진단과 접근
Kafka는 기본적으로 재전달이 가능하다고 가정하고 소비 업무 자체를 멱등하게 만들어야 합니다. eventId 또는 업무 키를 소비 이력과 함께 저장합니다.
설계와 운영
- 배송 DB에 eventId unique constraint를 두고 배송 생성과 처리 이력 저장을 한 로컬 트랜잭션으로 수행합니다.
- 이미 처리한 eventId가 오면 성공으로 간주하고 offset을 진행합니다.
- 알림처럼 외부 부작용은 notificationId를 idempotency key로 전달하거나 발송 상태를 먼저 기록합니다.
처리 후 offset commit 전에 장애 나면 재전달되므로 offset만으로 중복을 막을 수 없습니다. dedup 이력 보존 기간과 데이터 크기도 운영 정책으로 정합니다.
같은 주문의 이벤트 순서를 유지하기 위한 partition key를 무엇으로 선택하고, 그 선택이 처리량에 주는 영향을 설명해 주세요.
답변 예시 보기
진단과 접근
같은 주문의 상태 순서가 중요하므로 orderId를 partition key로 선택하면 해당 주문 이벤트는 같은 partition에 들어가 순서를 유지할 수 있습니다.
설계와 운영
- producer는 주문 상태가 확정된 뒤 동일 orderId로 이벤트를 발행합니다.
- consumer는 이전 상태와 허용된 상태 전이를 확인해 오래된 이벤트가 상태를 되돌리지 않게 합니다.
- partition별 처리량과 lag를 보고 일부 주문이나 판매자에 트래픽이 치우치는지 확인합니다.
모든 이벤트를 한 partition에 넣으면 순서는 강하지만 처리량이 제한됩니다. 필요한 순서 범위를 주문 단위로 좁혀 partition 간 병렬성을 확보합니다.
Kafka Consumer Lag 장애 대응
상황
조건
규모와 시스템 구성
- 평균 초당 3만, 행사 시 20만 이벤트
- partition 12개, consumer 12개
- 검색 반영 목표 1분 이내
현재 문제와 제약
- Lag행사 후 적체 장기화
- Partition특정 파티션 편중
- Downstream검색 저장소 쓰기 제한
꼬리 질문
Consumer Lag이 늘었을 때 producer 증가, hot partition, 느린 처리, downstream 장애를 어떤 지표로 구분하겠습니까?
답변 예시 보기
진단과 접근
Lag 숫자 하나만으로 원인을 알 수 없습니다. 유입량, partition별 lag, 처리 시간, consumer 오류와 downstream 지연을 같은 시간축으로 비교해야 합니다.
설계와 운영
- producer rate가 처리 rate보다 큰지 확인해 단순 용량 부족을 구분합니다.
- 특정 partition만 lag가 크면 key 편향이나 대형 메시지를 조사합니다.
- 모든 partition이 느리고 검색 저장소 latency가 증가했다면 downstream 병목과 retry를 확인합니다.
offset 차이뿐 아니라 가장 오래된 미처리 이벤트의 age를 봐야 사용자 영향 시간을 알 수 있습니다. 처리율로 적체 해소 예상 시간도 계산합니다.
consumer 수를 partition 수보다 늘려도 효과가 없는 이유와 partition을 늘릴 때 고려할 점을 설명해 주세요.
답변 예시 보기
진단과 접근
consumer group에서 한 partition은 동시에 한 consumer만 처리하므로 consumer 수가 partition 수를 넘으면 추가 consumer는 유휴 상태가 됩니다.
설계와 운영
- 병렬성을 늘리려면 partition 수를 늘리고 consumer를 함께 확장해야 합니다.
- partition 증설 후 같은 key의 신규 이벤트가 다른 partition으로 갈 수 있는지와 순서 영향도 확인합니다.
- 증설 과정의 rebalance 시간, 처리 중단, broker 디스크와 네트워크 부하를 관측합니다.
partition은 줄이기 어렵고 너무 많으면 broker와 rebalance 비용이 커집니다. 단기 장애라면 batch 처리 최적화나 downstream 확장이 증설보다 적절할 수 있습니다.
품절 이벤트를 일반 상품 설명 변경보다 먼저 반영하려면 topic·우선순위·별도 처리 경로를 어떻게 구성하겠습니까?
답변 예시 보기
진단과 접근
업무 중요도가 다른 이벤트를 같은 partition에서 완전한 우선순위로 처리하기는 어렵습니다. 품절과 일반 변경을 별도 topic 또는 처리 경로로 나누는 방식이 명확합니다.
설계와 운영
- 재고·품절 이벤트는 high-priority topic과 전용 consumer group으로 처리합니다.
- 일반 설명 변경은 별도 topic에서 처리하고 검색 저장소 쓰기 quota도 분리합니다.
- 동일 상품의 최종 상태는 version을 비교해 늦게 도착한 일반 이벤트가 최신 재고를 덮지 않게 합니다.
topic을 지나치게 많이 나누면 운영이 복잡해집니다. SLO와 장애 격리가 실제로 다른 업무만 분리하고 나머지는 batch 크기 조절로 대응합니다.
공연 좌석 임시 예약 서비스
상황
조건
규모와 시스템 구성
- 공연당 좌석 5만 개
- 오픈 시 동시 사용자 30만 명
- 예약 TTL 5분
현재 문제와 제약
- Race동일 좌석 동시 선택
- Expiry만료와 결제의 경쟁
- Recovery만료 작업 실패
꼬리 질문
좌석 상태를 AVAILABLE, RESERVED, SOLD로 관리할 때 허용할 상태 전이와 조건을 정의해 주세요.
답변 예시 보기
진단과 접근
상태 전이는 AVAILABLE→RESERVED→SOLD 또는 RESERVED→EXPIRED만 허용해야 합니다. 각 변경은 현재 상태와 reservationId를 조건으로 수행해 오래된 요청이 최신 상태를 덮지 않게 합니다.
설계와 운영
- 예약에는 userId, reservationId, expiresAt을 저장합니다.
- 결제 완료는 동일 reservationId의 RESERVED 상태에서만 SOLD로 전환합니다.
- 만료는 RESERVED이며 expiresAt이 지났을 때만 EXPIRED 또는 AVAILABLE로 전환합니다.
상태를 단순 boolean 두 개로 관리하면 모순된 조합이 생기기 쉽습니다. 명시적 상태 머신과 전이 로그가 장애 분석과 보상에 유리합니다.
DB 조건부 갱신이나 Redis 원자 연산을 이용해 동일 좌석의 중복 예약을 막는 흐름을 설명해 주세요.
답변 예시 보기
진단과 접근
DB에서는 좌석 행을 조건부 갱신해 영향 행 수로 성공 여부를 판단할 수 있습니다. Redis에서는 Lua Script가 상태 확인과 예약 기록을 한 번에 수행해야 합니다.
설계와 운영
- DB 방식은 UPDATE seat SET status=RESERVED... WHERE id=? AND status=AVAILABLE처럼 처리합니다.
- Redis 방식은 seat key에 reservationId와 TTL을 원자적으로 넣고 이미 값이 있으면 실패합니다.
- 어느 방식이든 user 요청 idempotency key로 네트워크 재시도가 새 예약을 만들지 않게 합니다.
DB 방식은 단순하고 최종 데이터와 가깝지만 인기 공연에서 write 경쟁이 큽니다. Redis는 빠르지만 DB 확정과 장애 복구가 필요하므로 부하 테스트와 운영 역량을 근거로 선택합니다.
예약 만료 작업이 늦거나 두 번 실행되어도 결제 완료 좌석을 보호하려면 어떤 정보와 검증이 필요합니까?
답변 예시 보기
진단과 접근
만료 작업은 reservationId와 현재 상태를 다시 확인해야 합니다. 단순히 시간이 됐다는 이유로 좌석을 AVAILABLE로 바꾸면 이미 완료된 결제를 되돌릴 수 있습니다.
설계와 운영
- 만료 명령에 reservationId를 담고 해당 예약이 여전히 RESERVED인지 확인합니다.
- 결제가 먼저 SOLD로 바뀌었다면 만료 작업은 아무것도 하지 않고 성공 처리합니다.
- 지연 큐 메시지 유실에 대비해 expiresAt이 오래 지난 RESERVED를 찾는 보정 배치를 둡니다.
만료와 결제 완료가 동시에 실행돼도 DB 조건부 갱신 중 하나만 성공하게 만들고 실패한 쪽은 최신 상태를 다시 읽어 업무 결과를 결정합니다.
상품 검색과 색인 동기화
상황
조건
규모와 시스템 구성
- 상품 5천만 개, 초당 검색 2만 건
- 상품 변경 초당 최대 5천 건
- 검색 응답 목표 300ms
현재 문제와 제약
- SyncDB와 색인 불일치
- Freshness가격·재고 지연
- Reindex전체 재색인 부담
꼬리 질문
상품 DB 변경을 검색 인덱스로 전달하는 이벤트 흐름과 실패 재처리 방법을 설계해 주세요.
답변 예시 보기
진단과 접근
상품 DB를 기준 원장으로 두고 변경 이벤트를 검색 인덱스에 비동기로 반영합니다. DB 커밋과 이벤트 발행 사이의 유실을 막기 위해 Outbox 또는 CDC가 적합합니다.
설계와 운영
- 이벤트에는 productId, 변경 version, 변경 필드를 포함하고 소비자는 versioned upsert를 수행합니다.
- 색인 실패는 제한 재시도 후 DLQ로 보내고 운영자가 원인 확인 후 다시 처리합니다.
- DB와 인덱스의 건수·수정 시각·표본 checksum을 주기적으로 비교하고 단건 재색인 API를 둡니다.
전체 상품 payload를 매번 보내면 단순하지만 트래픽이 크고 변경 필드만 보내면 순서와 누락 처리가 복잡합니다. 현재 변경량과 재구축 가능성을 기준으로 선택합니다.
색인된 가격·재고가 오래될 수 있다면 검색 결과와 상품 상세 조회에서 각각 어떤 검증을 하겠습니까?
답변 예시 보기
진단과 접근
검색 결과의 후보 ID와 자주 변하는 가격·재고를 분리해 생각하는 것이 좋습니다. 최종 구매 판단에 중요한 값은 상세 또는 응답 직전에 최신 저장소에서 확인합니다.
설계와 운영
- 검색 인덱스의 값에는 갱신 시각을 포함해 지나치게 오래된 상품을 식별합니다.
- 첫 화면의 상품 ID를 얻은 뒤 가격·재고 캐시를 batch 조회해 응답을 보정합니다.
- 주문 시에는 검색 결과를 신뢰하지 않고 주문 DB에서 가격 정책과 재고를 다시 검증합니다.
모든 검색 결과를 원본 DB에서 다시 읽으면 지연과 부하가 커집니다. 노출은 약간 오래될 수 있지만 결제는 정확해야 한다는 경계를 제품과 합의합니다.
검색 스키마 변경으로 전체 재색인이 필요할 때 서비스를 중단하지 않고 신규 인덱스로 전환하는 방법을 설명해 주세요.
답변 예시 보기
진단과 접근
기존 인덱스를 직접 변경하지 않고 새 스키마의 versioned index를 별도로 구축한 뒤 검증 후 alias를 바꾸는 방식이 안전합니다.
설계와 운영
- DB snapshot으로 신규 인덱스를 채우고 구축 중 발생한 변경 이벤트를 이어 반영합니다.
- 문서 수, 검색 결과 표본, 응답 지연을 구 인덱스와 비교합니다.
- alias를 신규 인덱스로 원자 전환하고 문제 시 구 인덱스로 되돌릴 수 있도록 일정 기간 보존합니다.
재색인 중 이중 쓰기는 실패 처리와 순서 관리가 필요합니다. CDC의 한 소비자가 구·신 인덱스에 적용하거나 version으로 오래된 갱신을 막습니다.
정기 리포트 작업 스케줄러
상황
조건
규모와 시스템 구성
- 월간 작업 50만 건
- worker 200대
- 작업 시간 1분~40분
현재 문제와 제약
- Duplicate같은 작업 이중 실행
- Long Run장기 작업 상태 확인
- Retry실패 작업 재시도 폭주
꼬리 질문
스케줄러가 실행할 작업을 만들고 여러 worker가 하나씩 가져가는 흐름과 작업 상태를 설계해 주세요.
답변 예시 보기
진단과 접근
스케줄러는 실행할 job을 만들고 worker는 queue 또는 DB claim을 통해 하나씩 가져갑니다. 상태는 PENDING, RUNNING, SUCCEEDED, FAILED로 관리하고 jobId를 전체 흐름의 식별자로 사용합니다.
설계와 운영
- 월간 대상 고객별로 businessMonth+customerId unique key를 사용해 job 중복 생성을 막습니다.
- worker는 조건부 갱신으로 PENDING을 RUNNING으로 바꾼 경우에만 실행합니다.
- 시작·종료·오류·재시도 횟수를 저장하고 고객별 진행률과 오래된 RUNNING 작업을 조회합니다.
스케줄러 하나에만 의존하기보다 중복 생성이 발생해도 DB unique constraint가 막도록 설계합니다. 실행 횟수와 업무 결과의 중복은 별도로 보호합니다.
worker가 중간에 종료됐는지 단지 오래 실행 중인지 heartbeat와 timeout을 이용해 어떻게 판단하겠습니까?
답변 예시 보기
진단과 접근
RUNNING 작업에 lease 만료 시각을 두고 worker가 주기적으로 heartbeat로 연장하면 종료된 worker의 작업을 다시 가져올 수 있습니다.
설계와 운영
- 작업별 예상 시간을 고려해 lease와 heartbeat 주기를 설정합니다.
- lease가 만료된 작업은 재시도 대기 상태로 옮기되 새 attempt 번호를 발급합니다.
- 이전 worker가 늦게 결과를 쓰지 못하도록 attempt 또는 fencing token이 현재 값인지 확인합니다.
timeout이 너무 짧으면 정상 장기 작업을 중복 실행하고 너무 길면 장애 복구가 늦습니다. 처리 시간 분포와 checkpoint 가능 여부에 맞춰 작업 종류별로 다르게 정합니다.
실패 작업을 재시도할 때 중복 결과와 재시도 폭주를 막기 위한 멱등키, 횟수 제한, 지연 정책을 설명해 주세요.
답변 예시 보기
진단과 접근
재시도는 일시 오류에만 적용하고 횟수와 속도를 제한해야 합니다. 결과 생성은 jobId 또는 업무 키로 멱등하게 만들어 같은 작업이 다시 실행돼도 결과가 하나만 남게 합니다.
설계와 운영
- 지수 백오프와 jitter로 공통 장애 후 모든 작업이 동시에 재시도되지 않게 합니다.
- 최대 횟수를 넘기면 DLQ 또는 MANUAL_REVIEW 상태로 보내고 운영 재실행 기능을 제공합니다.
- 리포트 파일은 임시 경로에 만든 뒤 성공 시 최종 키로 교체하거나 version을 확인합니다.
무한 재시도는 원인을 숨기고 자원을 고갈시킵니다. 재시도 성공률, 시도 횟수, 오래된 실패 작업과 downstream 오류를 관측합니다.
서비스 통합 모니터링 플랫폼
상황
조건
규모와 시스템 구성
- 서비스 300개, 초당 로그 20만 건
- metric 10초 주기 수집
- 최근 7일 빠른 조회, 90일 보관
현재 문제와 제약
- Backpressure수집 지연이 서비스로 전파
- Volume특정 서비스 로그 폭증
- Alert같은 장애의 중복 알림
꼬리 질문
애플리케이션에서 로그·metric을 수집하고 중앙 저장소에 적재하는 흐름을 비동기로 구성해 주세요.
답변 예시 보기
진단과 접근
애플리케이션은 로그 전송 완료를 기다리지 않고 로컬 agent나 비차단 버퍼에 기록해야 합니다. 중앙 collector가 이벤트를 받아 queue에 저장하고 저장·색인 작업자가 비동기로 처리합니다.
설계와 운영
- 애플리케이션→로컬 agent→collector→durable queue→검색/metric 저장소로 단계를 분리합니다.
- 공통 필드로 timestamp, service, environment, level, traceId를 정의합니다.
- 수집 지연, queue age, 저장 실패, 서비스별 유입량을 관측해 어느 구간이 막혔는지 확인합니다.
모니터링 데이터의 완전성을 높이려다 서비스 요청이 느려져서는 안 됩니다. 감사 로그처럼 반드시 보존할 데이터는 일반 디버그 로그와 별도 경로로 구분합니다.
수집 서버나 저장소가 느려질 때 애플리케이션을 보호하기 위한 로컬 버퍼, 샘플링, 폐기 우선순위를 어떻게 정하겠습니까?
답변 예시 보기
진단과 접근
중앙 수집이 느릴 때 로컬 버퍼에는 상한이 있어야 하며 중요도에 따라 무엇을 버릴지 미리 정해야 합니다.
설계와 운영
- ERROR와 핵심 업무 metric은 우선 보존하고 DEBUG·반복 로그는 먼저 샘플링하거나 폐기합니다.
- 버퍼가 가득 차도 애플리케이션 스레드를 오래 막지 않고 손실 건수를 별도 metric으로 남깁니다.
- 서비스별 전송 quota와 rate limit으로 한 팀의 폭주가 전체 수집기를 고갈시키지 않게 합니다.
디스크 버퍼는 장애 시간을 견디지만 디스크 고갈 위험이 있습니다. 최대 용량과 보존 시간을 정하고 오래된 낮은 우선순위 데이터부터 삭제합니다.
한 장애로 같은 알림이 계속 발생하지 않도록 알림 조건, 묶음, 재알림 간격을 어떻게 설정하겠습니까?
답변 예시 보기
진단과 접근
알림은 순간 한 번의 임계치 초과보다 일정 시간 지속되는 사용자 영향에 초점을 두어야 합니다. 같은 원인의 알림은 서비스와 오류 유형 기준으로 묶습니다.
설계와 운영
- 5분 중 3회 이상 임계치 초과처럼 지속 조건을 두고 정상 복귀에도 여유 구간을 둡니다.
- 같은 서비스·원인의 알림은 하나의 incident로 group하고 일정 시간 동안 중복 통지를 억제합니다.
- 심각도에 따라 즉시 전화, 메신저, 업무 시간 알림을 구분하고 ACK가 없을 때만 다음 담당자에게 전달합니다.
알림을 줄이는 과정에서 실제 장애 탐지가 늦어지지 않도록 알림 수, 오탐률, 탐지 시간, ACK 시간을 함께 측정합니다.