July 2009 Archives

예전에 기대되는 Perl 신간 서적에서




Automating System Administrationwith Perl: Tools to Make You More Efficient 란 책에 대해서 언급한적이 있는데 오늘 책을 구해서 대강 훑어보았다.

이번 2판이 1판과 다른 점은 내용이 보강된 점도 있지만 가장 큰 변화는 뭐니뭐니해도 Perl 코드 형식이 최신경향으로 전부 바뀌었다는 점이다. Perl은 범용언어이지만 시스템관리 쪽에서도 많이 쓰여왔는데 특히 시스템관리쪽 코드들은 과거 Perl 4시절 코드형태를 띄는 경우가 많으며 요즘도 그런 식으로 Perl 코딩하는 사람들을 종종 본다. 일례로 1판과 2판의 같은 기능을 하는 코드를 비교해보자.

<1판 코드>

use User::pwent;

$shells = "/etc/shells";
open (SHELLS,$shells) or die "Unable to open $shells:$!\n";
while(<SHELLS>){
    chomp;
    $okshell{$_}++;
}
close(SHELLS);

while($pwent = getpwent()){
   warn $pwent->name." has a bad shell (".$pwent->shell.")!\n"
       unless (exists $okshell{$pwent->shell});
}
endpwent();


<2판 코드>

use User::pwent;

my $shells = '/etc/shells';
open my $SHELLS, '<', $shells or die "Unable to open $shells:$!\n";

my %okshell;
while (<$SHELLS>) {
    chomp;
    $okshell{$_}++;
}
close $SHELLS;
while ( my $pwent = getpwent() ) {
    warn $pwent->name . ' has a bad shell (' . $pwent->shell . ")!\n"
        unless ( exists $okshell{ $pwent->shell } );
}
endpwent();


현대 Perl코드는 거의 필수적으로 strict와 warnings 프래그마를 사용하여

#!/usr/bin/perl
use strict;
use warnings;

로 코드를 시작한다. 1판의 소스에서 이 두 줄을 추가한다면 $shell = "/etc/shells"; 에서부터

Global symbol "$shells" requires explicit package name at ...

이런 에러가 나면서 동작하지 않을 것이다. 보통 여기서 strict와 warnings를 쓰라고 하는 건 어디서 들어본 것 같은데 쓰면 변수선언부터 에러가 나고 my는 서브루틴 같은 곳에서 렉시컬 변수로 쓴다고 대강 알고 있지만 이것이 정확히 뭘 의미하는지 모르니 1판 같은 소스를 계속 쓰게 되는 악순환을 겪게 된다. 2판의 소스도 strict와 warnings 프래그마를 넣지는 않았지만 넣어도 완벽하게 아무런 문제를 일으키지 않고 동작하는 코드이다. 특히 전역변수랍치고 $shells = "/etc/shells"; 이런 식으로 my,our,local같은 변수 범위선언자를 붙이지 않고 변수를 선언해서 사용하는 Perl코드를 쓰는 사람을 보면 이 사람 Perl 기초를 제대로 이해하지 못하고 나도는 예제코드들 보고 대강 베껴 쓰는구나 하고 생각하게 된다.

1판 소스가 어떻게 2판 소스처럼 바뀌게 되는지 알고 싶으면 최신 스타일 Perl로 개과천선하기를 읽어보시고 이제 제발 1판 같은 Perl코드는 양산하지 말아 주셨으면 좋겠다.

하지만 2판에서도 최신경향 Perl방식을 따르지 않는 부분이 간혹 있는데 그것은 다음과 같은 객체의 메소드를 호출하는 방법이다.

use Win32::Perms;
$acl  = new Win32::Perms();

위 코드는 Win32::Perms라는 객체를 간접호출 방식으로 생성하는 코드인데 마치 Java,C++의 new생성자와 유사한 형식이라 익숙해 보일 수도 있지만 Perl에서는 여러 가지 side effect를 회피하기 위해 다음과 같이 직접호출 방식을 쓰는 게 좋으며 그것이 최신 형식이다.

use Win32::Perms;
my $acl  = Win32::Perms->new();

Perl OOP에 관한 내용은 새로운 Perl OOP로 개과천선하기를 참고


이상 코드형식에 대해서 얘기했지만, 2판은 요즘 새롭게 등장한 Windows용 Strawberry Perl도 언급하는 등 Perl의 최신정보들을 최대한 반영하려는 노력을 보이고 있으며 1판에 비해 시스템관리 전 영역에 걸쳐 많은 내용이 보강되었고 Perl이 다양한 플랫폼에 포팅된 언어 인만큼 UNIX/LINUX뿐만 아니라 Windows 플랫폼에 관해서도 많은 부분을 할애하여 Perl을 플랫폼을 가리지 않는 시스템관리용 언어로 사용할 수 있도록 배려하고 있다.

