본문 바로가기
프로그래밍/Erlang

UNIX 개발자 관점에서 Erlang 배우기

by o테리o 2013. 8. 26.

UNIX 개발자 관점에서 Erlang 배우기

   Erlang은 아키텍처와 함수적 특성을 선호하는 고유한 프로세스로 인해 멀티 코어 시대에 매우 적합합니다. 이 기사에서는 Erlang 프로그래밍과 관련된 기본적인 내용을 배웁니다.

소개

UNIX 개발자이거나 시스템 관리자라면 아마도 선호하는 도구나 도구 세트가 있을 것이다. 아마도 자주 사용하는 도구는 Perl, Python, sed 및 awk 또는 Ruby일 것이다. 그렇지 않고 Java™나 C++을 애용할 수도 있을 것이다. 일단 특정 도구 세트에 익숙해지면 새로운 언어를 배우기 위해 시간을 소비하는 것을 정당화하기는 매우 어렵다. 이러한 노력을 정당화할 수 있을만한 이유가 있어야 한다. Erlang은 배울만한 충분한 이유가 있다. 이 기사에서 필자는 Erlang을 배워야 하는 이유와 Erlang을 시작하는 방법을 설명한다.

멀티 코어 시스템 시대는 이미 도래했고 확대되고 있지만, 이에 대한 준비는 아직 미흡한 상황이다. 대부분의 언어는 상태를 공유하는 스레드 또는 단일 코어의 단일 스레드로 실행을 제한하는 글로벌 잠금(더 좋지 않음)과 같은 취약한 동시성 메커니즘에 의존한다. 전형적인 범용 nix 서버에는 코어가 24개 있다. 오류가 발생하기 쉬운 매우 복잡한 스레드 코드나 코어가 24개인 시스템에서 코어를 하나만 사용하지만 여전히 CPU에 속박되어 있는 코드를 작성하기는 쉽다. 이러한 문제점을 피할 수 있는 한 가지 해결책은 확장 가능하도록 설계된 함수형 언어를 사용하는 것이다. Erlang에는 변하기 쉬운 상태가 없는데, 이는 nix 전문가들이 주로 사용하는 언어와는 매우 다른 점이다. 이외에도 Erlang에서는 본질적으로 동시성이 중요하게 다루어지고 있다. 사실상, 다른 언어는 대부분 오브젝트를 중심으로 빌드되는 반면에 Erlang은 프로세스를 중심으로 빌드된다. Erlang은 운영 체제 대신 동시성 메커니즘을 제어하기 때문에 Erlang에서는 일반적으로 수천 또는 수백만 개의 프로세스가 생성된다. Erlang에서는 상황이 다르며 오늘날의 컴퓨팅 과제를 정확히 해결할 수 있는 방법은 다양할 수 있다.

대화식 Erlang 쉘

명령행을 애용하는 개발자라면 Erlang의 대화식 쉘을 유용하게 사용할 수 있을 것이다. 개발자는 이 대화식 쉘을 사용하여 표현식을 입력하고 코드를 컴파일 할 수 있을 뿐만 아니라 프로세스와 통신할 수도 있다. 또한, 이 대화식 쉘은 LOM(Lights Out Management) 카드를 사용하는 *nix 시스템 및 복잡한 가상화 시스템을 관리할 때와 같은 기분을 느낄 수 있게 멋지게 설계되어 있다. 여기에서는 먼저 독자가 Erlang을 해당 시스템에 설치했다고 가정한다. Erlang을 설치하지 않은 경우에는 참고자료 섹션에 있는 정보를 참고하여 Erlang을 다운로드하고 설치한다. Erlang을 설치하면 해당 경로에서 "erl"을 찾을 수 있다. "erl"을 입력하면 대화식 프롬프트가 표시되는데, 여기에 명령을 입력할 수 있다.

대화식 쉘: Part A

lion% erl Erlang R14B (erts-5.8.1) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.8.1 (abort with ^G) 1>

