Rath World » Development

Archive

Archive for the ‘Development’ Category

CloudFoundry 구조 살펴보기 시작

June 19th, 2012 1 comment

지난번 CloudFoundry 소개글에 이어 이번에는 CloudFoundry 구조를 살펴본다.

일단 rightscale 블로그 글에 첨부된 이미지를 무단 링크하고 시작한다.

항목 별로 간단히 나열해보면,

  • Router
  • Cloud Controller
  • Droplet Execution Agent (그림에서의 App Exec Engine)
  • Services

이렇게 나눠볼 수 있다. Health Manager는 각 구성요소들이 잘 동작하는지 주기적으로 체크하다가 이상한 녀석이 있으면 신고해주는 역할을 하므로 설명을 생략한다. 각 구성요소들이 어떤 역할을 하는지 알아보기전에 사용자 기준 시나리오를 설명하는 것으로 시작하는게 좋을 것 같다.

먼저 CloudFoundry를 주도적으로 사용하는 웹개발자 입장에서의 흐름을 살펴본다.

  • VMC -> Router -> Cloud Controller -> (요청 종류에 따라 분기)

VMC는 CloudFoundry 이용자(웹개발자)가 사용하는 CLI 툴이다. VMC를 통해 로그인도 하고, 웹 어플리케이션을 업로드 하기도 하고, 인스턴스 수를 늘렸다 줄이기도 하고, 새 서비스(mysql, mongodb 등)를 자신이 올린 앱과 bind 하기도 한다. 로그파일을 보는 것도 vmc 로 한다. 지금 언급한 vmc 의 기능들은 모두 Cloud Controller 속에 구현되어있다. 그런데 왜 Router를 거치는가? 아니 Router 가 도대체 무엇인가?

Router 는 우리가 알고 있는 하드웨어 라우터가 아니다. Ruby 로 만들어진 HTTP 라우터 서버다. Host 헤더를 보고 어느 서버로 포워드해야하는지만을 알고 있는 녀석이다. 이 Ruby 로 만들어진 Router 는 이슈가 좀 있지만 어찌됐든 오직 하나의 목적을 가지고 있다. 외부에서 HTTP 요청이 오면 이 요청을 담당하는 서버가 어디있는지 알려주는 것이다.

Cloud Controller의 기능들도 모두 HTTP로 제공되기 때문에 구지 Cloud Controller를 Router 밖으로 분리할 이유가 없기 때문에 Router 아래에 위치한 것이다. 이 설정은 얼마든지 바꿀 수 있다. Cloud Controller 설정파일을 보면 use_nginx: true|false 가 있기도 하다. Router랑 안붙이고 독립 웹서버(Nginx)에 붙일 수도 있고, 아무것도 없이 Cloud Controller 가 80 포트를 바인드해서 서비스를 해도 (이중화 문제가 생기겠지만) 된다.

 

이제 CloudFoundry를 투명하게 사용하게 되는 엔드유저 입장에서의 흐름을 살펴보자.

  • 웹브라우저 -> Router -> Droplet Execution Agent -> Services

Drop Execution Agent (이하 DEA)는 Web Application Server 라고 보면 된다. 실제로 apache2+php 가 돌거나 python, ruby vm이 돌거나 Tomcat 이 돌아가는 곳이다.

Services는 WAS에 붙어있는 MySQL 이라고 이해하면 된다. 실제로는 MySQL 말고 NoSQL이 될 수도 있고 memcached 나 RabbitMQ 가 될 수도 있다. WAS가 사용하는 백엔드 서비스들을 총칭하는 것이 Service 이다.

딱히 이해하기 어려운 부분이 없다. 그런데 앱이 여러개이고 앱당 WAS 인스턴스가 늘어나게 되면 그 숫자만큼 DEA 가 필요할텐데 앱을 적당한 DEA에 배포하고 이를 Router 에게 알려주고 하는 등의 작업들은 누가 할까. Cloud Controller 가 한다. Cloud Controller 는 정말로 많은 일을 한다. 다행히 엔드유저의 요청을 처리할 때는 Cloud Controller 가 조금도 관여하지 않기 때문에 논리적으로 기능상 병목이 될 수는 있을지언정 트래픽이 몰려서 엔드유저가 사용하는 웹서비스가 느려진다거나 하는 등의 일은 발생하지 않는다.

