 |
Yaws와 ErlyWeb을 이용한 얼랭 웹 개발, Part 1: Yaws와 얼랭
|
 |


김석준 sjoonk@gmail.com
한 때 공직에서 근무하다 어릴 적부터 해오던 컴퓨터 프로그래밍의 진맛을 잊지 못해 업종을 전환하였다. 이후 파레토인터넷마케팅의 CEO 겸 CTO, 한국컴퓨터 CTI솔루션 개발팀장, 교보생명 정보시스템실 IT아키텍트 등을 거쳤으며 현재는 웹2.0 기반 애플리케이션 개발 및 컨설팅을 주로 하는 유스풀패러다임의 대표다. 역서로 "루비온레일스와 함께하는 애자일 웹 개발"과 "레일스 레시피"가 있다. 생각하는 것을 즐기고 매일매일 새로워지려고 노력한다. 블로그 주소는 http://thinkr.egloos.com이다
난이도 : 초급
2008년 5월 20일
|
|
 |
|
[오픈 developerWorks]는 여러분이 직접 필자로 참가하는 코너입니다.
이번 호에는 그 동안 잘 알려지지 않은 얼랭(Erlang)이라는 언어를 이용한 웹 프로그래밍에 대해 살펴봅니다.
Yaws 를 소개합니다
Yaws 는 얼랭 (Erlang) 이라는 프로그래밍 언어로 만들어진 웹 서버로, Yet Another Web Server의 약자다. 웹 서버 제품들이 대부분 정적인 콘텐츠를 제공하는 것을 위주로 제작된 반면, Yaws는 애당초 설계 시부터 동적인 콘텐츠 처리에 초점을 맞춰 제작되었다고 한다. 게다가 운영체제 스레드보다도 가벼운 경량 프로세스를 기반으로 하는 함수형 언어인 얼랭으로 만들어진 까닭에 웹 콘텐츠를 처리함에 있어 탁월한 성능을 보이는 것으로 알려져 있다. 그림 1은 아파치 웹 서버와 Yaws의 성능을 비교한 것인데 , 아파치(녹색과 청색 그래프)는 약 4000개의 동시접속에서 시스템이 멎는 반면, Yaws(적색 그래프)의 경우는 약 8만 개의 동시접속까지 너 끈히 처리하는 걸로 나와 있다. 더 자세한 내용은 참고자료를 참고하면 될 것이다.
그림 1 . 아파치 대 Yaws

