본문 바로가기

🎒 Activity/팀진저

[Team Ginger] 크리스마스에도 코딩을 하는 사람이 있다?

저는 어드벤트 캘린더 형식의 크리스마스 익명 편지 서비스인 "Ginger Hotel 🎄"의 2023년 이야기를 적어볼까 합니다.

 

 

🛠️ 팀진저의 백엔드에서는 이런 기술 스택을 선택했습니다.


저는 백엔드 개발을 맡아서 진행하게 되었습니다. 가장 먼저 했던 것은 기술 스택을 선택하는 일이었습니다.

 

 

팀진저에서 선택했던 백엔드 기술 스택은 Nest.js, Typescript, PostgreSQL이었습니다.

 

"Java, Spring으로 공부하고 계신데 왜 Node 기반의 기술 스택을 선택하게 되었나요?"

 

저에게도 큰 도전이었던 것 같습니다. 팀원 한분이 풀스택으로 참여를 희망하셨어서 Front-End 개발팀에서 선택했던 언어인 Typescript에 맞추기 위함이 가장 큰 이유였습니다.

 

저도 처음 사용해 보는 기술 스택들이었기 때문에 신중하게 선택을 했었습니다.

 

Typescript의 경우에는 타입의 안정성을 고려하며 개발할 수 있어서 언어 선택에 있어서는 주저함이 없었습니다.

 

프레임워크는 Nest.js를 선택했던 이유는 모듈 단위로 나누어 개발을 할 수 있고, 확장성에 있어서도 부족함이 없다고 생각했습니다.

또한 Spring가 굉장히 유사한 구조를 가지고 있어 러닝커브를 빠르게 극복할 수 있다고 판단했습니다.

 

그리고 개발을 하며 느꼈던 점은 npm에 정말 유용한 라이브러리가 많아서 부족함 없이 개발을 했던 것 같습니다.

 

마지막으로 데이터베이스는 PostgreSQL을 선택했습니다. 가장 큰 이유는 진저호텔에서는 Member -> Hotel -> HotelWindow -> Letter -> Reply와 같이 굉장히 깊은 연관 관계의 Depth가 있었습니다.

 

그래서 Join과 같은 연산 처리 능력이 뛰어난 데이터베이스를 고려해야 했습니다. 또한 2022년 진저호텔(편지 약 650만 개)이 가지고 있는 데이터를 무시할 수는 없었기 때문에 대용량 데이터에서 성능이 좋은 데이터베이스를 찾다 보니 Oracle과 PostgreSQL을 찾게 되었습니다.

 

저희는 클라우드 플랫폼으로 AWS를 사용하기로 결정이 된 상태이기 때문에 라이센스 비용 또한 고려해야 했기 때문에 라이센스 비용이 무료였던 PostgreSQL을 최종적으로 선택하게 되었습니다.

 

 

 

☁️ 팀진저의 클라우드 이야기


제가 이번 프로젝트에서 얻어가고 싶은 경험 중 하나가 "클라우드 플랫폼"을 이용하여 서버를 운영해 보는 경험이었습니다.

그래서 개발보다도 더 많은 시간을 쏟으면서 찾아보고, 적용해보고 했던 것 같습니다.

 

 

처음 구성 했던 아키텍처는 위와 같습니다. 구글링을 통해서 구성해 봤던 아키텍처였습니다. (AWS는 맨날 EC2 만 써봐서...)

 

Application Load Balancer는 부하 분산을 위해 EC2를 증설할 계획을 가지고 있었는데, 그래서 미리 적용해 두게 되었습니다.

여기서 Cloud Front는 본래 용도는 CDN 서버로 자주 사용되는 데이터를 캐시 하여 비용을 줄이는 용도로 많이 쓰인다고 합니다.

 

하지만, 지금 현재 아키텍처에서는 Cloud Front가 캐시의 역할이 아닌 그냥 AWS Certificate Manager와의 상호작용을 통해 SSL 인증서를 확인해 주는 역할 밖에 하지 않았습니다.

 

이대로 서비스에 나간다면 Cloud Front를 거치는 비용이 계속 나갈 것으로 판단되었고, 멋쟁이 사자처럼 대학 동아리에서 인연이 있었던 높으신 분께 현재 상황에 대한 피드백을 요청했었습니다.

 

