CH4 클라우드·결제시스템 모의면접 예상질문 리스트

임선구·2026년 6월 29일

모의면접

목록 보기
2/3

CH4 클라우드·결제 시스템 모의면접 예상질문 정리

AWS 배포, Docker, HTTPS, PortOne V2 결제, Webhook, 포인트 결제, 환불, 재고 정합성, 정기 구독 결제까지 CH4 프로젝트에서 나올 수 있는 면접 질문과 핵심 답변을 정리했습니다.


AWS · 배포 영역

Q1. EC2, RDS, S3를 함께 사용하는 이유가 뭔가요? 각각 어떤 역할을 담당했나요?

A.

EC2, RDS, S3는 각각 역할이 다르기 때문에 함께 사용했습니다.

  • EC2: Spring Boot 애플리케이션을 실행하는 서버
  • RDS: MySQL 데이터베이스를 관리하는 서비스
  • S3: 이미지, 파일 같은 정적 리소스를 저장하는 스토리지

EC2에 애플리케이션을 배포하고, 데이터는 RDS에 저장하며, 파일은 S3에 저장해서 서버와 저장소의 책임을 분리했습니다.

꼬리질문 1. EC2와 RDS를 같은 VPC 안에 두면서 보안 그룹은 어떻게 설정했나요?

EC2와 RDS는 같은 VPC 안에 두고, RDS는 외부에서 직접 접근하지 못하도록 설정했습니다.

보안 그룹은 보통 다음과 같이 구성합니다.

  • EC2: 80, 443, 필요 시 22번 포트 허용
  • RDS: 3306 포트를 EC2 보안 그룹에서 오는 요청만 허용

즉, 사용자는 EC2에만 접근하고, DB는 EC2를 통해서만 접근할 수 있게 구성합니다.

꼬리질문 2. RDS 대신 EC2에 직접 MySQL을 설치하는 방식과 비교했을 때 단점은 없나요?

RDS는 관리형 서비스라 편리하지만 비용이 더 들 수 있고, 세부 설정을 완전히 직접 제어하기는 어렵습니다.

반대로 EC2에 직접 MySQL을 설치하면 비용이나 설정 자유도는 장점이 될 수 있지만, 백업, 장애 복구, 보안 패치, 모니터링을 직접 관리해야 해서 운영 부담이 커집니다.


Q2. Docker로 애플리케이션을 컨테이너화한 이유가 뭔가요?

A.

Docker를 사용하면 애플리케이션 실행 환경을 이미지로 고정할 수 있습니다.

개발 환경과 배포 환경의 Java 버전, 라이브러리, 실행 방식 차이를 줄일 수 있고, 어디서 실행하더라도 동일한 방식으로 애플리케이션을 띄울 수 있습니다.

즉, 배포 환경의 차이로 발생하는 문제를 줄이기 위해 사용했습니다.

꼬리질문 1. Dockerfile 작성 시 이미지 크기를 줄이기 위해 고려한 것이 있나요?

이미지 크기를 줄이기 위해 다음을 고려할 수 있습니다.

  • 빌드 단계와 실행 단계를 분리하는 Multi-stage build 사용
  • 실행에 필요 없는 Gradle 캐시, 테스트 파일, 소스 파일 제외
  • JDK 대신 실행만 가능한 JRE 기반 이미지 사용
  • 불필요한 패키지 설치 최소화

이렇게 하면 최종 이미지에는 애플리케이션 실행에 필요한 파일만 포함할 수 있습니다.

꼬리질문 2. CI/CD 파이프라인에서 테스트 실패 시 배포가 어떻게 차단되나요?

CI/CD 파이프라인에서 보통 test 단계와 deploy 단계를 분리합니다.

./gradlew test가 실패하면 해당 job이 실패 상태가 되고, 그 다음 배포 job이 실행되지 않도록 설정합니다.

즉, 테스트를 통과한 코드만 Docker 이미지 빌드와 배포 단계로 넘어가게 해서 안정성을 높입니다.