Yaws 설치하기
그럼 우선 Yaws를 설치하자. Yaws가 얼랭을 기반으로 작동하기 때문에, 먼저 얼랭을 설치해야 하지만 여기서는 얼랭 설치 과정은 생략한다. 얼랭 설치는 다른 프로그램의 설치 방법들과 다르지 않고, 이미 많은 자료가 온라인에 나와 있으니 참고하면 되겠다.
이번 글은 우분투 리눅스 7.10 에서 작업하는 걸로 가정한다. 만약 독자들이 다른 운영체제를 사용한다면 설치방법이 조금 다를 수도 있다. 그렇지만 적어도 *nix 계열이라면 대동소이할 것이다 (윈도우 시스템에서는 수작업이 약간 필요하다). Yaws사이트에 접속하여 소스를 다운로드 한 다음 빌드하자.
$ configure; make; make local_install
|
필자의 경우 통상적인 make install 대신 make local_install 옵션으로 설치했다. 이렇게 하면 Yaws가 로컬 계정에 설치되며 설정 파일인 yaws.conf도 $HOME 디렉터리에 설치되므로 지금처럼 테스트나 실습을 하기에는 더 적합하기 때문이다.
Yaws 설정하기
Yaws가 정상적으로 설치되면, 이제 웹 서버를 설정하는 것만 남았다. Yaws는 웹 서버가 단독으로 실행되는 독립형 (standalone) 모드와 다른 애플리케이션 속에 내장되어 실행되는 임베디드 (embedded) 모드를 지원하는데 여기서는 통상적인 독립형 모드로 웹 서버를 실행한다고 가정할 것이다. 구성설정 파일은 Yaws 를 전역으로 설치한 경우라면 /etc/yaws.conf 로, 그렇지 않고 앞서와 같이 로컬로 설치한 경우라면 $HOME/yaws.conf에 위치할 것이다. 구성설정 파일 자체가 간단하고 주석이 잘 되어 있기 때문에 특별하게 언급할 내용은 없다. 다음과 같이 호스트를 설정하는 부분에 자신의 디렉터리 구조에 맞게 적절한 설정을 해주고 나면 설정이 완료된다. 여러 개의 가상 호스트 설정을 할 수 있는 점 등은 여타 웹 서버들과 크게 다르지 않다.
Listing 1 . yaws.conf 파일에서 호스트 설정
port = 8000
listen = 0.0.0.0
docroot = /home/myhome/www
|
Yaws 실행하기
구성설정을 마치면, 이제 $HOME/bin/yaws -i 로 서버를 띄우고 웹 브라우저에서 http://localhost:8000/ 으로 접속해 제대로 작동하는 것을 확인할 수 있다. 참고로 Yaws 의 실행 옵션에는 여러 가지가 있으며 , 주로 다음과 같은 명령을 사용한다 (더 자세한 것은 매뉴얼 페이지를 참조하자).
* yaws -i (인터랙티브 모드, 개발 시에 적합)
* yaws --daemon (데몬으로 띄우기)
* yaws --stop (데몬 종료)
첫 번째 Yaws 페이지
그럼 이제 첫 번째 콘텐츠를 하나 만들어 보자 . 짧은 인사말을 출력하는 간단한 웹 페이지다. 앞서 설정 파일에서 지정한 docroot 디렉터리에 index.yaws 라는 파일을 하나 만든 다음, 다음과 같이 입력하자.
Listing 2 . 첫 번째 Yaws 페이지 (index.yaws)
첫 번째 데모
out(Arg) ->
{html, "안녕하세요. 얼랭!"}.
|
통상적인 HTML 페이지와 크게 다르지 않다. 특이한 부분은 <erl> 태그로 시작되는 부분인데, 이 부분은 Embedded Erlang 이라고 하여 얼랭 코드가 들어가는 부분이다. Yaws 는 내부적으로 페이지를 읽다가 이 <erl> 태그를 만나면 얼랭 코드로 인식하여 그 코드 속의 out(Arg) 함수를 호출한다. 그리고 이 out/1 함수 호출 결과가 페이지에 삽입된다. 한 페이지에는 하나 이상의 out/1 함수가 올 수 있으며, 이 때 각각의 <erl> 부분은 각각 하나의 얼랭 모듈로 컴파일되어 저장된다.
[ 참고 ] 얼랭은 함수형 언어다. 객체지향 언어에서 모든 것이 '객체' 이듯 함수형 언어인 얼랭에서는 모든 것이 '함수' 다. 그리고 함수는 언제나 입력값과 함께 반환값을 가진다. 앞의 예제에서 out(Arg) 는 함수다. Arg 라는 하나의 인수를 가지는 함수라서 통상적으로 out/1 이라고 표기하며, 이 때 1은 애리티(arity)라고 부른다. 이 out/1 함수에 전달되는 인자 Arg는 웹 요청에 관련된 여러 가지 정보 (예를 들면 요청 URI, 헤더값, POST 데이터 등) 를 담은 자료구조(레코드)로서, 완전한 내용은 yaws_api.hrl 파일에 정의되어 있다.
Yaws의 작동 원리
Yaws는 *.yaws 파일을 파싱하여 HTML 부분과 얼랭 부분으로 나눈다. 각각의 얼랭 부분은 각각 하나의 모듈로 컴파일된다. 각 얼랭 모듈은 out/1 함수를 가지고 있어야 한다. 일단 한번 컴파일한 모듈은 캐싱하기 때문에 다음 번 웹 요청 시에는 컴파일된 모듈로부터 직접 결과를 제공한다.
또한 Yaws 의 out/1 함수는 반환값을 가진다. 앞의 예제에 나온 {html, X} 형태로 되어 있는 이 반환값은 얼랭에서 ' 튜플 ' 이라 부르는 자료구조로서, 대략 말로 풀어보면 'X 라는 내용을 html 형태로 반환하라' 는 의미다. 이것은 Yaws 에서 정의한 out/1 함수의 규약이며, 이 밖에도 {ehtml, Term}, {content, MimeType, Content} 등 여러 가지 다른 반환값이 올 수 있다. 예를 들어, 리다이렉션을 처리하는 경우라면 다음과 같이 하면 될 것이다.
{redirect, "http://othersite.com", 303}
|
이제 웹 브라우저에서 결과를 보면 다음과 같은 화면이 보일 것이다.
그림 2. 첫 번째 페이지
웹 요청 처리하기
웹 프로그래밍의 기본은 웹 요청을 처리하는 데 있다. 즉 클라이언트로부터 들어오는 GET 또는 POST 요청을 받아 처리하고 그 결과를 반환하는 것이다. 이제 간단한 폼을 하나 만들었다고 가정하고, 그 폼의 값을 받아 처리하는 process_form.yaws 파일을 아래와 같이 작성해 보자.
Listing 3 . process_form.yaws
폼 처리 결과
out(A) ->
{ok, Title} = postvar(A, "title"),
{html, " 당신의 이름은 " ++ Title}.
|
반환값을 처리하는 부분 바로 위에 {ok, Title} = postvar(A, "title")이라는 코드가 한 줄 더 들어간 것을 제외하면 앞의 예제와 별 다를 게 없어 보인다. 이 새로 추가된 한 줄이 바로 클라이언트로부터 들어온 POST 요청을 받아 처리하는 부분이다. 여기서는 yaws_api 라는 모듈에서 제공하는 postvar/2 라는 함수를 사용하는데, 이 함수는 POST 요청으로부터 특정 값을 추출하는 함수다.
[ 참고 ] 여기서는 패턴매칭을 사용하여 값을 추출하고 있다. 얼랭 언어에 익숙해지려면 이 패턴매칭을 능숙하게 처리할 수 있어야 한다. 이 예제의 경우 postvar/2 함수는 그 함수 명세에서 반환값으로 {ok, X} 를 반환하게끔 되어 있다. 따라서 {ok, Title} = postvar/2 라고 하면, 반환값이 {ok, Title} 과 패턴매칭하게 되고, 그 결과 Title 에는 원하는 값이 들어가는 것이다. 이렇듯 얼랭에서 = 연산자는 통상적인 언어의 = 연산자와는 그 쓰임새가 사뭇 다르다. 얼랭에서 = 은 패턴매칭 연산자다.
여기서 우리가 사용한 postvar/2 같은 함수들은 Yaws 에서 기본으로 제공하는 yaws_api 모듈 속에 들어 있는 함수로서, 그렇지 않으면 직접 처리했어야 할 번거로운 일들 ( 예를 들어 GET 과 POST 방식의 데이터는 각각 A#arg.querydata 와 A#arg.clidata 라는 튜플 속에 들어 있으므로 이 레코드를 직접 액세스할 수도 있다)을 편하게 처리할 수 있도록 해주는 여러 가지 유틸리티 함수가 들어 있다. 아래 표는 그 중 웹 요청 처리와 관련된 함수들을 정리한 것이다. 전체 함수 목록은 매뉴얼 페이지를 참조하면 되겠다.
표 . 웹 요청 처리를 위한 yaws_api 함수
함수명 |
내용 |
비고 |
parse_query(Arg) |
웹 요청의 쿼리 부분을 파싱하여 {Key, Value} 의 리스트를 반환한다 |
|
parse_post(Arg) |
parse_query 와 동일하나 , POST 데이터를 대상으로 한다 |
|
queryvar(Arg, VarName) |
쿼리 문자열에서 지정한 값을 추출한다. 반환값은 성공인 경우 {ok, Val}, 실패인 경우 undefined 다 |
자주 사용하는 함수이기 때문에 모듈에 자동으로 포함된다. 즉 호출 시에 앞에 모듈명을 부가할 필요가 없다 |
postvar(Arg, VarName) |
queryvar 와 동일하나 , POST 데이터를 대상으로 한다 |
상동 |
getvar(Arg, VarName) |
POST 호출인 경우는 postvar/2 를 , GET 요청인 경우는 queryvar/2 를 각각 호출한다 |
|
Appmod
지금까지는 파일 확장자가 *.yaws 로 끝나는 파일을 만들어 동적인 콘텐츠를 처리하였다. 그렇지만 Yaws 에는 이외에도 appmod 라고 하는, 조금 더 진보된 개념의 콘텐츠 처리방식도 제공한다. appmod 는 application module 의 약어로, 한마디로 말해 URL에 기반을 두고 각기 다른 얼랭 모듈을 맵핑하도록 해주는 메커니즘이다. 즉 URL 경로에 대해 각각 별도의 얼랭 모듈을 할당해 처리를 하도록 하는 메커니즘으로, 아파치에 익숙한 독자들이라면 mod_rewrite를, 그리고 루비온레일스 사용자라면 라우팅(routing)을 떠올리면 쉽게 이해가 될 것이다.
appmod는 yaws.conf 파일에서 설정하면 된다. 예를 들어 URL 경로명에 cookie라는 단어가 들어가는 호출은 모두 recipe라는 모듈에서 받아 처리하도록 하려면 다음과 같이 적어주면 된다.
Yaws는 어떤 웹 요청에 appmod경로가 들어 있을 경우, 통상적인 처리 대신 해당 appmod를 호출하여 처리한다. 이 때 appmod이하의 URL 경로는 Arg#arg.appmoddata에 들어간다. 예를 들어, 앞서와 같이 구성설정을 한 상태에서 클라이언트가 http://yourdomain.com/cookie/my/favorite.html이라고 호출한 경우, 실제로는 recipe이라는 모듈의 out/1 함수가 호출되며 이 때 URL 경로의 나머지 부분, 즉 my/favorite.html은 Arg#arg.appmoddata에 담기는 것이다. appmod는 이런 식으로 URL을 맵핑하기 때문에 이른바 "예쁜 URL(pretty URL)" 을 만드는 데도 쓰인다.
[ 참고 ] opaque 데이터
종종 애플리케이션에 특정한 데이터를 웹 서버로부터 애플리케이션으로 전달할 필요가 있다. 이를 opaque데이터라고 하며, yaws.conf 파일에서 <opaque> 태그 안에서 설정해 줄 수 있으며, 이렇게 설정된 데이터는 Arg#arg.opaque 를 통해 접근할 수 있다.
yaws appmod 데모 : 트랙백 서버
Yaws에는 지금껏 설명한 것 외에도 여러 가지 설명할 내용(예를 들면 쿠키와 세션 처리, SSI, 리다이렉트 등)이 있지만 지면관계상 생략하기로 하고, 여기서는 지금까지 설명한 내용을 가지고 간단한 appmod 를 하나 만들어 보기로 한다. 블로그의 트랙백 (trackback)을 받아 처리하는 트랙백 서버를 만들어 보겠다.
트랙백 서버는 클라이언트로부터 들어오는 트랙백 핑(ping)을 처리하는 서버로서, 이때 트랙백 핑은 HTTP POST 호출이며 콘텐츠 유형이 application/x-www-form-urlencoded로 되어 있어야 하는 등 몇 가지 간단한 규칙이 있다. 트랙백 핑의 자세한 스펙은 참고자료를 참고하면 되겠다. 여기서는 정교한 트랙백 서버를 만들기보다는, Yaws 의 appmod 를 이해하는 의미에서 개념 수준으로 구현할 것이다. 다음은 완성된 트랙백 서버의 코드다. 이 파일을 trackback.erl 로 저장한 다음 Yaws 의 구성설정 파일에서 appmods = <tb, trackback>이라고 한줄 추가하고서 yaws -i 로 Yaws 를 다시 시작하자. 그리고 나서 Yaws 셸에서 c(trackback). 명령을 주어 모듈을 컴파일하고 나면 이제 트랙백 서버가 작동될 것이다.
Listing 4 . 트랙백 서버 예제 (trackback.erl)
%% 간단한 트랙백서버 예제
-module(trackback).
-author(sjoonk@gmail.com).
-export([out/1]).
-include("/home/coti22/yaws/include/yaws_api.hrl").
-define(RESP(Code),
"
" ++ Code ++ "").
success() -> {content, "text/xml", ?RESP("0")}.
failure(Msg) ->
{content, "text/xml", ?RESP("1"++Msg++"")}.
out(A) ->
Header = A#arg.headers,
Accept = Header#headers.accept,
case yaws_api:postvar(A, "url") of
{ok, Url} -> case validate(Accept) of
ok ->
{ok, Title} = yaws_api:postvar(A, "title"),
dets:open_file(bloglist, []),
dets:insert(bloglist, {Url, Title}),
dets:close(bloglist),
success();
{error, Msg} -> failure(Msg)
end;
_ -> failure(" 잘못된 POST 데이터 ")
end.
validate(Accept) ->
case string:str(Accept, "application/x-www-form-urlencoded") of
1 -> ok;
_ -> {error, " 잘못된 콘텐츠 유형 "}
end.
|
코드에서는 yaws_api 모듈을 사용하여 POST 요청의 값을 획득한 다음, 몇 가지 간단한 검증 절차를 거치고 나서 적합한 트랙백 핑인 경우 얼랭에서 제공하는 디스크 튜플 저장소인 DETS에 데이터를 저장 한 다. 이렇게 저장된 데이터를 보여주려면 간단한 Yaws 페이지를 하나 만들면 될 것인데, 이 부분은 지면 관계상 생략하니 관심있는 독자는 직접 한번 만들어 보길 바란다.
다음은 이 서버의 작동을 테스트한 것이다. 파이어폭스의 확장 기능 중의 하나인 Poster 를 이용하여 http://localhost:8000/tb/1 과 같은 식으로 트랙백을 호출하였다. 이 경우 다음 그림과 같이 정상적으로 처리되었다는 결과가 나오는 것을 확인할 수 있다.
그림 3. 트랙백 처리 결과

지금까지 Yaws의 기본 개념과 간단한 사용법, 그리고 Yaws 의 appmod 에 대해 알아보면서 중간중간 얼랭 언어의 기본적인 내용도 짚어 보았다. 또한 간단하지만 트랙백 서버도 만들어 보았다. Yaws로 만든 우리의 이 트랙백 서버는, 얼랭에서 OTP 라고 부르는 무정지 플랫폼의 장점을 고스란히 활용하고 있기 때문에, 사이트 트래픽이 많아질 경우 그 진가를 제대로 발휘 할 것이다.
다음 회 에서는 얼랭으로 작성된 웹 프레임워크인 ErlyWeb을 소개할 예정이다. 참고로 ErlyWeb은 루비온레일스에서 영감을 얻어 개발된 오픈 소스 MVC 프레임워크로서, 이번 호에서 설명한 Yaws 의 appmod 로서 동작한다. 그럼 다음 회를 기대하자 .
참고자료
Yaws 사이트 : http://yaws.hyber.org/index.yaws
Yaws 와 아파치 의 성능 비교 : http://www.sics.se/~joe/apachevsyaws.html
Joe Armstrong, 『 Programming Erlang 』 , Pragmatic Programmer, 2007
Trackback Technical Specification : http://www.sixapart.com/pronet/docs/trackback_spec
이 문서 북마킹 하기

|
| 이제 전문가의 글을 단순히 ‘보는 것’에서, 직접 여러분이 developerWorks의 필자가 될 수 있습니다. IBM developerWorks를 통해 공유하고 싶은 지식이 있으신 분들은 원고 기획안을 접수해주세요. 채택되신 분께는 소정의 원고료를 드립니다. |
|
|
|
[지난 Open dW 보기] |
|
 |
|