왜 Next JS에서 토했나

펄핏 Perfitt·2022년 3월 2일
7

안녕하세요! 펄핏에서 웹 프론트엔드 개발자로 일하고 있는 jean입니다.
이번 글에서는 작년에 프로젝트를 한창 진행하며 사용했던 Next.js에 대한 이야기를 해보고자 합니다.
Next.js를 사용했던 그 여정은 과연, 행복했을까요?
궁금하시다면 끝까지 이 글을 함께 해주셨으면 좋겠습니다. 😎

1. 당시의 상황

펄핏에서는 웹 프론트엔드 라이브러리로 대부분 React를 사용해왔습니다. 펄핏 홈페이지와 관리자 페이지 등이 전부 React를 이용해 개발된 페이지입니다. 빠르고 간단하게 개발할 필요가 있었고, Single Page Application 구조가 적절했기에 React는 나쁜 선택이 아니었죠.

하지만 당시 새롭게 시작될 프로젝트는 조금 색깔이 달랐습니다. 펄핏은 기존에 어플리케이션에서만 발 사이즈 측정과 신발 판매 등의 서비스를 제공했는데요, 이 창구를 웹으로까지 확대하자는 결정이 이뤄진 것입니다. 한 마디로 E-commerce 웹페이지 개발!

그렇다면 E-commerce에서 중요한 요소는 무엇일까요? 아주 다양한 점들이 있겠지만 저희가 주목했던 요소 중 하나는 검색이었습니다. 많은 사람들이 필요한 물건이 생기면 일단 검색 창에 그 물건을 찾아보곤 합니다. 그렇기에 검색을 하는 순간 회사의 상품이 상단에 노출이 되는지 여부는 꽤 중요한 문제입니다. 한 번이라도 눈에 띄면 구매할 가능성이 현저히 높아질 테고, 구매하지 않더라도 회사 홈페이지가 눈에 익어 홍보 효과가 생길 테니까요. 한마디로 정리하자면 E-commerce에서는 검색 시 상단에 페이지가 노출되는 것, 즉 검색엔진 최적화(Search Engine Optimization, SEO) 가 아주 중요합니다.

하지만 기존에 사용하던 React는 검색엔진 최적화에 썩 뛰어나지 않았습니다. 그 이유는 렌더링 방식 때문인데요, React는 루트 페이지가 되는 하나의 HTML 파일을 두고 Javascript 단에서 가상 History를 이용하여 페이지를 이동시킵니다. 이 방식은 필요할 때만 화면을 갱신하기 때문에 페이지 전환이 빠르고 모바일과 유사한 사용자 경험을 줄 수 있다는 장점이 있습니다. 하지만 정적인 HTML 페이지이므로 검색엔진 로봇이 JavaScript Rendering을 못하면, 하나의 정적인 HTML 파일의 내용만을 검색 인덱스로 가져가서 전체적인 결과에 반영하므로 개별 상품이 조회되는 시점에서의 메타데이터를 파싱하지 않게 됩니다. 결론적으로 개별 상품의 내용이 검색엔진에 반영되지 않는 구조라 일반 소비자들이 상품 정보로 검색했을 때 저희의 상품 화면은 노출될 수 없는 현상이 발생됩니다.

그러므로 저희는 새로운 대안이 필요했습니다. React와 비슷한 구조를 유지하면서도 뛰어난 검색엔진 최적화를 적용할 수 있는 방식. 그것을 찾아내야만 했습니다.


Next.js ?

검색 끝에 찾은 것은 Next.js 였습니다. Next.js는 React를 기반으로 Server-Side Rendering을 쉽게 구현할 수 있게 해주는 프론트엔드 개발 웹 프레임워크입니다. 그 외에도 정적 웹페이지 생성, 간편한 라우팅, 자동 이미지 최적화 등의 기능을 제공하는데요, 저희가 집중했던 부분은 바로 Server-Side Rendering 이었습니다.

