Project 4 #1 / TIL

System Design

Featured image

개요

Github나 Slack과 비슷한 방향으로 업무를 효과적으로 해결하기 위한 관리 도구를 만들어보기로 했다. 특정 업무에 대해 각자 역할을 나누어 업무를 분배하고 진행상황을 관리할 수 있고, 업무 수정시 사용자에게 업무 변경 알림을 보내는 시스템을 구축할 것이다.



요구사항

Task Management Tool 기능 요구사항

필요한 리소스

인프라 요구사항



CRUD API

이번 프로젝트에 프론트와 백엔드는 자세히 구현하지 않을 것이기 때문에, CRUD API 명세는 간단하게 필요한 기능만 넣어서 작성하였다.

URL Method Function Req Res
/api/sign_in GET 로그인 요청 { “email”: “(email)”, “password”: “(password)” } { “message”: “사용자가 성공적으로 로그인했습니다.”, “email”: “(email)”}
/api/tasks POST 작업 추가 { “Task_name”: “(Task_name)”, “Task_contents”: “(Task_contents)”, “Task_status”: “(Task_status)”, “Deadline”: “(Deadline)”, “PIC”: “(PIC)”, “Supervisor”: “(Supervisor)” } { “message”: “작업이 성공적으로 생성되었습니다.”, “Task_id”: “(Task_id)” }
/api/tasks/(task_id) PUT 특정 작업 수정 { “Task_contents”: “(Task_contents)”, “Task_status”: “(Task_status)”, “Deadline”: “(Deadline)”, “PIC”: “(PIC)” } { “message”: “작업이 성공적으로 업데이트되었습니다.” }
/api/tasks/(task_id) DELETE 특정 작업 삭제 { “Task_id”: “(Task_id)” } { “message”: “작업이 성공적으로 삭제되었습니다” ,”Task_id”: “(Task_id)”, “Task_name”: “(Task_name)”}
/api/tasks GET 전체 작업 조회   { “message”: “전체 작업 조회” }



Domain Driven Design

다음은 처음했던 도메인 주도 설계이다.

기존에는 업무 관리 시스템과 알림 시스템으로 분리하였었는데, 두 시스템의 분리 근거가 명확하지 않았다. 알림 시스템이 그냥 email, messanger 등으로 전송하는 것에 불과하다면, 별도의 시스템으로 불릴 이유는 없었다.

따라서 메인 애그리거트인 Task 위주로 항상 이벤트가 발생하게 하고, 그 이벤트를 전부 별도의 system으로 보내서, 분석용으로 사용하는 것도 괜찮을 것이라고 생각했다. 분석용으로 사용함으로써, Task를 만들고 달성한 비율 같은 것을 분석하여 성과 관리 시스템으로도 확장할 수 있을 것이다.

또한 업무 분석 시스템은 업무 관리 DB를 갖고, 별도의 system(알림 전송/Log 저장)은 로그 분석용 DB를 가져서 구현하는 것도 이후의 확장성을 생각하면 좋은 방안인것 같다.

이런 방안들을 통해 시스템 분리의 당위성이 조금 더 생길 것이라고 생각했다.

또한 로그인 시스템또 별도로 분리하기로 결정했다. 그 이유는, 로그인 이후 업무 관리 시스템으로 라우팅하게 되고, 만일 로그 시스템이 별도의 CRUD를 갖는다면, 로그인 이후에 로그 시스템으로도 라우팅이 가능하게 되기 때문이다.

이런 피드백을 적용한 DDD는 다음과 같다.

위에서 말한대로 로그인 시스템은 이후 확장성을 위해 따로 분리하였고, 업무 종료에 대한 커맨드와 이벤트로 추가되었다. 업무가 수정되면 업무 변경 사항에 대한 Log를 로그 관리자 액터로 전달하게 되고, 그 로그를 DB에 축적하고, 로그 상황에 맞는 알림 메시지를 사용자 혹은 시스템 관리자(나)에게 전송하게 된다.



Resource Architecture

초기에 작성한 아키텍처에 대한 설명을 적어봤다. (잘못된 부분이 있음 : 소괄호 안의 내용 - 보완이 필요한 부분)

