Rails 앱을 배포하는 방법을 찾아보다 보면 Apache, Unicorn, Puma, Phusion Passenger, Nginx, Rainbows 등 수많은 이름을 마주하게 됩니다. 이 도구들은 모두 "Rails 배포"라는 범주에 속해 보이지만, 그 사이에는 중요한 차이가 있습니다. 어떤 것은 웹 서버이고, 어떤 것은 앱 서버입니다.
두 개념의 차이와 각각이 시스템에서 담당하는 역할을 이해하면, 배포 과정이 훨씬 명확하게 다가옵니다. 다만 두 범주의 경계가 항상 뚜렷하지는 않습니다.
웹 서버란 무엇이고, 앱 서버와는 어떻게 다를까요? 하나만 단독으로 사용할 수도 있을까요? 그리고 Rack은 어디에 위치할까요?
웹 서버란 무엇인가?
웹 서버(Web Server)는 사용자가 웹사이트에 보낸 요청을 받아 일련의 처리를 수행한 뒤, 필요하다면 그 요청을 Rails 앱에 전달하는 프로그램입니다. 대표적인 웹 서버로는 Nginx와 Apache가 있으며, 실무에서 가장 자주 접하게 되는 두 가지입니다.
CSS, JavaScript, 이미지처럼 자주 바뀌지 않는 정적 파일에 대한 요청이라면 굳이 Rails 앱까지 전달할 필요가 없습니다. 웹 서버가 스스로 처리할 수 있으며, 이렇게 하면 대체로 속도도 더 빠릅니다.
웹 서버는 SSL 요청 처리, 정적 파일 및 에셋 제공, 요청 압축 등 거의 모든 웹사이트에 필요한 공통 작업들을 담당합니다. 그리고 Rails 앱이 직접 처리해야 하는 요청이라면, 웹 서버는 그것을 앱 서버에 넘기게 됩니다.
앱 서버란 무엇인가?
앱 서버(App Server)는 말 그대로 Rails 앱을 실제로 구동하는 프로그램입니다. 앱 서버는 여러분의 코드를 로드하고 앱을 메모리에 유지합니다. 웹 서버로부터 요청을 받으면 Rails 앱에 전달하고, 앱이 요청 처리를 마치면 응답을 다시 웹 서버(그리고 최종적으로는 사용자)에게 돌려보냅니다.
대부분의 앱 서버는 웹 서버 없이 단독으로 실행할 수 있습니다. 개발 환경에서는 흔히 그렇게 하죠! 하지만 프로덕션 환경에서는 보통 앞단에 웹 서버를 함께 두는 것이 일반적입니다. 웹 서버는 여러 앱을 동시에 처리하고, 에셋을 더 빠르게 렌더링하며, 매 요청마다 반복되는 다양한 처리 작업을 대신 맡아줍니다.
Rails용 앱 서버는 Mongrel(요즘은 거의 쓰이지 않음), Unicorn, Thin, Rainbows, Puma 등 매우 다양합니다. 각각의 장점과 설계 철학이 다르지만, 결국 하는 일은 같습니다. Rails 앱을 계속 살려두고 요청을 처리하는 것이죠.
Passenger는 어떤가?
Phusion Passenger는 조금 특별한 존재입니다. "스탠드얼론(standalone) 모드"에서는 일반 앱 서버처럼 동작할 수 있습니다. 동시에 웹 서버에 직접 내장될 수도 있어서, 별도의 앱 서버 없이 Rails 앱을 운영할 수 있습니다.
이 방식은 상당히 편리합니다. 특히 여러 앱을 한 서버에서 운영하면서 앱마다 일일이 앱 서버를 설정하는 시간을 아끼고 싶다면 더욱 그렇습니다. Passenger를 설치한 뒤 웹 서버가 앱 서버가 아닌 Rails 앱을 바라보도록 설정하기만 하면, Rails 앱이 곧바로 요청을 처리하기 시작합니다!
Passenger도 훌륭한 선택지지만, 앱 서버를 분리해서 운영하는 것이 여전히 나은 경우도 많습니다. 분리하면 필요에 가장 잘 맞는 앱 서버를 자유롭게 고를 수 있고, 독립적으로 실행하고 확장(scaling)할 수 있습니다. 그래도 저는 다음에 작은 앱을 새로 배포할 때 Passenger를 다시 시도해 볼 생각입니다. 같은 서버에 앱을 추가로 배포하는 작업이 훨씬 쉬워지기를 기대하면서요.
그럼 Rack은?
Rack은 이런 앱 서버들이 Rails 앱(또는 Sinatra, Padrino 앱 등)을 구동할 수 있게 해주는 마법 같은 인터페이스입니다.
Rack을 Ruby 웹 프레임워크(Rails 등)와 앱 서버가 공통으로 사용하는 언어라고 생각하면 이해하기 쉽습니다. 양쪽이 같은 언어를 알기 때문에, Rails는 Unicorn의 내부 구조를, Unicorn은 Rails의 내부 구조를 전혀 몰라도 서로 소통할 수 있는 것입니다.
전체 구조는 어떻게 연결되는가?
그렇다면 이 모든 요소는 어떻게 맞물릴까요?
웹 요청은 먼저 웹 서버에 도착합니다. Rails가 처리해야 할 요청이라면, 웹 서버는 요청에 약간의 가공을 거친 뒤 앱 서버에 넘깁니다. 앱 서버는 Rack을 통해 Rails 앱과 통신하고, 앱이 처리를 마치면 응답이 앱 서버와 웹 서버를 거쳐 사용자에게 되돌아갑니다.
좀 더 구체적인 예를 들면, Nginx가 요청을 Unicorn에 전달하고, Unicorn은 Rack에, Rack은 Rails 라우터에, 라우터는 적절한 컨트롤러에 요청을 넘깁니다. 그리고 응답은 이 경로를 역순으로 되돌아갑니다.
이 개요는 다소 단순화된 설명입니다. 하지만 이 정도의 분류만 알고 있어도, 사용 중인 소프트웨어를 올바른 그릇에 분류하는 데 큰 도움이 됩니다.
웹 서버와 앱 서버의 관계를 이해하고 나면, 서버 문제가 발생했을 때 디버깅이 훨씬 수월해집니다. 어디를 살펴봐야 하는지, 각 요소가 어떻게 상호작용하는지 파악할 수 있기 때문입니다. 그리고 새롭고 흥미로운 앱 서버가 등장하더라도 교체 작업이 훨씬 쉬워질 것입니다.
Rails가 웹과 어떻게 상호작용하는지 더 깊이 알고 싶다면 "How Rails Sessions Work" 아티클을 확인해 보세요.