Q3. HTTPS를 적용한 이유와 적용 방식을 설명해주세요.

A.

HTTPS는 클라이언트와 서버 사이의 통신을 암호화하기 위해 적용합니다.

로그인 정보, 결제 정보, 개인정보가 네트워크에서 평문으로 노출되는 것을 막을 수 있습니다.

적용 방식은 보통 다음과 같습니다.

  • 도메인 연결
  • SSL/TLS 인증서 발급
  • Nginx 또는 ALB에 인증서 적용
  • HTTP 요청을 HTTPS로 리다이렉트

꼬리질문 1. Let's Encrypt를 쓰는 방식과 ACM을 쓰는 방식의 차이가 뭔가요?

Let's Encrypt는 무료 인증서를 발급받아 EC2나 Nginx에 직접 적용하는 방식입니다.

ACM은 AWS Certificate Manager에서 인증서를 발급받고, ALB나 CloudFront 같은 AWS 서비스에 연결하는 방식입니다.

구분Let's EncryptACM
적용 위치EC2, Nginx 등ALB, CloudFront 등
관리 방식직접 갱신 설정 필요AWS 서비스와 연동 시 관리 편리
사용 상황EC2 단독 구성ALB, CloudFront 사용 구성

꼬리질문 2. ALB 없이 EC2 한 대에 HTTPS를 적용하려면 어떻게 해야 하나요?

EC2에 Nginx를 설치하고, Certbot으로 Let's Encrypt 인증서를 발급받아 Nginx에 적용할 수 있습니다.

흐름은 다음과 같습니다.

  1. 도메인을 EC2 Public IP에 연결
  2. EC2 보안 그룹에서 80, 443 포트 허용
  3. Nginx 설치
  4. Certbot으로 SSL 인증서 발급
  5. Nginx에서 443 포트 SSL 설정
  6. 80번 HTTP 요청을 443번 HTTPS로 리다이렉트

결제 시스템 영역

Q4. PortOne V2 기반 결제 흐름, Client Confirm 방식을 처음부터 끝까지 설명해주세요.

A.

Client Confirm 방식은 클라이언트에서 결제창을 띄우고, 서버에서 최종 검증과 확정 처리를 하는 방식입니다.

전체 흐름은 다음과 같습니다.

  1. 사용자가 주문을 요청합니다.
  2. 서버가 주문 금액, 할인 금액, 포인트 사용 금액을 계산합니다.
  3. 서버가 결제 대기 상태의 주문과 결제 정보를 생성합니다.
  4. 클라이언트가 PortOne SDK로 결제창을 호출합니다.
  5. 결제 성공 후 클라이언트가 paymentId 등을 서버로 전달합니다.
  6. 서버가 PortOne 결제 정보를 조회하거나 confirm API를 호출합니다.
  7. 서버가 주문 금액과 실제 결제 금액을 검증합니다.
  8. 검증 성공 시 결제 상태를 PAID로 변경합니다.
  9. 주문 상태, 포인트 내역, 재고 상태를 함께 확정합니다.

핵심은 클라이언트 응답만 믿지 않고, 서버가 최종적으로 금액과 상태를 검증한 뒤 결제를 확정하는 것입니다.

꼬리질문 1. 사전 금액 검증을 서버에서 하는 이유가 뭔가요? 클라이언트에서 처리하면 안 되나요?

클라이언트 값은 사용자가 조작할 수 있기 때문입니다.

상품 금액, 할인 금액, 포인트 사용 금액을 클라이언트에서만 계산하면 결제 금액을 임의로 낮춰 보낼 위험이 있습니다.

따라서 최종 결제 금액은 반드시 서버가 DB 기준으로 다시 계산하고 검증해야 합니다.

꼬리질문 2. 결제 검증 후 확정 처리 중 서버가 다운되면 어떻게 되나요?

결제는 PG에서는 성공했지만, 내부 DB에는 반영되지 않은 상태가 될 수 있습니다.

이를 대비해 결제 확정 로직은 멱등하게 설계해야 합니다.