유저가 Route53을 통해 레코딩된 도메인으로 접속하면 s3로 정적 호스팅된 사이트로 접속하게 된다. 사용자는 ECS를 통해 (EC2로) 배포 중인 컨테이너로 접속하여 업무 내용을 작성, 수정, 삭제 등을 할 수 있다. ECS에 배포될 이미지는 Git Action을 통해 배포를 자동화 시킬 것이고, ECR을 통해 ECS로 배포된다. ECS에서 사용자가 작업 추가 및 수정을 할 경우 (EC2를 통해) RDS에 그 내용이 저장되고, 업무 내용이 변경될 시 SNS을 통해 SQS로 업무 변경 내용을 통보한다. 그리고 SQS를 트리거로하는 Lambda를 통해 SES로 업무 상태 수정사항에 대한 내용을 사용자에게 메일로 전달하게 된다. 만일 업무 변경 통보를 실패할 경우 실패한 메시지는 DLQ로 이동하여 Developer Lambda를 통해 개발자 팀의 디스코드 채팅으로 알림을 준다.


초기 아키텍처에 대한 피드백

  1. 기존 아키텍처에서 보완해야 할 부분은 사용자의 요청을 ECS로 보내는 것이 아니라, ECS에서 EC2로 컨테이너 배포를 하는 것이고, EC2에서 RDS를 다룬다는 것이다. ECS를 컴퓨팅 유닛이 아니기 때문에 메인 컴퓨팅 부분에 ECS, EC2, Auto Scaling의 표현(+subnet)을 제대로 하는 것이 중요하다.

  2. DDD에서 로그를 이용해 업무 성과 관리 측면까지 확장하였기 때문에, SNS의 이벤트를 구독해서 저장할 수 있는 데이터베이스(nosql)가 필요하다.

  3. 기존 아키텍처에서는 API Gateway를 사용하였는데, Application LoadBalancer로 교체하는 것에 대한 고려를 해보았다. 이 시스템이 제공하는 기능 측면에서 고려했을 때 다양한 기능을 제공하는 API Gateway보다는 로드 밸런서를 이용해 트래픽 분산 쪽에 중점을 두는 것이 좋을 것 같다고 생각했다.

  4. 프론트 부분에서 CloudFront 사용도 고려해보았다.

  5. RDS 가용성 부분에서 다중 AZ를 이용해 만일 기존 DB 인스턴스에 중단이 발생했을 때, 자동으로 다른 가용 영역에 있는 복제본을 사용해 서비스를 계속 제공할 수 있도록 하는 방안을 생각하였다. 이 방안을 통해 트래픽을 오프로드하고 성능을 향상하는 데에 좋을 것 같다고 생각했다.

  6. 이벤트 로그 저장소 DB는 가장 바쁘게 일하는 곳이기 때문에 읽기 쓰기 처리 속도가 빨라 접속이 많이 발생해도 견딜 수 있는 DynamoDB 이용에 대해 고려해 보았다.

  7. 리소스 사용량 모니터링은 Cloudwatch를 이용한다.


피드백을 고려하여 수정한 아키텍처이다. 바뀐 아키텍처에 대한 설명은 위에 작성하였던 초기 아키텍처 설명을 수정하였다.

유저가 Route53을 통해 레코딩된 도메인으로 접속하면 CloudFront를 통해 s3로 정적 호스팅된 사이트로 접속하게 된다. 사용자는 ECS를 통해 EC2로 배포 중인 컨테이너로 접속하여 업무 내용을 작성, 수정, 삭제 등을 할 수 있다. ECS에 배포될 이미지는 Git Action을 통해 배포를 자동화 시킬 것이고, 이미지는 ECR을 통해 ECS로 배포된다. ECS에서 사용자가 작업 추가 및 수정을 할 경우 EC2를 통해 RDS에 그 내용이 저장된다. EC2 인스턴스와 RDS 인스턴스 사이에 NAT 게이트웨이를 연결함으로써 EC2 인스턴스와 RDS 인스턴스가 각각의 안전하고 격리된 환경(프라이빗 서브넷) 내에 유지되는 동시에 EC2 인스턴스의 아웃바운드 트래픽에 필요한 인터넷 연결을 계속 활성화하도록 한다. 업무 내용이 변경될 시 SNS을 통해 SQS로 업무 변경 내용을 통보한다. 그리고 SQS를 트리거로하는 Lambda를 통해 SES로 업무 상태 수정사항을 사용자에게 메일로 전달하게 된다. 또한 NoSQL인 DynamoDB에 업무 상태 수정에 대한 로그를 저장한다. 만일 사용자가 없어질 경우 메시지가 전달될 수 없으므로, DLQ로 이동하여 Developer Lambda를 통해 개발자 팀의 디스코드 채팅으로 시스템 이상에 대한 알림을 준다.



ERD