앞서 말한 Client-Side Rendering 방식인 React와 반대로, Server-Side Rendering은 서버에서 모든 페이지를 생성해 브라우저로 보내줍니다. 때문에 검색엔진이 정보를 긁어갈 시점에 필요한 정보들이 존재할 테고, 검색엔진 최적화에 유리해지죠. Client-Side Rendering이 최근 React, Vue.js, Angular 등 프론트엔드 프레임워크 및 라이브러리의 부상과 함께 광범위하게 사용되고 있지만, 사실 Server-Side Rendering이야말로 전통적인 웹 렌더링 방식입니다. PHP나 JSP 아키텍처 등에서 이용해왔고, 현재에도 어렵지 않게 찾아볼 수 있습니다. 그리고 Next.js는 React에서 이런 Server-Side Rendering을 쉽게 구현하게 도와주는 프레임워크인 거죠.

다만 Next.js를 사용하자는 결정이 내려졌을 때, 조금 우려되는 점이 있었습니다. 저는 최근 부상한 Single Page Application 프레임워크만을 사용해본 개발자였습니다. 그렇기에 Server-Side Rendering 방식으로 웹 개발을 해본 경험이 없었고 꽤 낯설 것이라 짐작이 되었기 때문이죠.

하지만 막상 Next.js를 사용해보자 그런 우려는 사라져 갔습니다. Next.js는 React를 쓰는 것과 큰 차이점이 없었기 때문입니다. 크게는 Data Fetching 방식 정도가 달랐지만 (Next.js에서는 getServerSiderProps를 이용해 미리 데이터를 불러옴), Next.js 공식 홈페이지에 'The React Framework for Production' 이라고 작성된 만큼 둘은 사용 경험이 유사했습니다. 그래서 React에 익숙했던 저는 어려움 없이 개발을 해나갔습니다. 배포라는 새로운 벽을 마주치기 전까지는 말이죠...

3. 배포라는 새로운 벽

3-1. 이전에 사용하던 방식

기존에 React를 사용할 때에는 Amazon S3에 업로드하여 static file만 호스팅하는 방법으로 배포를 했습니다. 하지만 Next.js는 매번 서버에서 렌더링을 해야 하는 방식이기에 정적 웹사이트 배포에는 어울리지 않았죠.

그렇다면 Serverless 프레임워크를 써서 AWS Lambda에 연결하는 방법은 어떨까요? 펄핏에서 API를 배포할 때에는 Serverless 프레임워크를 사용해왔습니다. Serverless 아키텍처를 구현하기 위한 과정을 자동화해주는 유용한 프레임워크이죠. Next.js를 사용해보며 공통적으로 렌더링 해오는 파일을 function으로 이용해 AWS Lambda에 배포를 할 수 있으리라는 판단이 생겼고, 실제로도 시도해볼 수 있었습니다.

하지만 성공적이라 생각했던 배포 후 맞닥뜨린 것은,
"Background on the 200 resource limit"

에러 메시지였습니다.

해당 에러는 AWS Lambda로 배포하는 과정에서 함께 배포해야 하는 리소스 개수가 200개를 초과하면 발생하는 메시지인데요, 한마디로 배포 용량이 너무 커서 발생하는 문제였습니다. 이때는 프로젝트 초기였고, 앞으로 용량이 더 늘어날 것은 불 보듯 뻔한 일이었습니다. 그렇기에 써오던 Serverless를 포기하고 다른 해결 방안을 찾아야 했습니다.

3-2. Vercel

Next.js는 minor한 서비스가 아니고, 꽤나 많은 기업에서 Next.js를 선택해 사용하고 있습니다. 그렇기에 분명 널리 쓰이는 배포 방식이 있을 것이라 생각한 저는, Next.js 의 공식 홈페이지를 뒤지기 시작했습니다.

역시나 공식 홈페이지에는 배포에 대한 내용이 따로 설명되어 있었고, 그곳에는 무려 Recommended라는 표식이 달린 방법이 있었습니다. 바로 Vercel 이었습니다. Vercel은 Next.js 를 만들어낸 곳임과 동시에 Serverless 아키텍처 구현을 돕는 클라우드 플랫폼이기도 합니다. 같은 뿌리를 가지고 있는 만큼 Next.js 홈페이지에는 Vercel로 배포해~ Next.js에 최적화되어있어~ 라며 저를 유혹했습니다. 마침 Serverless 프레임워크에서 에러를 맞닥뜨리며 지쳐있던 터라 Vercel을 쓰면 배포가 잘 되고 회사가 잘되고 가정이 화목해지고 만사형통이 될 것만 같은 기분에 사로잡혔죠.