예를 들어 같은 paymentId로 다시 요청이 들어와도 이미 처리된 결제라면 중복 처리하지 않고 기존 결과를 반환합니다.

또한 Webhook이나 결제 상태 재조회 배치를 통해 PG 결제 상태와 내부 결제 상태를 다시 맞출 수 있습니다.


Q5. Webhook 멱등성 처리를 어떻게 구현했나요?

A.

Webhook은 같은 이벤트가 여러 번 올 수 있다고 가정하고 멱등하게 처리해야 합니다.

보통 다음 기준으로 중복 처리를 막습니다.

  • webhookEventId
  • paymentId
  • orderId
  • 결제 상태값

처리 흐름은 다음과 같습니다.

  1. Webhook 요청을 받습니다.
  2. HMAC signature를 검증합니다.
  3. 이벤트 ID 또는 paymentId로 이미 처리된 이벤트인지 확인합니다.
  4. 이미 처리된 경우 바로 성공 응답을 반환합니다.
  5. 아직 처리되지 않았다면 결제 상태를 조회하고 내부 상태를 변경합니다.
  6. 처리 완료 이벤트를 저장합니다.

핵심은 같은 Webhook이 여러 번 와도 결제, 포인트, 재고가 중복 변경되지 않게 하는 것입니다.

꼬리질문 1. HMAC 서명 검증은 어느 시점에 처리했나요?

Webhook 요청을 받은 직후, 비즈니스 로직을 실행하기 전에 처리합니다.

서명 검증에 실패한 요청은 신뢰할 수 없는 요청이므로 결제 상태 변경, 포인트 환불, 재고 복구 같은 내부 로직을 실행하면 안 됩니다.

즉, HMAC 검증은 Webhook 처리의 가장 앞단에서 수행해야 합니다.

꼬리질문 2. Webhook 수신에 실패했을 때 PortOne이 재전송을 보장하나요?

외부 결제사의 Webhook 재전송 정책에만 의존하면 위험합니다.

서버 장애, 네트워크 장애, 응답 지연 등으로 Webhook이 누락되거나 늦게 도착할 수 있기 때문입니다.

따라서 Webhook은 보조 수단으로 보고, 서버에서는 결제 단건 조회 API나 상태 동기화 배치를 통해 결제 상태를 다시 확인할 수 있게 설계하는 것이 안전합니다.


Q6. 포인트 + PG 복합 결제에서 PG 실결제 금액을 어떻게 산정했나요?

A.

PG 실결제 금액은 최종 주문 금액에서 사용 포인트를 차감해서 계산했습니다.

PG 실결제 금액 = 최종 주문 금액 - 사용 포인트

예를 들어 주문 금액이 50,000원이고 포인트를 10,000원 사용하면 PG 결제 금액은 40,000원입니다.

다만 포인트 사용 가능 여부는 서버에서 검증해야 합니다.

  • 사용자의 포인트 잔액이 충분한지
  • 주문 금액보다 많은 포인트를 사용하지 않았는지
  • 최소 결제 금액 정책을 만족하는지
  • 이미 사용 처리된 포인트가 아닌지

꼬리질문 1. 결제 취소 시 포인트 환불은 어떻게 처리했나요?

결제 취소나 환불이 성공하면 사용했던 포인트를 다시 복구합니다.

이때 단순히 잔액만 증가시키는 것이 아니라, 포인트 사용 취소 내역을 포인트 거래 원장에 남기는 방식이 좋습니다.

예를 들어 다음과 같이 기록합니다.

  • 결제 시: USE
  • 환불 시: REFUND

이렇게 하면 포인트가 왜 증가하거나 감소했는지 추적할 수 있습니다.

꼬리질문 2. 포인트 잔액보다 많은 포인트를 사용하려는 요청은 어떻게 처리했나요?

서버에서 사용자의 현재 포인트 잔액을 조회하고, 요청 포인트가 잔액보다 크면 예외를 발생시킵니다.

이 경우 결제창을 띄우기 전에 요청을 차단해야 합니다.

