고성능, 확장가능한 nodejs 앱을 위한 Good Practice [Part 2/3 번역]

QQQ
nodejs backend
Published in
5 min readMar 21, 2021

This post is from [ original post ]

Chapter 2 — 확장 전 준비 사항

이전 글에서 코드에 대한 고민없이 어떻게 Nodejs 앱을 수평 확장시키는지 알아봤습니다. 이번에는 확장을 할 때 일어날 수 있는 일들을 최대한 방지하기 위해 고려해야할 것들을 살펴보겠습니다.

Decouple application instances from DB

첫번째 힌트는 코드에 관한 것이 아니라 인프라에 관련된 것입니다.

만약 어플리케이션이 여러 호스트에서 확장될수 있길 원한다면, 데이터베이스를 독립적인 머신에 배포해야합니다. 그래야만 자유롭게 어플리케이션 머신을 필요한만큼 복사할수 있습니다.

데이터베이스와 어플리케이션을 같은 머신에 배포하는 것은 비용이 덜 들고, 개발 상황에서 편하지만, 실제 서비스에서는 추천되지 않는 방식입니다. 어플리케이션과 데이터베이스는 독립적으로 확장가능해야만 합니다. 인메모리 방식의 데이터베이스인 redis 또한 그래야만 합니다.

Be stateless

여러개의 인스턴스로 어플리케이션을 만들어둔다면, 각각의 프로세스는 각자만의 매모리 공간이 있게 됩니다. 이 말은 즉, 만약 한개의 머신에서 글로벌 값으로 혹은 메모리안에 session으로 값을 저장했을 때, 다른 머신에서는 그 값에 접근할수 없을 수도 있다는 뜻입니다.

설정 사항이 바뀔 수 있는 상황에서의 해결책은 데이터를 외부 데이터 베이스에 저장하는 것입니다.

Stateless authentication with JWT

인증은 stateless 앱을 배포할때 생각하게 될 첫 번째 주제입니다. 만약 session들을 메모리에 저장하게 된다면, 싱글 프로세스로만 접근 가능 범위가 한정됩니다.

제대로 작동하게 만들려면, 네트워크 로드벨런서를 반드시 개별 유저의 요청을 매번 같은 머신에서 동작하게끔 설정해야합니다. 또한 같은 프로세스로만 요청하게 해야합니다.

이 문제에 대해서 간단한 해결책은 세션 저장 방식을 지속가능한 저장소로 바꾸는 것입니다. 예를 들면 RAM에 저장하는 대신에 데이터베이스에 저장하는 것입니다. 그러나 이 방식은 모든 API 요청에 대해 데이터베이스에서 권한을 확인해야하기 때문에 성능면에서 좋지 않습니다.

더 좋은 방식은 session 정보를 in-memory 방식의 데이터베이스(like Redis)에 저장하는 것입니다. Redis는 보통의 데이터베이스와 같이 외부에 존재하지만, 외부에 존재함에도 불구하고 속도면에서 비교할 수 없을만큼 빠릅니다. 그리고 session들을 RAM에 저장하는 것은 세션의 갯수가 많아질수 있기 때문에RAM활용에 좋지 않습니다.

다른 효율적인 방법으로 JSON Web Token이 있습니다.

JWT의 핵심 아이디어는 간단합니다: 유저가 로그인 했을때, 서버는 payload(유저 정보들)가 포함된 JSON 객체의 base64 인코딩 토큰을 발행합니다. 페이로드(유저 정보들)는 유저 정보와 권한에 관련된 정보를 가지고 있고 서버가 가지고 있는 비밀키로 해싱된 상태입니다. 예를 든다면 userID, 유저가 가진 권한 리스트가 있습니다. 토큰은 유저에게 전달되고 모든 API 요청에 대해 인증할 때에 사용됩니다.

서버가 요청을 처리할 때, 토큰의 payload를 받고 secret key를 이용하여 비교합니다. 만약 비교된 값이 같다면 토큰안의 정보들은 유효한 것으로 인증되고 올바른 유저로 식별됩니다.

JWT는 어떠한 방식으로도 암호화를 제공하지 않는다는 점이 중요합니다. 토큰안에 저장되는 정보들(payload)는 단지 base64 방식으로 인코딩되고 순수한 text 방식입니다. 만약 값이 숨겨지길 바란다면 SSL을 이용하길 바랍니다.

아래 이미지는 jwt.io 에서 가져온 것입니다.

인증 과정동안 서버는 어떠한 세션 데이터도 접근할 필요가 없습니다. 그러므로 각각의 요청들은 여러 과정, 여러 머신에서 처리될 수 있게 됩니다. 어떠한 데이터도 RAM에 저장되지 않습니다. 그리고 저장소에 I/O할 필요도 없습니다. 그러므로 이 방식은 확장에 있어 매우 유용합니다.

Properly configure WebSockets

만약 어플리케이션이 real-time을 위한 WebSocket을 이용중이라면 여러 메시지들을 전파하기 위해 백엔드 인스턴스들을 연결시켜야만 합니다.

Socket.io 라이브러리는 “socket.io-redis”라는 것을 제공해주는데 이것을 이용하면 쉽게 서버들을 연결시킬 수 있습니다.

멀티 노드 socket.io 환경을 사용하기위해선 프로토콜을 “websockets”로 강제 설정하기도 해야합니다.

다음 단계

이번 짧은 글에서 nodejs 앱을 확장하기전에 필요한 간단한 것들을 살펴봤습니다. 다음 글에서는 확장성에 도움이 되는 패턴들을 살펴볼 것입니다.

This post is from [ original post ]

--

--