도움말 메뉴를 확인하려면 아래와 같이 help 명령을 실행한다. 각 표현식은 언제나 마침표로 끝나야 한다. 이렇게 해야 명령 해석기가 명령을 실행한다. 또한, 아래에 있는 도움말 메뉴 출력에 표시되어 있듯이 언제든지 "q()."를 입력하면 쉘을 중단할 수 있다.

대화식 쉘: 도움말 출력

Eshell V5.8.1 (abort with ^G) 1> help(). ** shell internal commands ** b() -- display all variable bindings e(N) -- repeat the expression in query < N > f() -- forget all variable bindings f(X) -- forget the binding of variable X h() -- history history(N) -- set how many previous commands to keep results(N) -- set how many previous command results to keep catch_exception(B) -- how exceptions are handled v(N) -- use the value of query < N > rd(R,D) -- define a record rf() -- remove all record information rf(R) -- remove record information about R rl() -- display all record information rl(R) -- display record information about R rp(Term) -- display Term using the shell's record information rr(File) -- read record information from File (wildcards allowed) rr(F,R) -- read selected record information from file(s) rr(F,R,O) -- read selected record information with options ** commands in module c ** bt(Pid) -- stack backtrace for a process c(File) -- compile and load code in < File > cd(Dir) -- change working directory flush() -- flush any messages sent to the shell help() -- help info i() -- information about the system ni() -- information about the networked system i(X,Y,Z) -- information about pid l(Module) -- load or reload module lc([File]) -- compile a list of Erlang modules ls() -- list files in the current directory ls(Dir) -- list files in directory < Dir > m() -- which modules are loaded m(Mod) -- information about module < Mod > memory() -- memory allocation information memory(T) -- memory allocation information of type < T > nc(File) -- compile and load code in < File > on all nodes nl(Module) -- load module on all nodes pid(X,Y,Z) -- convert X,Y,Z to a Pid pwd() -- print working directory q() -- quit - shorthand for init:stop() regs() -- information about registered processes nregs() -- information about all registered processes xm(M) -- cross reference check a module y(File) -- generate a Yecc parser ** commands in module i (interpreter interface) ** ih() -- print help for the i module true 2>

이러한 모든 명령을 입력하여 해당 명령이 어떤 기능을 수행하는지 확인하는 것도 매우 유익할 것이다. 실제로 코드를 작성하는 과정을 살펴보기 전에 Erlang에서는 상태가 변하지 않는다는 점을 기억한다. 따라서 변수를 설정할 때는 아래와 같은 결과가 표시될 수도 있다.

대화식 쉘: Part B

Eshell V5.8.1 (abort with ^G) 1> Var = 1. 1 2> Var = 2. ** exception error: no match of right hand side value 2 3>

물론 새로운 언어를 배울 때는 언제나 "Hello World" 예제가 적합하다.

대화식 쉘: Part C

4> io:format("Hello World~n"). Hello World ok

Erlang에 대한 종합적인 강의에서는 몇 가지 사항을 더 다루어야 하지만, 자주 사용되는 데이터 유형을 나열하는 것으로 마무리하도록 하자.

대화식 쉘: Part D

5> List = [1,2,3]. [1,2,3] 6> [Head|Tail] = List. [1,2,3] 7> Head. 1

이 예제에서는 패턴 일치를 사용하여 목록의 헤드와 테일을 추출했다. Erlang에서는 패턴 일치가 중요한 역할을 한다. 이 기사의 끝 부분에 있는 참고자료에서 패턴 일치에 관해 자세히 읽어보는 것이 유용할 것이다.

Erlang 모듈 작성 및 컴파일