그러나 Vercel은 차마 선택지에 넣을 수 없었습니다. 펄핏에서는 Cloud 배포를 하기 위해 전적으로 AWS를 사용해왔는데요, 이 상황에서 Vercel이라는 플랫폼을 하나 더 늘린다면 그만큼 관리 포인트가 많아지게 됩니다. 결과적으로 앞으로를 내다볼 때, 개발자들이 신경써야 할 지점은 많고 복잡해지겠죠. 플랫폼을 하나 더 늘리는 것은 안될 일이었습니다.

3-3. EC2

다음으로 눈여겨본 대안은 EC2 였습니다. EC2는 Amazon Elastic Compute Cloud의 줄임말로, 역시 AWS에서 제공하는 서비스 중 하나입니다. 쉽게 말해 컴퓨터 하나를 임대해 사용하는 클라우드 시스템이라고 할 수 있죠. EC2는 AWS의 심장이라고도 불릴 정도로 널리 쓰이지만, 펄핏에서는 이전까지 사용 경험이 없었습니다. 그렇지만 Next.js 앱 배포에 시도해볼 수 있지 않을까 싶어 후보에 올려두었죠.

그러나 막상 살펴보니 EC2로만 배포를 하면, 향후 확장되는 서비스를 대응하기 위해 용량을 동적으로 증설한다거나, 네트워크 트래픽을 분산하는 관리를 해주어야 하는 등의 이슈를 실시간 대응하기 힘들다는 문제점이 있었습니다. 또 다른 방법을 찾아야 했습니다.


4. 결국 사용한 것은 ECS + Elastic Beanstalk + CloudFront

2주가 넘게 배포와 씨름을 하다보니 저는 점차...

이제 어떻게든 방법을 찾아야 했습니다. 배포 후에도 개발해야 할 것들과 해결해야 할 문제들이 산더미처럼 쌓여있었기 때문입니다. 그래서 저는 결국 솔루션 개발 리드 마니 님을 찾게 됩니다.

그리하여 결국 마니님의 도움을 받아 아래와 같은 과정을 시도합니다.

간략하게 설명하자면 다음과 같이 정리됩니다.

  1. GitLab CI를 통하여 Next JS + Next JS 구동을 위한 NGINX 등을 Docker Image로 만듦
  2. 만들어진 Docker Image를 AWS CLI를 통하여 ECS에 배포
  3. 배포된 ECS를 Elastic Beanstalk에서 가져와서 새로운 EC2를 만듦
  4. Cloudfront에서는 Beanstalk의 Cache작업을 진행

다행히 위 방법을 통해 무리없이 배포를 진행할 수 있었고, 몇 주 간의 배포 여정은 끝을 맺게 됩니다.


5. 결말

이러한 과정을 통해 배포를 했던 E-commerce 웹 페이지는 과연 어떻게 되었을까요? 무사히 개발은 끝났을까요? 아니면 여전히 다른 이슈 속에서 헤엄치고 있는 걸까요?

아쉽게도 E-commerce 프로젝트는 거의 완성이 되었지만 운영 배포를 앞두고 잠정 중단되고 말았답니다. 펄핏 유저 서비스의 목적이 좀 더 사용자 중심의 추천 서비스에 집중하고자 판매 기능의 확장을 조금 미루자는 결정이었습니다. 정말 아쉬운 일이기 그지없으나 이 과정에서 E-commerce 플랫폼의 특징, Server-side Rendering과 Client-side Rendering의 차이, AWS 서비스 각각의 특징 등 많은 것을 배울 수 있습니다. 그렇다면, 충분히 의미 있는 일이 아니었을까요?

그럼 Next.js를 사용하며 고통받고, 또 극복했던 저의 이야기를 마쳐보고자 합니다. 여기까지 읽어주셔서 감사합니다. 펄핏의 1년차 웹 개발자 jean이었습니다!

profile
Beyond The Size Limit

0개의 댓글