잠깐, 위 그림에도 없고 아직 언급하지 않았지만 CloudFoundry 에서 아주 중요한 것 하나를 생략했다. 그것은 NATS 이다. NATS는 CloudFoundry를 설계한 Derek Collison 이 만든 메시지 버스로  경량 publish, subscribe 프로토콜 및 그 구현체이다.  CloudFoundry의 모든 컴포넌트들 (Router, Health Manager, Cloud Controller, Droplet Execution Agent, Services) 의 설정파일에 mbus: nats://1.2.3.4:4222/ 이렇게 NATS 서버 주소를 쓰게 되어있다. 그래서 새 DEA를 동적으로 붙인다던지, 잘 동작하던 DEA 서버 하나를 종료한다던지 할 경우 NATS를 통해 온 시스템에 해당 이벤트가 전파된다.

이렇게 보면 CloudFoundry 에서 NATS 가 없다면 절대로 돌아가지 않는, CloudFoundry 각 구성요소들을 한데 묶어주는 중요한 역할을 하는 것이다. 그러나 다행히도 NATS 또한 Cloud Controller 처럼 엔드유저의 요청수와 무관하다. 그렇기 때문에 DEA 인스턴스 2,000여개가 돌면서 NATS 에게 이벤트를 발송하더라도 딱히 문제 될 것은 없다. 게다가 publish-subscribe 특성상 메시지가 쌓이는 일도 없다. NATS 서버가 여러개고 각 메시지가 idempotent 라면 서버 하나 몇시간 죽었다 올라와도 전체 시스템에 영향을 미칠 수 없는 것이다.

여기에 하나 더, 각 컴포넌트 내에서 비동기 작업큐로 사용하는 Resque 가 있다.  CloudFoundry 각 컴포넌트들이 거의 다 Ruby 로 작성되어있기도 하고 (Ruby는 타언어에 비해 쓰레드 처리가 약하다), 경량 pubsub 인 nats 에 실어보내기엔 꽤 규모가 되지만 그렇다고 persist 할 필요가 없는 대부분의 작업들에 대해 Resque 를 사용한다. Resque 는 Redis backed 므로 CloudFoundry 인스턴스 내 어딘가에 Redis 가 하나 돌고있어야 한다.

Router 에 관련하여 하나 더. 초반에 말했듯이 CloudFoundry Router 는 Ruby 로 작성되어있다. 사용자 요청을 Ruby 가 바로 받는다니 어쩐지 이상하지 않은가? 실제 환경에서는 당연히 Router 앞에 Nginx 가 붙어있다. Router version 1의 경우 Nginx 가 HTTP 요청을 제일 먼저 받아서 유닉스 소켓을 통해 Ruby router 에게 by pass 하고 Router 는 HTTP 헤더를 보고 어느 DEA로 분기해야하는지 잡아서 그 DEA로 입력스트림을 포워드하고 응답이 올때가지 기다렸다가 이를 받아 다시 Nginx 로 보내고 웹브라우저로 리턴되는 식이였다. 아니 이게 말이 되는가, Ruby Router 의 i/o 병목 어쩔건가. Nginx 웹서버는 로그분석이랑 SSL 처리를 위해 쓴다고 하면 할 말이 없지만 이름(Router)에 어울리지 않는 일을 하고 있었다.

그래서 Router version 2 가 나왔다. Router version 2에는 CloudFoundry 용 Nginx Lua 모듈이 있다. 이 모듈의 역할이 무엇인가하면, HTTP 호스트 헤더를 받아 Ruby Router에게 JSON over HTTP로 묻는다. ‘이 Host 가려고 하는데 위치가 어디니?’ 하면 위치만 리턴한다. 그러면 Nginx Lua 모듈이 이 일련의 과정을 처리하여 proxy_pass 에 들어갈 최종 host/port를 넘기는 것이다. 뭔가 복잡하게 보일수도 있지만 최소한 더이상 Ruby Router가 웹어플리케이션의 i/o를 파이프라이닝 하는 일은 없다. 정말 라우팅 테이블만 관리하는 컴포넌트가 된 것이다.

독자도 지치고 나도 지치고.

Categories: Development Tags:

An Overview of CloudFoundry

June 11th, 2012 1 comment

몇달전부터 CloudFoundry.org를 애용하고 있다.

CloudFoundry는 VMware에서 Ruby로 만든 오픈소스 PaaS (Platform as a Service)이다. 용어에 Platform이 들어가기 시작하면 너도 나도 다른 생각을 하는 경우가 부지기수니 PaaS 라는 용어는 사용하지 않고 CloudFoundry에 집중하도록 하겠다.