Erlang 애플리케이션을 작성하는 과정에는 대화식 쉘에 표시되어 있는 표현식뿐만 아니라 실제 모듈을 작성하는 과정도 포함되어 있다. 먼저 개발 환경에 관해 간단히 살펴보자. 중대한 Erlang 애플리케이션 개발에 참여할 계획이 있는 경우에는 Erlide 플러그인이 있는 Eclipse 또는 Emacs를 사용하려고 할 수도 있다. 그렇지 않고 Erlang을 사용하여 경량 프로그래밍을 하는 경우에는 vim이 매우 적합할 수도 있다.


Erlide 플러그인이 있는 Eclipse와 같은 IDE를 사용 중이면 편리하게도 모듈 코드를 작성하자마자 이 코드가 자동으로 beam 파일로 컴파일된다. 또는 컴파일이 Erlang 대화식 명령 해석기 내부에서 수행되거나 erlc 명령행 컴파일러를 통해 수행될 수 있다. 아래에 있는 예제는 간단한 모듈을 beam 파일로 컴파일하는 예제이다.

fingerprint.erl

%% This is a module that gets the operating system type -module(fingerprint). -export([get_os/0]). get_os ()-> os:cmd("uname").

이 코드를 대화식으로 컴파일하려면 다시 erl을 실행한다.

모듈을 대화식으로 컴파일

lion% erl Erlang R14B (erts-5.8.1) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.8.1 (abort with ^G) 1> c(fingerprint). {ok,fingerprint} 2> fingerprint: get_os/0 module_info/0 module_info/1 2> fingerprint:get_os(). "Darwin\n" 3> q(). ok

쉘에서 직접 나열하면 fingerprint.beam 파일이 생성되었다는 것을 알 수 있다. 또는 다음과 같이 실행하여 이 beam 파일을 작성했을 수도 있다.

lion% erlc fingerprint.erl

EUnit을 사용한 Erlang 유닛 테스트

Erlang 코드를 작성 할 경우에는 고가용성 시스템을 구축할 수 있는 기회가 생긴다. 이러한 경우에는 처음부터 세부사항에 주의를 기울여서 해당 코드의 유닛 테스트를 작성하는 것이 중요하다. 이전에 설계한 모듈을 이용하여 빌드하는 경우에는 테스트가 다음과 같이 수행된다.

EUnit 예제

%% This is a module that gets the operating system type -module(fingerprint_with_test). -include_lib("eunit/include/eunit.hrl"). -export([get_os/0]). get_os ()-> os:cmd("uname"). get_os_test ()-> get_os().

기본적으로 수행해야 할 작업은 EUnit을 사용하여 모듈을 테스트하는 것이며, 앞서 살펴본 바와 같이 헤더를 삽입하고 "_test" 패턴과 일치하는 함수의 이름을 지정해야 한다. 이렇게 하면 모든 테스트 함수가 자동으로 내보내어져서 아래에 있는 테스트 함수를 통해 실행된다.

대화식으로 컴파일하여 테스트한 EUnit

Eshell V5.8.1 (abort with ^G) 1> c(fingerprint_with_test). {ok,fingerprint_with_test} 2> fingerprint_with_test:test(). Test passed. ok 3>

Erlang을 스크립트 언어로 사용하거나 명령행에서 사용

Erlang을 컴파일하지 않고 스크립트 모드로 실행할 수도 있다. 이렇게 하려면 Erlang R11B4 버전 이상의 사본을 실행해야 한다. 위에 있는 예제를 약간 수정하여, 즉 다음과 같이 #!가 있는 행과 기본 함수를 추가하여 이 예제를 스크립트로 변경할 수 있다.

대화식으로 컴파일하여 테스트한 EUnit

#!/usr/local/bin/escript get_os ()-> os:cmd("uname"). main(_) -> io:format("OS Platform: ~p~n", [get_os()]).

다음은 결과물이다.

lion% chmod +x fingerprint.escript lion% ./fingerprint.escript OS Platform: "Darwin\n"

마지막으로 Perl이나 Ruby와 같이 명령행을 이용하여 라이너를 하나 작성할 수도 있다. 이와 같은 예제는 다음과 같다.