응답은 보통 400 Bad Request로 처리하고, 메시지는 “보유 포인트보다 많은 포인트를 사용할 수 없습니다.”처럼 반환할 수 있습니다.


Q7. 부분 환불 시 결제수단별 비율 분리 산정과 반올림 오차 보정을 어떻게 구현했나요?

A.

포인트와 PG가 함께 사용된 결제에서는 환불 금액을 결제수단별로 나눠야 합니다.

예를 들어 총 결제 금액이 100,000원이고, 포인트 20,000원, PG 80,000원으로 결제했다면 비율은 다음과 같습니다.

  • 포인트: 20%
  • PG: 80%

부분 환불 금액이 30,000원이라면 비율대로 계산합니다.

  • 포인트 환불: 6,000원
  • PG 환불: 24,000원

다만 나눗셈 과정에서 소수점이 생길 수 있기 때문에 반올림 오차를 보정해야 합니다.

PG 환불 금액 = 전체 환불 금액 - 포인트 환불 금액

이렇게 계산하면 포인트와 PG 환불 금액의 합이 항상 전체 환불 금액과 일치합니다.

꼬리질문 1. 반올림 오차를 PG에 몰아주는 이유가 있나요?

포인트는 내부 시스템에서 직접 관리할 수 있지만, PG 환불 금액은 외부 결제사에 정확한 금액으로 요청해야 합니다.

따라서 전체 환불 금액과 결제수단별 환불 합계가 어긋나면 안 됩니다.

한쪽을 기준으로 계산하고 나머지를 차액으로 보정하면 총액 불일치 문제를 줄일 수 있습니다.

실무에서는 회사 정책에 따라 오차를 포인트에 둘 수도 있고 PG에 둘 수도 있지만, 중요한 것은 합계가 정확히 맞도록 일관된 기준을 두는 것입니다.

꼬리질문 2. 여러 상품 중 일부만 환불하는 부분 환불과, 전체 금액의 일부만 환불하는 경우를 구분해서 처리했나요?

네, 구분해서 처리하는 것이 좋습니다.

  • 상품 단위 부분 환불: 특정 주문 상품의 수량과 금액을 기준으로 환불
  • 금액 단위 부분 환불: 전체 결제 금액 중 일부 금액만 환불

상품 단위 환불은 재고 복구, 주문 상품 상태 변경, 환불 가능 수량 검증이 함께 필요합니다.

반면 금액 단위 환불은 주로 결제 금액 정산과 환불 한도 검증이 중요합니다.


Q8. 재고 선차감 정책과 단일 트랜잭션 기반 정합성 보장을 어떻게 설계했나요?

A.

재고 선차감 정책은 주문 생성 시점에 재고를 먼저 차감하는 방식입니다.

결제까지 기다렸다가 재고를 차감하면 동시에 많은 사용자가 결제할 때 초과 판매가 발생할 수 있습니다.

그래서 주문 생성 시점에 재고를 차감하고, 결제 실패나 주문 취소가 발생하면 재고를 복구하는 방식으로 설계합니다.

흐름은 다음과 같습니다.

  1. 주문 요청을 받습니다.
  2. 상품 재고를 조회합니다.
  3. 재고가 충분한지 검증합니다.
  4. 재고를 차감합니다.
  5. 주문을 생성합니다.
  6. 결제 대기 상태로 저장합니다.
  7. 결제 실패 또는 취소 시 재고를 복구합니다.

이 과정은 하나의 트랜잭션 안에서 처리해서 주문 생성과 재고 차감이 함께 성공하거나 함께 실패하도록 해야 합니다.

꼬리질문 1. 비관적 락 대신 낙관적 락을 사용하지 않은 이유가 있나요?

재고처럼 동시에 많은 요청이 몰리고, 초과 판매가 절대 발생하면 안 되는 경우에는 비관적 락이 더 단순하고 안전할 수 있습니다.

낙관적 락은 충돌이 적을 때 유리하지만, 충돌이 많으면 재시도가 많이 발생할 수 있습니다.