Cloud Front 제거

 

얻은 피드백에서는 Load Balancer에서도 AWS Certificate Manager와 상호작용할 수 있는 방법이 있다는 것이었습니다.

[aws] ELB Application Load Balancer를 이용한 SSL 설정

 

[aws] ELB Application Load Balancer를 이용한 SSL 설정

이번 포스트에서는 AWS ELB application load balancer를 이용해 SSL을 적용 하는 방법을 정리한다. 즉 이 포스트의 목적은 아래 Fig 1과 같은 architecture 로 서버 운영 구조를 완성하는 것이다. 이 구조를 간

pajamacoder.tistory.com

 

이렇게 되면 기존 Cloud Front를 떼어내서 아키텍처가 가벼워지고, Cloud Front에서 과금될 비용들을 다른 곳에 쓸 수 있게 되기 때문에 바로 적용하게 되었습니다.

 

 

Cloud Front를 떼어내고 난 후의 아키텍처입니다. 생각보다 빠르게 떼어낼 수 있었습니다.

비용도 줄이고, 서버 아키텍처가 더 간결해지고, 깔끔해질 수 있었습니다! ✨

 

CI/CD 파이프라인에 Docker 적용

 

기존에는 CI/CD 과정에서 Github Actions로 EC2에 접근하여 미리 적어둔 스크립트를 실행시키도록 해두었습니다.

즉, EC2에서 프로젝트 build 작업까지 하다 보니 인스턴스에 부하가 모이게 되는 것 같았습니다.

그래서 Docker Image를 이용하기로 했습니다.

관련된 내용은 따로 글에 정리를 잘해뒀습니다. 

 

https://hoonsb.tistory.com/98

 

[Github Actions x Docker] 자동화 배포 환경 도커로 변경하기

1. 기존 아키텍처와 배포 스크립트 분석 프로젝트 진행 과정에서 초반에 간단한 인프라 설계를 위처럼 진행했습니다. 먼저 EC2(Ubuntu) 내부에 Node 16 버전을 포함해서 필요한 것들을 모두 수동으로

hoonsb.tistory.com

 

EC2 인스턴스 추가, RDS Multi-AZ 다중화 배포 적용

 

진저호텔 서비스를 운영하는 데 있어서 가장 중요하게 여겼던 것은 2가지가 있습니다.

  1. 사용자들이 주고받은 편지를 안전하게 보관하자!
  2. 사용자들이 서비스를 이용하는 과정에서 끊기지 않도록 중단 없이 확장할 수 있는 서버를 만들자!

먼저 서버 중단 없이 기능을 확장하고, hotfix를 처리하기 위해서 EC2 인스턴스를 추가하여 Load Balancer의 대상 그룹에 추가했습니다.

이렇게 구성하고, 하나의 서버에 배포 변경 사항을 적용하고 Health Check가 통과되었을 때, 다른 하나의 서버를 배포하게 되었습니다.

이렇게 진저호텔은 12월 한 달간 한 번의 서버 중단 없이 서비스를 유지할 수 있었습니다.

 

그다음은 데이터 백업입니다. 기존 RDS는 Single-AZ로 하나의 Availability Zone을 사용했기 때문에 데이터 백업 중에는 데이터베이스가 중단된다는 문제점이 있었습니다. 중단 없이 백업할 수 있는 방법은 없을까 방법을 찾다가 AWS RDS에서는 "Multi-AZ 다중화 배포" 옵션을 제공했고, master DB와 standby DB가 있어서 백업의 경우에는 standby에서 진행되어 master DB는 계속 중단 없이 사용할 수 있게 됩니다. 또한 master DB에 문제가 생겼을 때, standby DB가 바로 master로 승격하게 되면 장애 대응에도 신속한 특징을 가지고 있어 운영 환경에서는 적용하게 되었습니다.

 

이렇게 변경한 후의 아키텍처는 다음과 같습니다.

 

서버 인스턴스의 상태를 모니터링하자.

 

이 부분은 운영 환경에서는 필수라고 여겨지는 부분이라 현재 팀진저에서 소통 수단으로 쓰고 있던 Discord의 Web Hook과 AWS의 CloudWatch를 연동하여 사용하기로 결정했습니다.

 

