SeongJae Oh

Technology Blog

PM2를 활용한 무중단 배포와 라운드로빈 로드밸런싱, Jenkins를 사용한 깃허브 push작업 시 자동 반영(CI/CD), JWT토큰을 이용한 Stateless 인증, Swagger를 이용한 API 명세 등이 들어가있습니다.

Project Environment

  • NestJS Framework
  • MariaDB / TypeORM
  • JWT / Redis
  • PM2 / Jenkins

프로젝트 개발 동기 및 개요

동료 한 명과 함께 기술블로그를 제작해보자는 취지로 각각 FE/BE로 나뉘어 작업하게 되었고, BE를 담당한 저는 NestJS 프레임워크를 이용한 RestAPI를 제작하였습니다.

DDD(Domain Driven Design) 구조에 이어 TDD(Test Driven Development)를 채택하여 Jest를 이용한 테스트 후 조립하는 식으로 개발하였습니다.

PM2를 이용한 무중단 배포와 2개의 클러스터로 나누어 라운드로빈 로드밸런싱을 하였으며, JWT토큰을 이용한 stateless방식의 인증, 깃허브에 push작업 시 자동으로 서버에 반영되어 재시작되도록 Jenkins를 구성하였습니다.

프로젝트 스크린샷

image
image

Redis

지금까지는 로그인 시 JWT RefreshToken의 재발급과 저장을 위해 Redis를 사용했었지만, 로드밸런싱에 대해 생각을 해보며 트래픽이 몰렸을 때 추가적으로 캐싱 작업도 해주면 좋을 것 같다는 생각이 들어 속도가 빠른 인메모리 방식인 레디스를 사용해서 캐싱의 목적으로도 같이 사용하였습니다.

image
image

PM2

무중단 배포의 목적으로 사용하던 PM2에 클러스터 모드로 클러스터를 늘려 Java 스프링과 같은 다중 스레드를 활용하여 동작시켰습니다. 기본적으로 생성된 클러스터에 라운 드로빈 방식의 로드밸런싱을 지원하며 여러가지 부가설정을 ecosystem 파일을 통해 설정할 수 있습니다.

image
image

Jenkins

젠킨스는 소프트웨어 개발시 지속적인 통합/배포(Continuous Integration/Deployment)를 제공해주는 도구 입니다. 빌드, 테스트, 배포 프로세스를 자동화하여 실서버에 올려 직접 빌드 후 동작시키는 시간을 절약했고 생산성을 높일수 있었습니다. Jenkinsfile을 통해 상세한 옵션 설정이 가능하고, 본 프로젝트에서는 Jenkinsfile을 깃허브에 올려두어 사용하기보다는 Jenkins의 프로젝트 설정에 직접 코드를 작성하여 민감한 ip등의 정보가 노출되지 않도록 변경하였습니다.

image
image

프로젝트 코드 일부

깃허브 저장소 주소로 대체합니다. [Click Me!]

프로젝트 후기

FE/BE로 나뉘어 제대로 된 협업을 경험하고자 동료 한명과 같이 시작하게 되었고, 생각보다 많은 것을 배울 수 있었습니다.

테이블 설계부터 FE와 의견을 맞추어야 했으며, 개발 도중 FE에서 어떤 식으로 바뀌었으면 한다 하는 의견이 있을 때 마다 그에 맞춰 수정 후 매번 서버에 올려 빌드 후 동작시키는 과정이 번거로워 Jenkins를 채택하여 붙여보며 CI/CD에 대한 많은 공부가 되었습니다.

트래픽이 많이 몰렸을 때는 어떻게 해야 할까 또한 많은 정보를 검색하며 해답으로 JWT토큰을 저장하는 용도로 사용하던 Redis를 DB에 가해지는 부담을 줄이고자 Look Aside + Write Around 조합의 캐싱 전략을 채택하여 사용하였고, PM2를 fork모드가 아닌 cluster모드로 설정 후 클러스터를 늘려 자동으로 라운드로빈 로드밸런싱이 되도록 작성하였습니다.

이처럼 단일 장애 지점(SPOF)에 대한 개념을 파악하고 최대한 안정적인 서비스를 운영하려면 어떻게 해야하는가에 대한 물음을 스스로에게 던져보며 많은 배움이 있었습니다.

다른 기발한 아이디어가 있으신가요?

주니어 개발자로써 많은 것을 배우고 제작해보고싶습니다. 현재 프로젝트에 추가되었으면 하는 기능이나, 완전히 새 프로젝트에 대한 아이디어가 있으시면 저에게 연락주시면 감사하겠습니다.