책이 포함하고 있는 자세한 내용은 다음과 같으며

    * Manage user accounts
    * Monitor filesystems and processes
    * Work with configuration files in important formats such as XML and YAML
    * Administer databases, including MySQL, MS-SQL, and Oracle with DBI
    * Work with directory services like LDAP and Active Directory
    * Script email protocols and spam control
    * Effectively create, handle, and analyze log files
    * Administer network name and configuration services, including NIS, DNS and DHCP
    * Maintain, monitor, and map network services, using technologies and tools such as SNMP, nmap, libpcap, GraphViz and RRDtool
    * Improve filesystem, process, and network security

This edition includes additional appendixes to get you up to speed on technologies such as XML/XPath, LDAP, SNMP, and SQL. With this book in hand and Perl in your toolbox, you can do more with less -- fewer resources, less effort, and far less hassle.

시스템관리자 뿐만 아니라 개발자들에게도 시스템을 이해하는데 아주 도움이 되는 책이라고 생각한다.
JEEN님의 [ SSH ] .ssh/config 에 대해서... 라는 블로그 포스팅을 보고 뭔가 복잡한 것 같아 윈도우용 ssh클라이언트인 putty에서 socks proxy를 지정해서 ssh접속하는 기능이 생각나서 LINUX의 일반 ssh 명령에서는 어떻게 사용할까 궁금해서 여러자료를 찾아서 시도해봤다.

JEEN님의 문제는 A,B 서버가 있다면 B서버는 A서버를 통해서만 접속할 수 있어서 편리하게 B서버에 접속하고 싶다는 것인데 JEEN님의 방법은 ssh설정을 사용해서 B서버에 접속을 하면 차례로 A,B 서버 인증을 거치며 들어가는 것이다.

하지만 A가 proxy서버의 역할을 한다면 A서버를 proxy로 지정하고 B에 접속하면 B에 대한 인증만 통과하면 된다. 그럼 먼저 A를 proxy서버 역할을 하도록 ssh의 Dynamic Port Forwarding기능을 이용하여 다음처럼

ssh -N -D localhost:8888 user@hostA

명령을 내리면 password를 물어보는데 password를 입력하여  A서버에 로그인한 상태가 되고나면 이제 localhost의 8888 포트(포트는 마음대로 바꿔도 됨)는 A서버와 ssh채널로 이어져서 proxy처럼(socks4, socks5 proxy프로토콜을 지원한다.) 동작하기 때문에 이것을 proxy로 지정한 모든 접속은 ssh연결을 통해 A서버를 통해서 나가게 된다.

그러면 이제 proxy를 지정하고 B서버에 접속하려고 하면 실제 접속은 A서버를 통해서 이루어지게 될 것이므로 문제 없이 접속될 것이다.

여기서 일반적인 ssh명령이 proxy( localhost:8888 )를 사용하게 하려면 어떻게 할까?

먼저 connect라는 유틸리티를 여기서 받은 다음 gcc -o connect connect.c 로 컴파일하고 컴파일된 connect 바이너리를 path가 잡힌곳에 복사한다. 그 다음

ssh -o "ProxyCommand connect -5 -S localhost:8888 %h %p" user@hostB

처럼 명령을 내리면 proxy(ssh채널로 이어진 A서버)를 통해서 B서버로 접속하게 된다.

(옵션들의 사용법과 동작방식은 메뉴얼에 다 잘 나와있으므로 자세한 설명은 생략...)