서버 모니터링이 중요했던 이유는 RDS의 경우 만약 쿼리 병목이나 슬로우 쿼리가 발견되어 과도한 부하가 걸리게 되거나, 요청에 대한 처리 속도가 늦어지게 되는 경우를 조기에 발견하고 대응해야 된다고 생각되었습니다.

 

그래서 CloudWatch에 EC2, ALB, RDS에서 감지할 옵션들의 임계값을 설정하고, 임계값을 넘어선 경우에 AWS SNS를 통해 AWS Lambda에서 Event를 받아 Discord로 알림을 바로 줄 수 있도록 구성했습니다.

 

 

이렇게 서버 인스턴스 모니터링 과정을 거치게 되면 다음과 같은 메시지(경보)를 Discord에서 확인하고, 바로 대응할 수 있습니다.

 

제가 무적 짱짱맨이어서 24시간 안 자고, 계속 서버만 모니터링할 수 있다면 좋았을 텐데 저는... 무적 짱짱맨이 아니기 때문에 다른 팀원들의 눈과 귀를 빌리고자 Discord를 적극적으로 사용하게 되었습니다.

 

 

 

✉️ 편지, 답장 차단 프로세스에 대한 고민


작년에 편지 차단에 대한 피드백이 굉장히 많았었습니다. 그래서 올해는 편지 차단 기능에 힘을 많이 쓰게 되었습니다.

차단 기능에 있어서 익명 편지 서비스이다보니 편지를 보낸 사람이 누구인지 특정할 수 없도록 하는데 고민을 많이 했었습니다.

고민 했었던 부분은 한 명이 여러 닉네임으로 편지를 보냈을 때의 상황이었습니다. 위 예시를 보면 "헤르미온느"와 "론"으로부터 받은 편지가 있습니다. "헤르미온느"와 "론"은 모두 훈섭이라는 사람이 보낸 편지입니다.

 

만약 기존에 생각하고 있던 프로세스로 편지를 받은 철수가 훈섭을 차단했을 때, block_history 테이블에 차단한 사람은 철수, 차단당한 사람은 훈섭으로 하게 되었을 때 아래와 같은 고민이 있었습니다.

 

철수가 "헤르미온느"를 차단했는데, "론"에게 받은 편지도 차단된다면, 철수는 "헤르미온느"와 "론"이 같은 사용자라는 것을 유추할 수 있게 됩니다. 그래서 차단 프로세스에서 차단 횟수를 넣게 되었습니다.

 

각 편지는 별개로 차단을 할 수 있고, 발신자에 대한 차단을 횟수로 관리하여 편지 차단을 진행합니다. "헤르미온느"에게 온 편지를 차단하면 차단한 사람은 철수, 차단당한 사람은 훈섭 그리고 차단 횟수가 1이 됩니다. 이렇게 되면 훈섭은 철수에게 편지를 보낼 수 없고, "헤르미온느"에게 온 편지를 차단했을 때, "론"에게 온 편지에는 어떠한 영향도 주지 않기 때문에 "헤르미온느"와 "론"이 같은 발신자라는 것을 유추할 수 없게 됩니다.

 

반대로 차단을 해제하게 되면 차단 횟수는 감소하게 됩니다.

 

"론"에게 받은 편지에 대한 차단을 해제했을 때는 아직 훈섭(헤르미온느)에게 받은 편지를 차단한 상태이기 때문에 훈섭에게는 편지와 답장을 받을 수 없습니다.

 

"헤르미온느"에게 받은 편지까지 차단 해제를 하면 철수가 훈섭을 차단했던 횟수가 0이 되기 때문에 해당 데이터는 사라지게 됩니다. 이제는 훈섭이 철수에게 편지를 보낼 수 있게 됩니다.

 

 

 

 

대부분 인프라 관련된 클라우드 이야기였지만, 제가 프로젝트를 진행하며 느꼈던 내용과 왜 이런 결정을 했는지에 대해서 기록해두고 싶어서 정리하게 되었습니다.

 

여기까지 2023년 진저호텔의 백엔드 개발 이야기를 풀어봤습니다. 🎄