1. API 명세에 보면 주문 기능에 대한 API 가 /buy, /sell, /my 이렇게 3가지로 나누어져 있는데요. 주문이면 /orders 가 들어가거나 제품에 대한 동작이라면 /products/{productId}/sell 이런식으로 하는게 더 좋지 않을까요? 어떻게 생각하시나요?
•
동작에 대한 API 설계
◦
Domain으로서 먼저 접근을 하려고 하였습니다. REST API 를 설계하고자 resource 위주로 설계하였기에 각각의 domain 에 따라 API를 구성하게끔 하였습니다.
◦
하지만 말씀해주신 내용을 기반으로 몇 가지 API를 수정할 예정에 있습니다.
▪
가령 즉시구매와 즉시판매 같은 경우, /api/sell/{productId}/now를 사용하여 판매입찰도메인을 사용하기 보다, /order를 사용하는 것이 좋아보인다고 생각합니다.
◦
판매입찰을 sell로, 구매입찰을 buy로 나타내고 있기 때문에 동작으로서 사용되고 있지 않습니다.
2. API 명세에서 하나만 더 말씀드리고 싶은건 판매 입찰내역, 완료내역을 추출할때 경로는 /history 까지만 명시하고 그뒤에 입찰/완료 여부는 쿼리 파라미터로 구현하는게 좋지 않을까요? 어떻게 생각하시나요?
•
쿼리파라미터로 받게 되는 경우, 상태에 대한 정확한 값을 알아야 하기 때문에 두 상태에 따른 API로 분리하였습니다.
•
현재 구매 입찰 상태가 두 가지로 한정되기 때문에, 쿼리파라미터로 분기처리하는 것은 효율적이지 않다고 생각했습니다.
•
하지만 서비스가 확장되어 입찰 상태가 여러가지인 경우에는, /api/buy/history에 쿼리 파라미터로서 상태를 조회하는 방법으로 리팩토링 할 것 같습니다!
3. ERD 상으로는 쿠폰을 주문에 사용했을때 연관관계를 표현하지 못하는 것 같습니다. 쿠폰을 사용하는 기능도 고려해서 주문 데이터와 연관관계를 만든다면 어떻게 만들 수 있을까요?
•
연관관계를 뺀 이유
◦
만약 주문도메인과 쿠폰도메인 간의 연관관계를 만들게 되는 경우, 여러 주문에 대해 여러 쿠폰이 사용될 수 있으므로, 다대다 연관관계를 사용해야합니다.
◦
이는 기존에 하나의 주문에 대해 구매자,판매자,상품에 대한 조인에 추가적인 쿠폰 조인 연산까지 처리해야하는 오버헤드를 발생합니다.
◦
현재 정책과 앞으로의 정책을 미루어보았을 때, 쿠폰은 단지 가격에 대한 할인의 역할을 해주는 도메인일 뿐, 주문과 쿠폰과의 연관관계를 나타내어 데이터로 저장할 필요가 없다고 생각합니다.
◦
따라서 저희는 쿠폰에 대해서 팩토리 혹은 ENUM을 사용하여 할인정책에 대한 할인만 연산수행하기로 하였습니다.
•
만약에 연관관계를 만들게 된다면
◦
다대다 연관관계를 만들어서 외래키값을 설정한 뒤,
◦
해당 외래키값을 Nullable하게 설정하고,
◦
쿠폰과 주문과 상품과 유저를 조인을 통해 요청을 처리할 것 같습니다.
◦
만약 조인 오버헤드가 심하다면, 주문에 대한 어그리거트를 도큐먼트 형식으로 표현하여 저장할 것 같습니다.
4. 아키텍쳐 상으로는 프론트 배포에 대한 내용이 안보이는데요. 프론트 배포 과정에 대한 설명을 추가로 해주세요.
•
재윤
◦
프론트는 팀원 1명이 담당하기로 해서, 깃 브랜칭 전략은 따로 없이 main 브랜치에 바로 푸쉬하도록 하였고, github action을 이용하여 main 브랜치에 푸쉬가 되면 빌드 후 AWS S3에 정적 파일들이 배포가 됩니다. 그리고 cloudFront에서 S3의 파일에 접근하여 사용자가 이용할 수 있도록 하였습니다.
◦
이를 통해 수동으로 S3에 배포할 시간을 줄여서 코드 작성에 더욱 시간을 쏟을 수 있었으며, 또한 클라우드프론트에 배포까지 함으로써 사용자는 지리적으로 가까운 캐싱 서버로부터 정적 파일을 내려받아 빠르게 이용할 수 있게 되었습니다.
5. 도커 스케일 아웃을 구현하셨다고 되어있는데 수동으로 스케일 아웃하는지 자동으로 하는지 자동으로 한다면 어떻게 할 수 있을지 얘기해주세요.
•
현재는 아키택처가 바뀌어서 nginx가 아니라 AWS Application Load Balancer를 이용한 자동 오토 스케일링을 적용했습니다.
•
Nginx에서 AWS Load Balancer로 아키텍처를 변경하였습니다.
•
이유로는 Nginx의 설정 허들이 AWS Load Balancer 보다 높지만 설정 허들에 비해 성능이 동일하거나 비교적 낮기 때문입니다.
•
현재 타켓그룹에 대한 인스턴스 증가 설정을 자동으로 설정하였습니다
•
인스턴스에 부하가 생기면 최소 1개에서 최대 3개까지 인스턴스가 늘어나도록 설정했으며 추후 부하테스트를 통해 인스턴스를 늘려나가며 트래픽에 대한 대응책을 마련할 예정입니다. (지훈)
6. MySQL DB를 Master&Slave 구조로 구성해주셨는데요 각각의 역할이 무엇이며 Master 에서 장애가 발생했을 경우 어떻게 조치해야할 지 과정을 설명해주세요.
•
규정
◦
DB를 Master와 Slave로 나눈 이유는 DB에서 장애가 났을 때를 대비한 것 입니다. Master는 가장 주된 데이터베이스로 메인 데이터베이스라고 생각하면 될 것 같습니다. 역할은 데이터베이스의 쓰기 / 수정 / 삭제를 맡고 있으며, Slave는 데이터베이스를 읽는 역할을 합니다. 만약 Master에서 장애가 발생할 경우 추가적으로 있는 Slave 중 한 DB를 Master로 승격시키는 것으로 장애를 극복하려고 합니다. (지훈)
7. Gihub 이슈나 PR 을 잘 정리해주시고 서로 리뷰도 잘 남겨주셨는데요. 서로 리뷰해주면서 좀더 좋은 방법을 찾고 개선한 경험이 있다면 대표적으로 한개만 얘기해주세요.
•
규정
◦
메서드 안에서 분기를 나눌 필요성이 있을 때 if문 안에 직접적으로 그 조건을 넣어서 작성해 주었으나 그렇게 했을 때 코드의 가독성이 떨어지고, 이 조건이 어떤 것을 나타내는지 명확하지 못한 경우가 존재하였습니다. 그러한 조건 자체를 다른 메서드로 빼서 작성하여 가독성을 올리고 하나의 메서드가 어떤 일을 너무 도맡지 않게 하며, 여러 메서드로 분할하여 추후에 새로운 메서드에서 그 메서드가 필요한 경우 사용할 수 있게되는 유연성을 갖게 하는 경험이 좋았습니다. (지훈)
•
재윤
◦
깃허브 PR을 남기는 과정에서 PR 하나에 여러 작업이 들어있어서 커밋 및 파일 변경이 수십 건이 있어, 리뷰하기 어려워지고, 또 리뷰하기 어려워서 PR이 머지되지 않고 시간이 지나게 되고, 또 시간이 지나면서 더욱 작업이 쌓이는 문제가 있었고, 이로 인해 메인 브랜치와의 차이가 벌어지게 되는 문제가 있었고, 이를 해결하고자, PR에는 1가지 작업만 하고, 1커밋 1파일변경만 있어도 되니 적은 분량으로 자주 머지하여 리뷰어가 리뷰하기 부담이 없도록 하여 빠르게 머지하도록 하였고, 이로 인해 메인 브랜치와 작업 브랜치 간의 차이를 최소화 하여 충돌을 방지하여 작업을 빠르게 진행할 수 있었습니다. (지훈)
8. Github 레파지토리에서 커밋 이력을 보면 “fix : Dockerfile 수정” 이런식의 수정 내용을 알 수 없는 커밋 메시지가 반복적으로 수십번씩 사용되는 경우가 있는것 같은데 커밋 메시지의 목적이 뭐라고 생각하시나요?
•
의미있는 커밋 메세지를 남기지 못하였습니다. CICD 과정에서 알 수 없는 문제들이 연속으로 발생하였고 그중 도커파일이 제대로 실행이 되질 않아서 수정을 많이 했었습니다. 바뀐 코드들로 github actions를 실행 시키려면 커밋을 진행해야 했습니다. 다음에는 좀더 정확하게 문제를 해결해서 반복되는 작업들을 없에고, 커밋 메시지의 바디 부분에 상세한 변경 내용을 작성하여 의미 있는 커밋 메세지를 남기겠습니다.
9. 쿠버네티스 배포전략이 여러개 있는데 그것들은 어떤것들이 있으며, 그중에 Blue/Green 를 선택한 이유에 대해서 설명해주세요.
•
다양한 배포 전략이 있으며 크게는 롤링 업데이트, Blue/Green, 카나리 등이 있습니다. 이중에 Blue/Green을 선택한 이유는 배포시 새 버전에 오류가 생길 경우 빠르게 blue로 트래픽을 변경하여 Roll Back 시킬 수 있고, 한번에 트래픽이 옮겨 가기 때문에 이전 버전과의 호환성을 고민하지 않아도 되며, AWS Load Balancer 생성시 Blue/Green을 선택할 수 있어서 빠르게 무중단 배포를 도입할수 있었기 때문입니다.
10. 단일 장애 지점 제로를 목표로 설계하고 개발하고 계신것으로 보이는데요. 단일 장애 지점이 발생하지 않도록 고민한 부분과 적용한 부분이 있으면 설명 부탁드립니다. :)
•
원래는 EC2에서 클러스터링이나 MySQL Master/Slave 을 구현하려고 했으나, 밑바닥부터 작업을 하기보다, 이미 시중에 잘 나와있는 서비스를 적극적으로 이용하여 서비스의 볼륨을 키우는 쪽으로 방향을 틀었습니다.
•
장애가 발생할 시나리오를 예상하여 장애가 날만한 지점을 파악하고, 이를 AWS의 서비스로 어떻게 극복을 할 수 있을지를 알아보고 고민해보았습니다. (서버에 트래픽이 과도하게 몰려서 서버가 죽었을 때 어떻게할지, DB에 데이터가 과하게 몰렸을 때 어떻게 할지 등등..)
•
현재는 CloudFront, 로드밸런서, 오토 스케일링, 무중단 배포, ECR 를 이용하였고, RDS를 master/slave 를 구현하고, EC2에 Redis를 띄운 것을 Elastic Cache를 사용하여 단일 장애 지점을 없애는 것을 목표로 하고 있습니다.
•
배경 문제 해결 결과
•
서비스 특성상 현금성 자산을 주고받으며, 높은 트래픽과 복잡한 로직 처리 과정에서 장애가 발생할 시 회사와 사용자 모두에게 치명적인 손실을 끼칠 수 있다고 판단해서, 장애가 나지 않도록 하는 것이 가장 중요한 요소로 꼽았다.
•
우선은 시중에 잘 나와있는 서비스 정도의 기술을 기한 내에 구현하기에는 무리가 있다고 판단하여 AWS의 Saas를 적극 이용하고자 하였다
•
아키텍처를 대략적으로 그린 뒤 장애가 날만한 지점을 파악하였고, 이를 시중의 어떤 서비스로 대체를 할 수 있을지를 고민하고, 적용을 해보았다.
•
그 결과로, CloudFront, 오토 스케일링, 무중단 배포를 구현하여 장애지점을 제거하였으며, 이후로 RDS를 Master/Slave 구조로 변경하고, EC2에 띄운 Redis를 ElasticCache로 전환하여 완전히 단일 장애지점을 없애는 것을 목표로 하고 있습니다.