CloudFoundry가 이용자(개발자)에게 주는 핵심가치는 편리함이다. CloudFoundry를 사용할 경우 아래와 같은 (개발자 입장에서) 귀찮은 작업들로부터 해방될 수 있다.

  • 관계형 데이터베이스(MySQL, PostgreSQL) 설치/운영
  • NoSQL 무리들(Redis, MongoDB) 설치/운영
  • MQ(Rabbit) 설치/운영
  • 웹사이트 주소가 중요하지 않을 경우, 도메인 등록
  • 웹서버의 가상호스트 설정
  • 웹서버와 어플리케이션 서버간의 프록시 설정
  • 트래픽에 따라 웹어플리케이션 서버 개수 줄이거나 늘리기
  • 배포

위 항목들을 살펴보라. 통채로 보면 지긋지긋하게 보일 수 있겠지만 각 항목 하나씩만 본다면 어려운 것이 없다. 그러나 묘하게 사람 귀찮게 하는 일들이다.

MySQL 을 설치했다 치자. 디비이름도 결정해야 하고 계정이름과 비밀번호도 결정해야 한다. 결정한 뒤에는 어딘가 적어둬야하고 웹서버코드에 옮겨놓거나 설정파일로 뗀다거나 등의 작업을 해야한다.

지인들과 사용할 기능 위주의 웹페이지를 만들었다고 치자. 이런 경우라면 호스트명이 중요하진 않다. 어디 빌붙어사는 느낌이 팍팍나는 our-rooms.cloudfoundry.com 뭐 이런거면 어떤가? 돌아가면 됐지. 그러나 CloudFoundry 가 해주는 것처럼 이용자에게 서브도메인을 자동으로 발급해주는 제품을 사용하지 않는다면, 비록 1분만에 작업이 끝나더라도 그 작업을 해야한다.

DNS 레코드 수정하는 것도 귀찮은 작업이지만, 웹서버에 가상호스트 설정하는 것 또한 귀찮은 작업이다. 웹프로그램 하나 만들때마다 Nginx server 블럭이 하나 추가된다. 물론 다른 호스트꺼 복사해서 붙여서 호스트명과 WAS 프록시 주소만 바꾸면 된다. 그리고 nginx -s reload. 이것 역시 30초도 안걸리는 작업이다. 하지만 그 작업을 해야한다.

트래픽이 늘어나서 WAS 2개를 추가했다. nginx upstream 블럭에 서버 두 줄 추가하면 된다. 편집기로 nginx 설정파일을 열었는데 새로 추가한 WAS 서버 호스트랑 포트가 잘 기억이 나지 않기도 하고, 서버 10대중 3대를 빼는거라면 빼야할 서버 3개가 무엇인지 정확히 파악하느라 일시적인 스트레스를 받기까지 해야한다.

CloudFoundry는 시스템엔지니어와 말 한마디도 섞지 않으면서 서비스 오픈까지 하고 싶은 개발자를 위한 제품이다. 시스템엔지니어 업무들 일부분이 통합되고 자동화된 것이다.

그러므로 자신이 만드는 서비스가 시스템 특성이나 설정을 많이타는 특수한 과업을 견뎌내야하는 상황이라면 CloudFoundry 를 검토하지 말것을 추천한다. CloudFoundry 는 개발자가 딱히 신경쓰지 않아도 될 부분들로부터 자유를 주겠다는 것이지, 중고급 시스템 엔지니어 인건비를 절감해주겠다는 제품이 아니다. 시스템 엔지니어가 눈감고 졸면서 처리할 수 있는 일들을 자동화해주는 것이다.

다음에는 CloudFoundry 구성요소와 설치에 대한 이야기를 이어서 하겠다. CloudFoundry 설치에 대한 내용을 Overview와 함께 풀게되면 포스트의 특정 파트만 하드코어해지는 문제가 생기므로.

Categories: Development Tags:

자급자족 개발자

May 31st, 2012 4 comments

언젠가부터 만든 프로그램을 외부에 노출하지 않기 시작했다.