반면 비관적 락은 먼저 데이터에 락을 걸고 처리하므로 같은 재고를 동시에 수정하는 상황을 강하게 제어할 수 있습니다.

꼬리질문 2. 인스턴스가 N대로 늘어나도 지금의 재고 동시성 제어가 그대로 유효할까요?

DB의 비관적 락을 사용한다면 애플리케이션 인스턴스가 여러 대로 늘어나도 같은 DB row에 대한 락이 걸리기 때문에 기본적인 정합성은 유지됩니다.

하지만 애플리케이션 내부의 synchronized 같은 JVM 락만 사용했다면 인스턴스가 여러 대일 때는 유효하지 않습니다.

인스턴스가 N대로 늘어나는 환경에서는 DB Lock, Redis Lock 같은 외부 공유 자원을 기준으로 동시성을 제어해야 합니다.

꼬리질문 3. 커넥션 점유가 늘어나면 어떤 일이 발생할까요?

트랜잭션이 오래 걸리거나 락 대기가 길어지면 DB 커넥션이 오래 점유됩니다.

그 결과 커넥션 풀이 고갈되고, 다른 요청들이 DB 커넥션을 얻지 못해 지연되거나 실패할 수 있습니다.

그래서 트랜잭션 범위를 짧게 유지하고, 외부 API 호출을 트랜잭션 안에서 오래 수행하지 않도록 주의해야 합니다.


Q9. 빌링키 기반 정기 구독 결제와 스케줄러 멱등 처리를 어떻게 구현했나요?

A.

빌링키 기반 정기 결제는 사용자가 최초 1회 결제수단을 등록하면, 이후에는 서버가 빌링키를 이용해 정해진 주기마다 자동 결제를 요청하는 방식입니다.

구현 흐름은 다음과 같습니다.

  1. 사용자가 결제수단을 등록합니다.
  2. PortOne을 통해 빌링키를 발급받습니다.
  3. 서버에 빌링키와 구독 정보를 저장합니다.
  4. 스케줄러가 결제 예정 구독을 조회합니다.
  5. 결제 요청을 보냅니다.
  6. 결제 성공 시 다음 결제일을 갱신합니다.
  7. 결제 실패 시 실패 상태와 재시도 정보를 저장합니다.

스케줄러는 중복 실행될 수 있으므로 멱등하게 처리해야 합니다.

예를 들어 subscriptionId + billingDate 기준으로 결제 시도 이력을 저장하고, 이미 처리된 결제일이면 다시 결제하지 않도록 막습니다.

꼬리질문 1. 정기 결제 실패 시 재시도 정책은 어떻게 설정했나요?

정기 결제 실패 시 바로 구독을 종료하기보다는 재시도 정책을 둘 수 있습니다.

예를 들어 다음과 같이 처리할 수 있습니다.

  • 1차 실패: 실패 이력 저장 후 다음 날 재시도
  • 2차 실패: 사용자에게 결제 실패 알림
  • 3차 실패: 구독 일시 중지 또는 만료 처리

재시도 횟수와 주기는 서비스 정책에 따라 정하고, 중복 결제가 발생하지 않도록 결제 시도 이력을 반드시 저장해야 합니다.

꼬리질문 2. 등급별 적립률 차등 적용은 어떻게 관리했나요?

회원 등급별 적립률은 코드에 하드코딩하기보다 정책 테이블이나 Enum으로 관리할 수 있습니다.

예를 들어 BASIC, VIP, VVIP 등급에 따라 적립률을 다르게 두고, 결제 완료 시점에 회원 등급을 조회해서 적립 포인트를 계산합니다.

중요한 점은 결제 당시 적용된 적립률을 이력으로 남기는 것입니다.

나중에 등급 정책이 바뀌더라도 과거 결제의 적립 내역은 그대로 추적할 수 있어야 합니다.


Q10. 결제 성공 응답과 Webhook 이벤트가 동시에 들어오거나, 서로 다른 시점에 지연 도착하는 상황을 고려해 결제 확정 로직을 어떻게 설계했나요?

