1.
특정 경매가 인기가 좋아 트래픽이 많이 발생했다면 어떤식으로 대응 할 계획이신가요? 수정
단일 서버 기준 connection timeout 10초 최대 tread 24로 평균 최대 레이턴시 5초대로 느리지만 에러 없이 처리 했습니다.
•
또한 Auto-scale 구성을 해놓아서 트래픽이 많이 몰린다고 어느정도 부하를 감당할 수 있습니다.
•
DB, Redis 의 경우에도 RDS, Elastic Cache의 클러스터 설정으로 동적으로 노드를 늘려주거나 줄여주어 트래픽에 대응할 수 있습니다.
•
다만 무작정 서버를 늘리는것에는 코스트 한계가 있기 때문에, 현재 구성 이 감당 불가능한 트래픽이 지속적으로 발생하게 되면 alb 앞 단에 대기열 큐를 구성하여 트래픽 제어를 고려할 것 같습니다.
- 트래픽 대응 방법은 아주 완벽합니다 좋습니다.
•
"특정 경매"라는 키워드로 질문을 드린 이유는 예상 가능하거나 이미 트래픽이 초과된 이후 상황을 가정한 거라 대응 방법을 순서대로 또는 각 상황별 대응방법을 답변해주시는것이 좋습니다.
ps. 너무 AWS의 기능에 의존하는것 처럼 보이는 답변입니다.
2.
경매, 선착순 결제 등 좌석이 결제가 된 상황에서 공연이 취소 될 경우 환불을 진행해야 하는데 이 때 DB에 어떻게 반영할건지 전략을 알려주세요.
1. 예매 상태에 환불 상태 추가하여 예매 상태 식별
2. 환불 작업 배치 프로그램 개발
a. 환불 공연 선택
b. 공연에 포함된 모든 결제된 기록을 각각 별도의 트랜잭션으로 결제 취소 처리를 진행한다.
c. 환불 처리에 대한 로그를 별도의 테이블에 기록하여 트랜잭션 오류 발생시 재처리를 시도사용자한테 환불 처리 알림
•
환불 이라는 키워드에 조금 매몰되신거 같습니다. 환불의 영향 범위는 단순 결제가 아닌 좌석의 롤백까지 입니다. 결제 취소와 빈 좌석 상태가 어느시점에 적용되며 어디까지 롤백을 시킬건지 등등 고민해보시면 좋을거 같습니다.
c.
사용자한테 환불 처리 알림
•
환불 이라는 키워드에 조금 매몰되신거 같습니다. 환불의 영향 범위는 단순 결제가 아닌 좌석의 롤백까지 입니다. 결제 취소와 빈 좌석 상태가 어느시점에 적용되며 어디까지 롤백을 시킬건지 등등 고민해보시면 좋을거 같습니다.
3. Mysql 에도 입찰 테이블이 있고 Redis에도 입찰 테이블이 있는데 어느 시점에 어떻게 동기화가 진행되는지 동기화를 하는 이유는 무엇인지 알려주세요.
•
우선 입찰 API 를 통해 입찰을 하게 되었을 떄, Redis 의 입찰가를 조회하여 상횡입찰인지에 대해 검증을 수행합니다. 상회 입찰일 경우 DB 입찰 테이블에 입찰 정보를 저장합니다. 결국 경매 입찰은, 아무리 많은 입찰 요청이와도 '상회입찰'만 실제 입찰이 되기 때문에, Redis를 통해 입찰 검증을하게되면 그만큼 DB에 부하를 주지 않습니다. 그리고 Redis 입찰가 갱신하는 시점에 같이 DB 동기화를 해주는 이유는 다른 유저가 첫 경매정보를 조회할때, 해당 경매의 입찰테이블 에서 가장 높은 금액의 입찰가를 조회하기 떄문입니다.
•
잘 답변해주셨습니다. 단순 입찰 비교용으로 레디스를 사용하셨군요! 만약 경매가 과열되어서 상회입찰이 빈번하게 일어난다고 하면 경매 종료시에만 DB에 동기화하는것도 좋아보입니다!
4. 대용량 트래픽을 목표로 하고 있는데 알림 푸쉬 전략도 궁금합니다.
•
입찰가 갱신과 추후 구현 예정인 경매 상태 알림 등 SSE 통신을 하게 되는데, SSE 연결객체는 각 서버의 메모리에서 관리를 하게됩니다. 대용량 트래픽 처리를 위해서는 분산 서버 환경이 필수인데, 서버가 분산되는경우 SSE 알림이 각 서버별로 따로 동작하게 됩니다. 이를 해결하기 위해 Redis Pub/Sub 구조를 활용하여 Client에 SSE 를 통해 메시지를 보내야 하는 경우, Redis 에 Publish하여 필요한 메시지를 서버들이 구독하여 각 SSE에 연결된 클라이언트들에게 보내도록 구현하였습니다.
시스템이 MSA로 고도화된다면 SSE 전용 서버를 따로 두고 관리하는것도 고려해볼것 같습니다.
•
아주 좋습니다. 분산 서버 환경에서 SSE 활용을 잘 이해하고 계십니다! 답변해주신 방법 외에 알람 전용 서버를 하나 따로 만드는 방법도 있습니다!
5. 로그인 전략과 선택 이유를 대규모 트래픽 이라는 키워드에 맞춰서 말씀해주세요
•
대용량 트래픽 처리를 위해서 서버가 2대 이상 운영되어야 할 필요성이 있기 때문에, 분산, 무상태 아키텍처를 지원하는 JWT 를 이용한 로그인 전략을 선택하였습니다. 그리고 global redis를 통해 로그아웃 상태와 유효기간이 상대적으로 긴 refresh token을 관리함으로써 여러 서버 간에서 일관된 유저의 로그인 상태를 유지할 수 있도록 하기 위해 jwt 방식을 선택했습니다.
•
좋은 답변입니다! 보통 redis는 다른 서버라고 생각하기 때문에 굳이 global redis라고 명시 안하셔도 괜찮습니다
6.
ERD가 초기와 많이 바뀌었습니다. 바뀐 이유와 어떤점이 개선 되었는지 설명해주세요
•
초기에 ERD를 설계할때는 프로젝트 기획상 예매와 경매를 구분하고 화차별로 관리되어야 하기 때문에 공연장을 생성할때 생성된 좌석정보들과 공연이 생성될때 생성되는 회차별 좌석의 정보를 가지고 있는 공연 회차별 좌석 테이블을 생성하여 관리했습니다. 이러한 관리방식은 사용하지 않는 데이터가 발생할 경우가 많고, 공연정보가 생성될때마다 회차별로 좌석을 생성하기 때문에 적게는 1000~ 수만개의 좌석이 한번에 생성될 경우가 발생합니다. 이럴경우 DB가 부하가 심각하게 걸려 정상적인 서비스를 운영할 수 없다고 판단했습니다.개선된점은 기존의 좌석에 대한 문제를 구역과 등급테이블로 분리하고 동시에 관리할 구역 등급 테이블을 추가하여 예매와 경매를 등록할시 좌석정보가 생성되게끔하여 사용하지 않는 데이터가 없게끔 변경하였고 동시에 생성트래픽을 관리하는것이 아닌 분산으로 트래픽을 관리하게 끔하여 DB부하를 최소화 했습니다.
•
ERD 변경에 대한 이유가 명확하고 풀이방법에 대한 접근도 올바르게 보입니다. 고생하셨습니다!!
7.
Front 배포를 CloudFront로 선택했는데 그 이유를 설명해 주세요, 또 CDN이 무엇인지 설명해주세요
•
사용자가 직접 실시간으로 입찰을 진행하는 상호작용된 결과를 웹 페이지에서 실시간으로 보여주는 역할을 담당하며 입력과 행동에 따라서 발생한 데이터를 처리하고 유효성 검사를 진행하여 서버로부터 필요한 데이터를 요청하고 받은 응답을 표시할 권한이 있다. 백엔드는 사용자의 실시간으로 들어오는 요청을 비즈니스 로직으로 처리하며 여러 요청이 동시에 들어올때 이를 효과적으로 DB와 상호작용하여 필요한 데이터를 순서대로 처리 및 관리를 통해 사용자에게 즉각적인 피드백을 줄 수 있는 역할을 담당하며, 사용자에게 요청에 따른 데이터를 프론트엔드로 전송할지 결정하고 사용자의 접근 권한을 관리할 권한이 있습니다.
•
전체적으로 잘 답변해 주셨습니다! 다만 백엔드와 프론트에서 가지고가는 디테일 부분을 더 설명해주시면 좋을거 같습니다. 예를들면 시스템 보안적으로 고려해 이렇게 나눴다 라던지, 성능 최적화를 위해 이렇게 나눴다가 추가되어있으면 좋겠습니다!
8.
CI/CD를 적용한다고 하면 입찰 중에 배포가 될 수도 있습니다. 이럴 경우는 어떻게 동작하는지 예상 시나리오를 알려주세요
수정
•
운영중인 Ec2 인스턴스가 2대일 때(블루그룹), 2대의 대체인스턴스(그린그룹)를 추가 생성합니다
•
대체인스턴스에 새로 배포된 서버를 올리고 로드밸런서가 대체인스턴스에 트래픽을 허용하게 됩니다.
•
트래픽 허용후 설정한 확인시간 (5분) 동안 서버에 문제가 없는지 확인하고 문제가 있다면 롤백 처리하도록 하였습니다. (롤백 여부도 설정)
•
이상이없다면 기존 운영중인 인스턴스 그룹에 대한 트래픽을 제한하고 자원을 회수하게 됩니다.
9.
해당 프로젝트를 진행하면서 효율적이였던 협업 방식과 비효율적이였던 협업 방식을 하나씩 설명해주세요 수정
•
저희는 프로젝트를 진행하면서 코드 품질을 유지하기 위해 PR을 통해 2명 이상의 리뷰를 받고 승인을 받아야 Merge가 되게 구성하였고 지키려고 노력하였습니다. 다만 팀원이 PR을 올릴 때, 슬랙을 통해 채팅을 하거나
리뷰를 해달라 요청하는게 번거로웠습니다. 그래서 커뮤니케이션 툴인 Slack 의 github 훅을 연동하여 PR 리뷰 요청 또는 이슈 등록에 대해 알림설정을 하여 효율적으로 코드리뷰를 할 수 있었습니다.
비효율적이었던 부분은 테스트 코드 였습니다. 처음엔 모든 로직에 대해 테스트코드를 작성하고 PR을 올리도록 원칙을 정했는데, 짧은 일정과 예상치 못한 기능 문제들로 일정을 소화하기 힘들었습니다.
그래서 중요한 비즈니스 로직이 아닌이상 테스트코드는 과감히 생략했고, PR시 테스트 빌드 자동화로
최소한의 리뷰로 코드품질을 유지할 수 있었습니다.
•
답변이 사실과 상황 설명만 하고있어 면접 답변으론 적합하지 않은거 같습니다. 문제와 함께 접근방법, 해결방안 등을 같이 답변해주시면 좋을거 같습니다.
새로운 질문
1.
아키텍쳐 구성을 굉장히 잘 해주셨는데요. 각각의 도입 이유와 도입 시 장점에 대해서 설명해주세요.
1-1. Prometheus, Grafana, Promtail, Loki 의 도입 이유 및 장점
시스템 모니터링 대상은 서버 리소스와 로깅을 목표로하고있었습니다해당 툴들 외에 Springboot admin, cloudwatch, elk 등 다양한 툴들을 고려하였는데해당 스택을 선택한 이유는 다음과 같습니다.
1. 플랫폼에 종속적이지 않습니다.
2. 오픈소스 툴이라 별도의 구매비용이 들지 않습니다.
3. metric 설정 레퍼런스가 많고 그라파나의 경우 다양한 대시보드 템플릿을 제공하여 러닝커브가 높지않습니다.
4. 서버 메트릭과 로깅을 한 대시보드에서 볼 수 있습니다.
위와 같은 장점으로 해당 스택을 사용하여 모니터링을 구성하였습니다.
Plain Text
복사
1-2. CloudFront, S3 의 도입 이유 및 장점
3가지 중 이것을 한 이유
1개 못들었어요ㅠ
바로바로 클라우드프론트에 배포된다는 장점
aws 에서 나머지 것들을 관리하고 있기 때문에 이것도 함께 aws를 이용하여 관리하면 좋을 것 같아서
Plain Text
복사
2.
redis 캐싱 전략에 대해서 설명해주세요. (어떤 성격의 데이터 언제 캐싱하고 언제 만료시키는지)
메인페이지에서 사용한 캐싱전략은 Cache Aside입니다.
메인페이지 특성상 많은 유저가 조회를 하기 캐시메모리를 먼저 조회하여 데이터가 있다면 제공하고 없다면 DB에서 데이터를 조회 및 유저에게 데이터를 제공하고 캐시메모리에 저장합니다.
만료 시간은 트래픽이 몰릴때를 가정하여 30분으로 설정했습니다.
Plain Text
복사
3.
동시성 처리 방식에 대해서 설명해주세요.전체 아키텍쳐와 서비스 구성, 트러블 슈팅까지 정말 잘 정리되고 구현된 프로젝트인 것 같습니다. 다루고 있는 기술도 많고 서비스적인 결정사항도 많으니 이미 구현을 끝낸 부분이라도 재학습을 통해 면접 대비 시간을 충분히 가지시면 좋을 것 같습니다. 정말 고생많으셨습니다.
경매 입찰의 경우 락을 이용하여 구현하였습니다.
그중 Redis의 분산락을 이용하였는데요
우선 분산환경을 고려해서 syncronized 나 서버 트랜잭션제어에 대해서는 제외하였습니다.
입찰의 특성상 같은 데이터로 동시성 출돌되는 경우가 매우 많다고 생각하는데.
DB에서 Lock을 사용하게 되면 우선 db에 커넥션을 맺고 레코드를 점유하게 되서
redis에서 처리하는 것보다 비용이 비싸다고 생각했습니다.
----Redis 락에대해 추가질문할 경우
Jedis , Lettuce, Redisson 중 Redisson을 이용하여 구현하였습니다.
Jedis 는 다른 두 라이브러리에 비해 성능이 떨어지지므로 제외했고
Lettuce는 스핀락기반으로 요청이 많을 수록 부하가 커지고 retry 로직을 작성해야해서
Redisson으로 구현하였습니다. 입찰의 경우 상회입찰이 아닌경우 오직 하나의 입찰을 가진 요청만 처리하면되기때문에
retry에 대한 강제성이 거의 없고 적절한 타임아웃 시간만 조정해주면 부하도 줄일 수 있다고 생각했습니다.
-- 예매 좌석 동시성
예매 좌석의 동시성 문제는 생성을 제약함으로서 제어했습니다.
회차id, 구역등급id, 좌석번호id 복합키를 기본키로 두고, 생성을 제약합니다.
Plain Text
복사
4.
경매 사이트다 보니 많은 유저가 경매에 참여하고 취소하는 경우가 있을 텐데 중복 처리는 어떻게 구현하셨나요?
우선 유저가 경매 동시 입찰할 경우를 고려하여 redis의 분산락을 통한 동시성 제어를 구현하였습니다.
경매 취소의 경우 무분별한 입찰 제한을 위해서 취소는 불가능하게 기획하였고 낙찰 후 예매가 되었을 때,
환불을 할 수 있도록 열어놓았습니다.
Plain Text
복사
5.
대용량 트래픽 관련해서 어떠한 노력을 하셨는지?
1. 반복 조회 데이터 캐싱 및 쿼리 개선
2. 고가용성을 위한 클러스터링 구성 및 이중화 구성
3. 트래픽 분산 처리를 위한 Auto Scale Out 구성
4. 장애 대응을 위한 서버 모니터링 시스템 구성
Plain Text
복사
6.
팀원들과 협업 관련해서 가장 문제점이 뭐였는지?
협업에 관련한 가장 큰 문제점은 개발을 진행함에 있어서 각자 담당하고 있는 API가 많다보니 서로 소통할 시간없이 개발에만 몰두하여 나중에 서로진행 상황을 확인하지 못한부분인데요.
이부분에 관련하여 저녁시간에 따로 시가을 마련하여 서로 진행상황에 대해 공유하고 피드백하는 시간을 가져 서로의 개발 부분에 대한 진행사항과 지식의 공백을 채웠습니다.
Plain Text
복사
7.
대용량 트래픽 처리 관련해서 DB connection 리소스를 줄인점이 좋았습니다. 그렇다면 트래픽에 대해 네트워크 대역폭 관점에서도 고려한 사항이 있을까요?
RDS 를 구성할 때 네트워크 I/O에 대한 고민은 했었지만 고가용성을 더 우선순위에 두고 결정했습니다.
비용적인 한계가 있어 인스턴스 성능과 클러스터링 구성 중 클러스터링을 선택하게 되었습니다.
또한 현재 서비스 특성상 대용량의 데이터보단 많은 트래픽에 대한 처리를 고려해야한다 생각해서
ReplicaDB 를 구성하여 로드밸런싱을 통해 네트워크 트래픽을 분산처리 하고있습니다.
Plain Text
복사
8.
모니터링 매니징 툴로 그라파나, 프로메테우스를 사용했다고 했는데, 어떤 메트릭 지표를 중점적으로 모니터링 하셨나요? 모니터링간에 문제가 발생한 적 있었다면 어떻게 해결해 나갔는지도 궁금하네요~
9.
아직까지 남아 있는 이슈가 있을까요? 남아 있다면 어떤 이유 때문에 남아있고 그 문제를 해결하기 위해 어떤 과정을 겪었는지 알려주세요!
네트워크 RTT를 줄이기 위해 Redis의 pipeline 기능을 사용했는데, API 요청이 많아지면
RedisConnectionFailureException 예외가 발생하는 문제가 있습니다.
문제를 해결하기 위해 redis의 maxclient이나 connection timeout을 늘려서 해결을 시도했지만
해결하지 못했습니다. 현재는 요청 횟수를 제어하는 방향으로 트러블 슈팅을 진행중입니다.
또한 예외의 정확한 원인을 알기 위해 Redis client로 사용중인 lettuce의 코드를 분석하고,
redis 책을 학습중입니다.
Plain Text
복사
10.
대용량 트래픽 처리의 해결방안으로 레디스에 캐싱을 사용하셨다고 했는데 구체적으로 레디스를 통해 어떠한 상황의 대용량 트래픽 처리에 도움이 됐는지 사례와 함께 알려주세요!
좌석 상태 조회 API를 호출할 때, 좌석 상태 데이터를 빠르게 얻기 위해서 Redis에 캐싱했습니다.
데이터의 정합성을 위해서 좌석 상태가 변경될 때, Redis에 캐싱된 데이터도 갱신합니다.
좌석 상태 조회 API는 Redis에 캐싱된 데이터만 읽음으로서 API TPS는 1000 -> 1800으로 80% 상승,
MTFB(평균 첫 바이트 도착 시간)은 600ms -> 400ms로 약 30% 감소했습니다.
Plain Text
복사
11.
JwtAuthenticationFilter 가 실제 로그인을 처리하는 Filter 인걸로 보이는데, attemptAuthentication 에서 반환하는 인증전 객체(UsernamePasswordAuthenticationToken)에 대한 실제 인증을 처리해주는 로직이 어디있는지 흐름을 설명해주실 수 있을까요?
12.
Spring Security 전반적으로 흐름을 잘 잡아주셨는데, 조금 과하게 사용된 부분이 보이고 챙겨야하는데 놓친 부분이 보여서 관련 질문 드려봅니다.
실제 인증 처리는 AuthenticationManager 가 Provider 에게 위임하여 진행됩니다.
이 Provider(DaoAuthenticationProvider) 는 UserDetailsService 구현체의 loadUserByUsername 내용으로 사용자 정보를 가져와 비교 후 인증해줍니다.
정확하게 과하게 사용된 부분과 놓친 부분을 파악할 수 없어서.. 자세히 설명해주시면 감사드리겠습니다.
Plain Text
복사
13.
Annotation 을 이용한 Spring AOP 를 구현해주신 부분에서 CustomSpringELParser 를 이용해서 동적 Key 를 획득하는 부분이 인상적이네요. Key 에 입력된 값과 실제 파라미터의 문자열 형태가 달라졌을 때 어떤 방식으로 문제가 발생하는지 궁금합니다.
CustomSpringElparser를 통해 key 값을 메소드 return 값, 문자열, 파라미터 등 다양한 값을 key로 만들 수 있었습니다.
다만 문자열 형태로 key 값을 받음으로써 key값이 변경되는 경우 직접 문자열을 수정해주어야 하는 유지 관리 관점에서 문제점이 있습니다.
또한 컴파일 시점에서 에러를 확인할 수 없어 오타로 인한 장애가 발생할 수 있습니다.
JavaScript
복사
14.
추가로, 분산락을 구현함에 있어 Redisson 을 사용했는데 왜 선택했는데, 그리고 Redisson 과 더불어 Lettuce 를 부분적으로 사용하고 있는데 혼합해서 사용한 이유가 있는지 궁금합니다.
Lettuce는 스핀락기반으로 요청이 많을 수록 부하가 커지고 retry 로직을 작성해야합니다.
입찰의 경우 상회입찰이 아닌경우 오직 하나의 입찰을 가진 요청만 처리하면되기때문에
retry에 대한 강제성이 거의 없고 적절한 타임아웃 시간만 조정해주면 부하도 줄일 수 있다고 생각되서
Redisson으로 분산락을 구현하였습니다.
다만 Redisson을 통해 캐싱 및 저장을 하려면 Redisson의 자료구조에 대해 배워야하는데,
자료구조 이용을 배우는 것보다 기존에 사용하던 Letucce 클라이언트를 이용하여 캐싱 및 저장을 하는게
좋다고 생각되어 두개의 클라이언트를 이용하게 되었습니다.
JavaScript
복사
15.
nGrinder 를 사용해 성능테스트를 진행할 때 vUser, RampUp 등의 기능을 어떤 방식으로 활용했고, 어떤 산출물을 최종적으로 만들어냈는지 궁금합니다.
먼저 vUser의 확장을 통해 저희 프로젝트에서 동시에 접속하는 유저에 한에서 최대로 수용가능한 지표를 알고 싶었고 RampUp을통해서 점진적으로 유저가 유입됐을때에 대한 테스트를 진행했습니다.
테스트를 진행함에 따라 서버에서 어느정도 부하를 버틸 수 있는지 확인했고, 구현한 모니터링 시스템을 확인하면서 테스트 진행시에 유저 3000명의 동시 접속시에 부하를 못버티는 문제를 발견했습니다.
따라서 EC2의 서버의 t.3Micro에서 t.3 Small로 변경하여 부하에 대한 안정성을 보강했습니다.
Plain Text
복사
질문 1 ) 어떻게 설계를 하게된것?
대용량 트래픽과 동시성을 고려하여
휘웅 튜터님 → 이 플젝은 공격거리가 많은 듯! (내용상)
질문 2) 외부와 API 통신이 있다면? (가상의 판매처(이게 맞나)를 두고 구현 /
독점 판매가 아니라면, 외부 서버와 통신해야할텐데 그게 구현 되어있나
고려를 해야함, 면접관들은 브로셔를 보고 그렇게 생각할 것임 ! 개선 필요함
질문 3) 대용량 데이터, 트래픽을 고려하여 개발한 부분은?
좌석 조회 캐싱
메인 페이지 내의 공연 정보 캐싱
입찰 정보 조회 시, 레디스를 먼저 조회하여 db에 쓸모없는 요청을 제어
경매 종료 처리
코드 적으로 얘기할 수 있음 → db에 조금 적게 접근하도록 쿼리 작성 등,
질문 4)협업하면서 뭐가 힘들었냐
pr approve 어려움에 대한 얘기 후 그냥 끝내면 안됨, 이렇게 끝내면 코드 리뷰 컬쳐에 어려움만 토로하는 격 → 보완 내용 , 차선책을 두면서 개선하려고 했다~ 이런식으로 가야함