lion% erl -eval 'io:format("OS Platform: ~p~n", [os:cmd("uname")])' -noshell -s init stop OS Platform: "Darwin\n"

분산 컴퓨팅을 이용하면 Mac OS X와 Ubuntu 간의 원격 메시징을 수월하게 처리할 수 있음

몇 가지 기본적인 사항을 처리하면 서로 통신할 수 있는 프로세스 클러스터를 빌드하는 데 필요한 매우 유익한 자료를 얻을 수 있다. 위치 투명성 덕택에 단일 시스템에서 클러스터를 테스트한 후, 이 클러스터를 전 세계에 있는 시스템에서 실행할 수 있는 대용량 분산 클러스터로 이동하기가 수월해졌다. 다음에는 필자의 랩탑에 있는 Ubuntu(가상 머신을 통해)와 Mac OS X에서 Erlang을 시작하고 단지 두 행으로 된 코드를 이용하여 원격으로 코드를 실행한다. 이 예제에서는 로컬 DNS 및 방화벽 설정과 같은 문제점이 없다고 가정한다. 만일 이러한 문제점이 있는 경우에는 올바르게 구성한다.

먼저 다음과 같이 Ubuntu와 OS X 노드에서 Erlang을 실행한다.

mac% erl -name mac -setcookie test

ubuntu% erl -name mac -setcookie test

이 작업을 수행한 후에는 OS X 시스템의 통신을 설정한 후, 다음과 같이 노드 함수를 호출하여 원격 노드를 볼 수 있는지 확인한다.

(mac@lion.local)1> net_adm:ping('ubuntu@ubuntu.localdomain'). pong (mac@lion.local)2> nodes(). ['ubuntu@ubuntu.localdomain']

이제 다음과 같이 임의의 코드를 실행할 수 있다.

(mac@lion.local)15> rpc:call('ubuntu@ubuntu.localdomain', os, cmd, ['uname -a']). "Linux ubuntu.local 2.6.35-24-generic #42-Ubuntu SMP Thu Dec 2 01:41:57 UTC 2010 i686 GNU/Linux\n"

Erlang이 실제로 얼마나 강력한지 그리고 Erlang으로 프로세스 간 통신(IPC)을 수행하는 것이 얼마나 간단한지 충분히 이해하려면 다소 시간이 필요하다. 이전의 간단한 예제에서도 살펴볼 내용은 훨씬 더 많지만, 작동 중인 Erlang의 강력한 기능에 대한 개념을 이해하는 데는 이것만으로도 충분하다.

결론

이 기사에서는 이론을 살펴보면서 Erlang을 사용하여 코딩 작업을 연습했지만 배워야 할 것은 훨씬 더 많다. 미래에는 Erlang으로 작성된 대규모 프로덕션 시스템이 많이 증가할 것이다. 최근에 발표된 Harvard Business Review 기사에서는 "부족"이 혁신에 매우 중요한 요소라고 언급되어 있다. 이제 사람들은 현재의 고도로 확장 가능한 시스템을 다루는 과정에서 부족하다는 것이 무엇인지 경험하고 있다. 이 때가 바로 경쟁 우위를 확보하고 혁신적인 Erlang 언어의 전문가가 되어야 할 시기이다.

Erlang을 자세히 배우고 싶으면 다음과 같은 조언을 따르도록 한다. Erlang 관련 책을 가능한 한 권 이상 읽어본다. 새로 발행된 세 권의 책 중에서 선택한다. 이 책들은 모두 우수한 책이다. 이외에도 tryerlang.org에 있는 대화식 튜토리얼을 처음부터 끝까지 살펴본다. 이 튜토리얼은 참고자료 섹션에 언급되어 있다. 마지막으로 CouchDB, RabbitMQ 및 Ejabbrd와 같이 실제로 실행 중인 Erlang 프로젝트 중 일부를 시도해 본다.

출처 : 한국IBM

제공 : DB포탈사이트 DBguide.net