Distributed Untar.

내가 사용하는 서버중에 core가 8개인 서버가 있다. 메모리도 4기가 정도 되고…

오늘 이 서버에 데이터를 옮기로 압축을 풀고 있는데 이 압축 푸는 속도가 너무 느리고 htop을 쳐서 보면 1개 코어만 쓰고 나머지는 핑핑 놀고 있어서 나중에 써먹을 것을 생각해서 코어에 분산시켜서 untar를 하는 Erlang 프로그램을 짜봤다.

[CODE js]
#!/usr/bin/env escript

main(_) ->
    OptionList = [{cwd, “.”},compressed],    
    stdioloop(io:get_line(standard_io, ”), OptionList, []).

stdioloop(eof, _OptionList, []) ->
    io:format(“finished~n”);

stdioloop(eof, _OptionList, PidList) when length(PidList) > 0 ->
    io:format(“finished 1~n”),
    receive
        {Pid, RetValue} when is_pid(Pid)->
            io:format(“receive Pid : ~p~n”, [Pid]),
            NewPidList = lists:delete(Pid, PidList),
            io:format(“~s File processing complete ~p ~n” , RetValue),
            stdioloop(eof, _OptionList, NewPidList)
    end;

stdioloop(FileName, OptionList, PidList) ->
    StrippedFile = string:strip(FileName,right ,$\n),
    io:format(“file ~s~n”, [StrippedFile]),
    From = self(),
    Pid = spawn(fun() -> tarextract(StrippedFile,OptionList,From) end),
    io:format(“Pid : ~p~n”, [Pid]),
    %Pid = spawn(distribute_untar, tarextract, [FileName,OptionList,self()]),
    stdioloop(io:get_line(standard_io, ”), OptionList, [Pid|PidList]).

tarextract(FileName, OptionList, From) ->
    From ! {self(), [FileName, erl_tar:extract(FileName, OptionList)]}.

[/CODE]

부푼꿈을 안고 코드를 작성했다.

stdin으로 파일이름을 입력 받고, 그 파일 이름을 가지고 각 파일의 압축을 푸는 작업에 spawn을 걸어 각 프로세스의 반환값을 기다리는 간단한 프로그램이다.

몇가지 테스트를 해보고 잘 되는것을 확인을 해본다음에 바로 서버에 돌렸다.
아주 훌륭하게도 아래와 같은 모습을 보여줬다.
단 한개의 코어도 놀지 않는다. ^^

사용자 삽입 이미지

결과가 더 빨리나온다는건 안봐도 비디오다.

참고로 이 프로그램은 보완할 점이 몇가지 있다.
프로세스를 띄워 압축을 여러개 풀때 몇몇 파일은 메모리 초과로 인해 로딩을 하지 못하는데, 그때 error code를 봐서 다시 나중에 메모리가 여유있을때 다시 띄워줘야 한다.
그리고 위의 tarextract메서드에서 내부 erl_tar라는 라이브러리를 사용하는데 이것보다 os:cmd()함수를 사용해 직접 tar 명령을 실행 하는것이 메모리를 훨씬 적게 사용한다는걸 확인했다.

아래는 실행 로그다.

gogamza@localhost:~/doc_2nd$ cat files | ../distribute_untar.erl
file 2nd_1_doc.tar.gz
Pid : <0.29.0>
file 2nd_2_doc.tar.gz
Pid : <0.31.0>
file 2nd_3_doc.tar.gz
Pid : <0.33.0>
file 2nd_4_doc.tar.gz
Pid : <0.35.0>
file 2nd_5_doc.tar.gz
Pid : <0.37.0>
file 2nd_6_doc.tar.gz
Pid : <0.39.0>
finished 1
receive Pid : <0.29.0>
2nd_1_doc.tar.gz File processing complite “2nd_2_wm_doc.txt\n2nd_3_wm_doc.txt\n”
finished 1
receive Pid : <0.33.0>
2nd_3_doc.tar.gz File processing complite “2nd_6_wm_doc.txt\n2nd_7_wm_doc.txt\n”
finished 1
receive Pid : <0.39.0>
2nd_6_doc.tar.gz File processing complite “2nd_12_wm_doc.txt\n2nd_13_wm_doc.txt\n”
finished 1
receive Pid : <0.35.0>
2nd_4_doc.tar.gz File processing complite “2nd_8_wm_doc.txt\n2nd_9_wm_doc.txt\n”
finished 1
receive Pid : <0.37.0>
2nd_5_doc.tar.gz File processing complite “2nd_10_wm_doc.txt\n2nd_11_wm_doc.txt\n”
finished 1
receive Pid : <0.31.0>
2nd_2_doc.tar.gz File processing complite “2nd_4_wm_doc.txt\n2nd_5_wm_doc.txt\n”
finished

각 프로세스의 종료 순서가 꼭히 프로세스가 만들어진 순서로 진행되지 않는다를걸 알 수 있다.

정확히 시간을 측정해야 하지만, 훨씬 빠르게 끝나서 굳이 그럴필요 없을듯 하다.

CC BY-NC 4.0 Distributed Untar. by from __future__ import dream is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.