추가:
connect를 사용해서 proxy를 지정하는 방법은 별도의 shell 스크립트를 만들거나 ssh설정에 미리 넣어놓을 수 있지만 약간 번거로운 감이 있다. 이때는 dante( http://www.inet.no/dante/ )라는 socks서버에 포함되어 있는 socksify라는 명령을 이용해서도 socks proxy를 통해서 ssh접속을 할 수 있다. ubuntu라면 sudo apt-get install dante-client 로 패키지를 설치하고 나면 socksify라는 명령도 같이 설치된다. socksify가 사용하는 proxy를 지정하기 위해서는 /etc/dante.conf 파일을 열어 다음 내용을 추가해준다.

route {
        from: 0.0.0.0/0   to: 0.0.0.0/0   via: 127.0.0.1 port = 8888
        protocol: tcp udp                # server supports tcp and udp.
        proxyprotocol: socks_v4 socks_v5 # server supports socks v4 and v5.
        method: none #username           # we are willing to authenticate via
                                         # method "none", not "username".
}

설정이 어떤 의미를 가지는지는 주석이 다 설명해주고 있으므로 패스~

이제

socksify ssh user@hostB

라고 명령을 내리면 socksify뒤에 오는 명령이 접속하려는 네트웍접속은 후킹되어서 자동으로 socks proxy를 통해서 나가게 된다. socksify는 ssh뿐만 아니라 기본으로 proxy설정을 지원하지 않는 어플리케이션에도  모두 사용할 수 있다는 장점이 있다.
보통 UNIX Shell Script를 만들 때 파일의 첫 줄에

#!/bin/sh

처럼 넣는 것을 shebang line이라고 한다.

이것은 어떤 스크립트파일이 실행될 수 있도록 권한을 주고 해당 스크립트를 실행시켰을 때 shebang line 이후의 줄들을 어떤 명령이 해석할 것인가를 지정해주는 것으로 Perl같은 동적 스크립트언어( Python,Ruby도 마찬가지)에도 마찬가지로 다음과 같이 적용된다.

<test.pl>
#!/usr/bin/perl
print "Hello World\n";

<실행>
chmod a+x test.pl
./test.pl

만약에 shebang line이 없는 상태에서 적절한 해석기를 통해 실행시키려면

perl test.pl

처럼 [스크립트해석기] [스크립트] 형식으로 명령을 실행시켜야 할 것이다. 이 경우에는 해석기를 지정하여 스크립트를 실행시키므로 스크립트 파일에 굳이 shebang line을 쓸 필요가 없다.

그런데 가끔 보면 Windows용 Perl ( Activestate Perl 또는 Strawberry Perl )을 사용해서 Perl 프로그래밍 하는 사람들이

#!C:/Perl/bin/perl.exe

print "Hello World\n";

이런식으로 UNIX에서 했던 것과 같이 perl실행파일이 있는 Windows 드라이브 상의 path를 그대로 요상한 모양으로 적어주는 경우를 종종 보는데, 간단히 결론만 말하자면 Windows에서는 shebang line은 아무런 의미가 없다.

스크립트를 Perl을 통해 실행시키고자 하면 unix에서와 마찬가지로 perl 바이너리가 path에 잡혀 있다면

perl test.pl

하면 실행된다. 그럼 unix에서 스크립트 파일을 실행가능하도록 해서 스크립트 파일이름만으로 실행되게 하려면 어떻게 해야할까?

방법은 단지 Windows가 특정확장자의 파일을 어떤 실행파일을 통해서 열 것인가를 지정하는 기능을 사용하는 것이다.( txt파일을 더블클릭하면 notepad가 실행되며 파일이 열리는 것을 떠올리면 됨 ) 이것은 파일탐색기 메뉴를 통해서 설정할 수도 있고 다음과 같은 dos명령을 통해서도 설정할 수 있다.

ASSOC .pl=PerlScript
FTYPE PerlScript=C:\strawberry\perl\bin\perl.exe %1 %*

하지만 개인적으로 Windows에서 이런 식으로 사용하는 건 별로 좋아하지 않는다.

다시 말하면 Windows에서 shebang line은 단지 장식용(?)일 뿐이다. 따라서 응용력을 과도하게 발휘해서 이상한 모양의 shebang line을 쓰지말고 나중에 UNIX에 가져가서라도 그냥 쓸 수 있게 보통 UNIX에서 하던 것처럼 그냥  #!/usr/bin/perl 이라고 해주자.

그런데 UNIX에서도 shebang line이 꼭 #!/usr/bin/perl 일 필요는 없다. 대게는 UNIX에서 기본으로 perl 바이너리가 /usr/bin에 있기 때문에 저렇게 쓰는 것이지 만약에 자신만의 Perl을 소스를 받아서 따로 컴파일해서 /usr/local/bin/perl 에 깔았고 그 Perl을 이용하고 싶으면  shebang line을  #!/usr/local/bin/perl 이라고 지정하면 된다.

그런데 시스템에 여러 종류의 Perl이 존재할 경우 필요할 때마다 shebang line을 변경하는 것은 매우 귀찮은 일일 것이다. 이런 경우에는 스크립트 소스는 건드리지 않고 PATH 환경변수만 적절하게 바꿔서 유연하게 사용할 수 있는 방법이 있다.

사용하고 싶은 Perl 바이너리가 있는 경로를 PATH환경변수에 세팅하고 ( 만약 perl 바이너리가 PATH환경변수의 여러 곳에 있다면 예- /usr/local/bin, /usr/bin PATH환경변수에 먼저 나오는 것이 우선된다. )

#!/usr/bin/env perl

이라고 shebang line을 적어주면 PATH환경변수에서 가장 우선되는 perl 바이너리를 찾아 스크립트를 실행한다.

여기서 env는 뒤따르는 명령의 수정된 환경변수를 스크립트 해석시 적용하는 명령이다. perl은 컴파일되서 설치될 때 자신만의 고유의 라이브러리 경로등의 정보를 가지는데, 따라서 어떤 perl 바이너리가 실행되느냐에 따라 그러한 정보들이 다르게 적용되므로 env를 통해서 실제 실행되는 바이너리의 환경을 자동으로 적용될 수 있게 해주는 것이다.

            


Ruby on Rails는 Perl, Python에 밀려  그렇게 주목받지 못하던 Ruby라는 언어를 화려한 주류언어의 무대로 끌어올린 대표적인 스타 웹프레임웍이다.

Perl하면 옛날의 CGI기반 게시판 등 고리타분 한 인식을 가진 사람들도 있겠지만 그건 호랑이 담배피던 시절 이야기고 현재에는 Perl에도 Ruby on Rails 못지않은 많은 MVC기반 웹 프레임웍들이 존재한다. 그중에서 제일 대표적인 것이 Catalyst인데 최근 Ruby on Rails와 Catalyst의 성능을 비교한 흥미로운 글이 있어 소개하려고 한다.

예전 2009년 4월 Victor Igumnov란 사람이 Catalyst vs Ruby on Rails의 성능을 비교한 글이 있었는데 그때 당시 결과는 Ruby on Rails 가 Catalyst 보다 약 62%정도 빨랐다. 그래서 인터프리터의 성능이 여타 언어보다 빠르다고 알려진 Perl이 비교적 느리다는 Ruby에서 구현된 웹프레임웍 보다 성능이 떨어지는데 의문을 품고 분석한 결과 Catalyst의 Controller구현에서 다중상속에서 메소드의 연속적 호출에 쓰이는 NEXT 모듈의 병목 때문에 성능이 떨어짐을 알아내고 Catalyst개발자에게 알려 이것을 새로운 C3 모듈로 교체하여 성능을 개선했는데

그 후 이런 개선사항이 반영된 새로운 Catalyst 5.8 버젼으로 다시 둘의 성능을 비교했더니 놀랍게도 Catalyst가 single process일때 Ruby on Rails 보다 135%, forking 된 multi process 환경에서는 471% 빨랐다고 한다.

Catalyst는 약간의 진입 장벽은 있지만 여타 프레임웍과는 다르게 ORM과 Template엔진을 필요에 따라 여러 가지로 교체해서 사용할 수 있어 개방적이고 확장성이 뛰어나다고 알려져 있다.

그런데 벤치마크결과에서 더 놀라운 것은 성능이 대폭적으로 향상된 Catalyst 5.8은 예전 5.7대 버젼에서는 OOP구현을 위해 Class::Accessor::Fast 라는 모듈을 사용한데 반해 Moose 라는 Meta Object Protocol 기반의 진보된 OOP프레임웍으로 교체하였다는 것이다. Moose는 다소 번거로움이 많았던 Perl OOP구현을 어느 언어보다 편리하고 획기적이며 진보적인 방법으로 할 수 있도록 발전시킨 OOP프레임웍으로 다소 메모리를 좀 더 소비하고 속도가 떨어진다는 비판을 받았는데 Moose가 기반이 된 Catalyst 5.8의 성능이 이 정도로 나오는 걸 보면 그런 걱정은 기우에 지나지 않았나 생각된다.

Catalyst가 쓰이는 대표적인 서비스로는 일본 최대의 Social Network 싸이트인 mixi, 세계 최대규모 도색 동영상 싸이트 중 하나인 Youporn( Alexa 싸이트순위 44위 참고로 우리나라 최대 포털 naver는 60위권) 영국 BBC의 BBC News, BBC iplayer, Vox, Ticketmaster, Shopzilla, Takkle, Editgrid, IUseThis, MighTyV 등이 있다. ( Site running Catalyst )

Perl Catalyst 한 번 해보시지 않으시겠습니까?

참고: 또 다른 Catalyst vs Ruby on Rails 자료

About this Archive

This page is an archive of entries from July 2009 listed from newest to oldest.

June 2009 is the previous archive.

August 2009 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Creative Commons License
This weblog is licensed under a Creative Commons License.
Powered by Movable Type 4.21-en