몽그렐 클러스터가 필요한 이유
레일스 애플리케이션을 개발/배포할 때 가장 많이 사용되는 서버가 몽그렐(mongrel)이다. 몽그렐이 나오기 전에는 개발 환경에서는 Webrick(순수 루비 HTTP 서버)을 사용하고, 배포 환경에서는 FastCGI(또는 SCGI)를 즐겨 사용했었는데, 속도와 안정성 측면에서 문제가 많았다. 몽그렐은 구세주 같았다.
몽그렐은 레일스 전용이 아닌 일반적인 HTTP 서버 프로그램이다. 하지만 실제 배포 사례들을 보면 꼭 몽그렐을 뒷단(backend)에 두고 앞에는 일반적인 웹서버(아파치나 Nginx같은)를 둔다. 그 이유가 뭘까? 첫 번째 이유는 몽그렐의 정적 파일 처리 능력이 기존의 웹서버 프로그램보다 떨어지기 때문이다. 그래서 라우팅 트릭(rewrite)를 이용해 정적 파일은 기존 웹서버가 처리하도록 하고, 동적 요청(레일스)만을 몽그렐로 전달하게 한다.
이보다 근본적인 이유는 몽그렐 클러스터, 즉 몽그렐 프로세스를 여러개 띄우고 이들을 풀(pool)로 활용하기 위해서이다. 여기서 궁금증이 생긴다. 왜 유독 몽그렐만 클러스터가 필수처럼 여겨질까? 몽그렐이 동시 사용자를 처리하지 못하나? 그렇지 않다. 몽그렐은 요청당 한 스레드(루비의 그린쓰레드라는 문제는 있지만)를 사용하며, 완전한 스레드 안전성(Thread Safety)를 보장한다. 그렇다면 왜? 답은 레일스 문화에 있다. 레일스 초창기부터 여러 부분에서 다중 스레드를 고려하지 않아왔기 때문이다. 대부분의 환경에서 단일 스레드로 충분했다고나 할까?
ActionController::Base 클래스와 ActiveRecord::Base에 모두 allow_concurrency라는 속성이 정의되어 있고, 이 속성의 기본값은 거짓(false)이다. base.rb를 보면 아래와 같은 코드를 찾을 수 있다.
- # Action Pack and Active Record are by default thread-safe,
# but many applications may not be. - # Turned off by default.
@@allow_concurrency = false
cattr_accessor :allow_concurrency
이 값을 true로 바꾸는 것으로 레일스의 스레드 안전성을 보장받을 수 있을까? 나는 아니라고 생각한다. 이유는 루비 커뮤니티가 스레드 안전성에 익숙하지 않고(애플리케이션에서 사용하는 어떤 코드에서 문제가 일어날지 모른다), 다중 스레드 환경에서 충분한 테스트도 이루어지지 않았기 때문이다. 한마디로 검증되지 않았다는 이유이다. 몽그렐 핸들러를 이용해 작은 프로그램을 처음부터 다중 스레드를 고려해서 만든다면 가능하겠지만, 그렇지 않은 경우 위 옵션을 켜는 것을 추천하지 않는다.
이런 이유로 몽그렐의 레일스 핸들러에서 디스패처 전후로 뮤택스(Mutex)를 이용한 동기화를 행하고 있다. 아래는 mongrel-1.0.1/lib/mongrel/rails.rb 코드의 일부이다.
- module Mongrel::Rails
- class RailsHandler < Mongrel::HttpHandler
- def process(request, response)
- # ...
- @guard.synchronize {
- @active_request_path = request.params["PATH_INFO"]
- Dispatcher.dispatch(
- cgi,
- ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
- response.body)
- @active_request_path = nil
- }
- # ...
- end
- def process(request, response)
- end
- class RailsHandler < Mongrel::HttpHandler
- end
이제 몽그렐은 한번에 하나의 요청만을 처리할 수 있다. 따라서 동시 사용자를 처리하기 위해서는 꼭 몽그렐 클러스터가 필요하다. 그래서 개들을 다루는 능력이 레일스 서비스 운영에서 핵심 역량이 되었다.
이미지 출처: Skinny Request, Fat Backend - Scaling Rails
한번에 하나의 요청만을 처리할 수 있기 때문에 레일스 애플리케이션이 요청을 처리하는 전략도 수정되어야 한다. 즉, '빠른 응답 시간'을 보장할 필요가 있다. 따라서 오래걸릴 만한 작업이라면 BackgrounDRB 등의 방법을 이용해 백그라운드로 처리하고, 상태만을 반환해야 한다. 얼핏 보기에는 번거러운 작업일 수 있지만, 사용자의 요청에 빨리 응답한다는 면에서 좋을 수도 있겠다.
참고 자료
History
Last edited on 03/10/2008 12:07 by deepblue
Comments (0)