A.

결제 성공 응답과 Webhook은 도착 순서가 보장되지 않습니다.

클라이언트 성공 응답이 먼저 올 수도 있고, Webhook이 먼저 올 수도 있으며, 둘 다 동시에 들어올 수도 있습니다.

그래서 결제 확정 로직은 하나의 공통 메서드로 모으고, 멱등하게 처리해야 합니다.

예를 들어 다음과 같이 설계할 수 있습니다.

  1. 클라이언트 성공 응답 또는 Webhook 수신
  2. paymentId 기준으로 결제 정보 조회
  3. 이미 PAID 상태라면 추가 처리 없이 종료
  4. 아직 대기 상태라면 PortOne 결제 상태 조회
  5. 금액, 주문번호, 상태 검증
  6. 검증 성공 시 내부 결제 상태를 PAID로 변경
  7. 주문, 포인트, 재고 상태를 확정
  8. 처리 이력 저장

핵심은 어느 경로로 들어오든 같은 확정 로직을 타게 만드는 것입니다.

그래야 중복 요청, 지연 요청, 동시 요청 상황에서도 결제가 한 번만 확정됩니다.


Q11. 결제 실패가 발생했을 때 원인을 어떻게 추적할 수 있나요?

A.

결제 실패 원인을 추적하려면 외부 PG 응답과 내부 서버 로그를 연결할 수 있어야 합니다.

이를 위해 다음 값을 로그와 DB에 남기는 것이 좋습니다.

  • orderId
  • paymentId
  • PortOne transaction id
  • 요청 금액
  • 실제 결제 금액
  • 결제 상태
  • 실패 코드
  • 실패 메시지
  • Webhook event id
  • 요청 시각과 응답 시각

이렇게 남겨두면 결제 실패가 외부 PG 문제인지, 서버 검증 실패인지, 내부 트랜잭션 문제인지 추적할 수 있습니다.

꼬리질문. 외부 PG, Webhook, 내부 트랜잭션 장애 발생 시 어떻게 대응할 수 있나요?

장애 위치에 따라 대응 방식이 달라집니다.

장애 위치대응 방식
외부 PG 장애실패 응답 저장, 사용자에게 결제 실패 안내, 재시도 유도
Webhook 장애결제 단건 조회 API나 배치로 상태 재동기화
내부 트랜잭션 장애결제 상태와 내부 주문 상태 불일치 여부 확인 후 보정
DB 장애트랜잭션 롤백, 실패 로그 저장, 재처리 대상 등록
네트워크 장애timeout 설정, 재시도 정책, 중복 처리 방지

중요한 것은 결제 성공 여부를 클라이언트 응답만으로 판단하지 않고, PG 결제 상태와 내부 DB 상태를 비교해서 불일치를 복구할 수 있게 만드는 것입니다.


마무리 정리

CH4 클라우드·결제 시스템 면접에서는 단순히 기능 구현 여부보다 장애 상황에서 정합성을 어떻게 보장했는지를 많이 물어볼 수 있습니다.

특히 다음 키워드는 꼭 연결해서 답변하는 것이 좋습니다.

  • EC2, RDS, S3의 역할 분리
  • VPC와 보안 그룹 설정
  • Docker를 통한 실행 환경 통일
  • HTTPS 적용 이유
  • 서버 기준 결제 금액 검증
  • Webhook 멱등성
  • 포인트 원장 관리
  • 부분 환불 금액 산정
  • 재고 선차감과 복구
  • 트랜잭션과 락
  • 결제 실패 추적과 상태 보정

면접에서는 “구현했습니다”에서 끝내기보다,
왜 그렇게 설계했는지, 장애가 나면 어떻게 복구할 수 있는지, 중복 요청이 와도 안전한지까지 함께 설명하는 것이 중요합니다.

출처: 내일배움 스파르타 클럽

profile
끝까지 가면 내가 다 이겨

0개의 댓글