제작년에 만들었던 Android 용 MSN 클론 때문이다. public release 는 대단히 고통스럽고 에너지가 많이 소모되는 일이다. Total Installation 수는 360만정도였고, Active Installation 수는 내가 이 프로젝트를 버린지 1년이 넘었기도 하고 Microsoft 가 ‘왜 앱이름에 MSN이 있니? 마켓에서 내려라’ 해서 Market 에서 사라지고 이름을 바꿔 새로 올렸기 때문에 지금은 50만대 밖에 안된다. 50만대밖에라는 표현을 하긴 했지만, 혼자 감당하기에는 큰 숫자다. 배포 한 번 할 때마다 가슴 졸이며 받았던 스트레스는 어마어마했고 사용자 피드백도 많았다. 부정적인 피드백은 그 순간의 내 에너지를 빼앗아가고, 긍정적인 피드백은 당장은 기분이 좋지만 더 잘해야겠다는 생각으로 내 미래 에너지를 빼앗아간다. 어찌됐든 내 에너지가 소모된다.

나는 너무 지쳤고, 업데이트 시마다 받는 관심 리젠을 받지 않기 위해 업데이트를 1년째 안하고 있다. 성공했다. 제품이 만들어내는 수익은 1/10 수준으로 떨어졌지만 나는 에너지를 다른 곳에 쓸 수 있게 됐기 때문이다.

지난 3월경에 만든 버스앱이 있다. 2월 중순에 집을 이사했고, 여기는 지하철역과 15분이나 떨어져있지만 버스정류장과는 1분 거리기 때문에 버스앱이 필요했다. 런던에는 Transport for London 이란 사이트에서 각 버스정류소의 지리적 위치, 실시간 버스 도착 시간 등을 제공한다. 1-2주 정도의 시간을 들여 만들었고 쓸만한 수준이다. 이렇게 1달 정도를 쓰다보니 Google Maps 타일 이미지 때문에 3G 트래픽이 많아진 것을 발견했다. 그래서 OpenStreenMapMapnik 을 이용하여 런던 전체 지도를 렌더링하여 SD 카드에 넣었다. 줌레벨 14~18 PNG 타일을 다 넣었지만 670MB 정도면 되고 앱 반응속도도 빨라져서 좋다. 이렇게 또 1달 정도를 썼다. 아직 불만이 없다. 며칠전에 버스로 30분을 이동해야하는 헬스장을 끊었으니 조만간 앱도 개선이 될 듯 하다.

우리집 인터넷은 무지막지하게 느리다. 아내가 유튜브로 드라마를 보기만 해도 업무에 지장이 올 정도다. 그런데 내가 즐겨듣는 몇몇 음악은 유튜브에서만 들을 수 있다. 그래서 유튜브 다운로더를 만들었다. 나는 커멘드라인 중독자라 CLI로 만들었다. 다운로드 후 오디오만 ffmpeg 으로 뽑아서 Apple Script 으로 iTunes ‘YouTube’ 플레이리스트에 넣는다. 개발에 걸리는 시간은 수시간이였고, 여태까지 아무런 불만도 없었다. 이거 릴리즈한다고 생각해봐라. 일단 YouTube 컨텐트를 다운로드 하는 것 자체가 불법이다. 사람들이 다 Mac 을 쓰는 것도 아니고, Mac 사용자라 하더라도 iTunes 을 메인으로 쓸지 안쓸지 모른다. 그들의 플레이리스트 이름이 과연 ‘YouTube’ 일까? 게다가 ffmpeg 바이너리도 재배포해야한다. 내 ffmpeg 은 –enable-gpl 에 –enable-nonfree 다. ffmpeg 바이너리 재배포만 해도 불법이다. Mac 쓰는 사용자중에 몇명이나 Terminal.app 을 항상 띄워둘까?

Michael T. Nygard의 Release it: Design and Deploy Production-Ready Software도 읽어보았지만 내겐 효과가 없었다. 아니 역효과만 났다. 책 제목만 보고 ‘릴리즈 못하는 병이 없어질지도 몰라’ 했지만 Production Ready 의 눈높이만 올려줘서 릴리즈 안하는 이유를 더 잘 만들어 낼 수 있게 됐기 때문이다.

내 릴리즈 기준을 충족하는 제대로 된 제품을 만들어 릴리즈하려면 훌륭한 엔지니어(디자이너 포함)가 적어도 4명은 필요한 것 같다. 그런데 나는 내 밑에 사람을 두는 것을 끔찍히도 싫어하고, 협동을 하는데 꼭 필요한 희생의 미덕이 부족하다. 갈 길이 멀다. 그렇기 때문에 인생은 살만한 가치가 있다.

Categories: Development, Life, Personal Tags: