2007년 2월 19일 월요일

웹서버 부하 분산을 위한 허접한 로드밸런싱 ^^;

웹서버가 그렇게 성능(Xeon 2.4, 스카시HDD, 1G RAM)이 떨어지는 것도 아닌데... 60만명이 넘는 회원을 가진 다음카페 회원들한테 메일한번 쏜 이후로 엄청난 접속에 거의 서버가 멎을 뻔 하였던 경험을 하였습니다.

그래서 생각한 것이 로드밸런싱인데... 허접한 제 실력에 로드밸런싱이란 것은 하기 힘든 작업이었죠.^^

그래도 어디서 들어본 것은 있는지 문득 생각난 것이 rsync와 Round-Robin이였습니다.^^

하지만 들어보기만 했지 직접 해 본적은 없어서... 어떻게 해야 할 지 난감하더군요..^^

어째든 맨땅에 헤딩은 그렇게 시작이 되었습니다.^^

여기서 많은 분들께 질문도 하고... 여기 저기 문서도 많이 찾아 봤습니다.^^



아직 완벽하지는 않은 듯 하니... 참고로 보시고..

물론 더 뛰어난 실력을 갖추신 분들은 더 좋은 로드밸런싱을 사용하시기 바랍니다. (skip... ^^)



그럼 하나 하나 제가 한 방법을 적어보도록 하겠습니다. 이하 존댓말 생략입니다.^^;





기존의 웹서버 A와 새롭게 추가하고자 하는 웹서버 B가 있다고 보자.



A서버의 아이피 : 192.168.1.1

B서버의 아이피 : 192.168.1.2



우선은 두 서버가 하나의 서버로 인식하기 위해서는 두 서버 모두 하나의 도메인을 가지고 있어야 한다. 따라서 DNS의 설정은 필수적이다.





1. DNS 설정(Round-Robin)



$TTL 86400

@ IN SOA ns.localhost.com. root.localhost.com. (

2003052901

21600

1800

1209600

86400)

IN NS ns.localhost.com.

IN A 192.168.1.1

www IN A 192.168.1.1

www IN A 192.168.1.2

www1 IN A 192.168.1.1

www2 IN A 192.168.1.2





위와 같이 zone 파일을 설정한다. 물론 named는 restart 해야 한다. 그러면 www.localhost.com이란 도메인은 192.168.1.1과 192.168.1.2 두개의 아이피를 가지게 된다. 이 상태에서 nslookup www.localhost.com이라고 하면... 다음과 같이 나온다.





Server: 168.126.63.1 --> 질의한 서버 아이피

Address: 168.126.63.1#53



Name: www.localhost.com

Address: 192.168.1.1 --> 결과값1

Name: www.localhost.com

Address: 192.168.1.2 --> 결과값2



이와 같이 나온다면 네임서버는 잘 설정한 것이다.^^





2. 웹서버의 설정



우선 두대 모두다 apache의 httpd.conf파일에 www.localhost.com 도메인을 설정해 두어야 한다. 만일 이미 다른 것으로 사용하고 있다면 apache의 가성서버 설정을 이용해야 한다.(물론 여기서 가상호스트 설정까지 살펴보지는 않겠다.^^) 기본적으로 두 서버의 DocumentRoot가 틀려도 되지만, 손 쉬운 관리를 위해서 경로를 같게 두는 것이 좋을 것이다.



ex)

A서버의 DocumentRoot - /usr/local/localhostSource

B서버의 DocumentRoot - /usr/local/localhostSource





3. rsync의 설정



이제 두대의 서버가 갖춰지고 두대 모두 동일한 도메인을 가지게 되었다면 두 서버의 소스가 동일하도록 할 차례이다. 이러한 것을 위해서 바로 rsync가 필요하다. rsync와 관련된 많은 참고문헌들을 뒤졌는데 결론적으로 '질주본능'님의 조언으로 성공하게 되었다. 이 자리를 빌어 감사하다는 말씀을 전한다. '질주본능'님이 쓰신 rsync 관련 내용을 보시고 싶으신 분은 http://www.phpschool.com/bbs2/inc_view.html?id=9985&code=tnt2&start=0&mode=search&field=title&search_name=&operator=and&period=all&category_id=&s_que=rsync 를 참고하기 바란다.



우선 rsync 는 ssh를 이용한 방법과 873 포트를 이용한 방법이 있다. ssh를 이용한 방법이 조금더 안정성 면에서 좋을 것이라는 생각에 시도하였지만 번번히 실패하게 되었고 결국에는 873포트를 이용한 rsync를 성공하게 되었다. ssh를 이용한 rsync에는 비밀번호를 물어보게 되는데 파일을 이용하여 비밀번호를 자동으로 입력할 수 있다고 하는데 잘 되지 않았다.(성공한 분은 비결좀 알려주시길...^^)





그럼 873포트를 이용한 rsync 설정 방법을 알아보도록 하자.



우선은 xinetd를 이용하여 rsync가 구동되므로 다음과 같이 설정을 해 줘야 한다.



#vi /etc/xinetd.d/rsync



# default: off

# description: The rsync server is a good addition to an ftp server, as it

# allows crc checksumming etc.

service rsync

{

disable = no

socket_type = stream

wait = no

user = root

server = /usr/bin/rsync

server_args = --daemon

log_on_failure += USERID

}





그 다음 rsync의 설정파일을 수정해 줘야 한다. rsync의 설정 파일은 rsyncd.conf 파일이다. 물론 이 파일은 원래 존재하지 않는다.(원래 존재하는데 필자만 없었을 수도 있다.) 한가지 주의할 것은 설정파일 이름이 rsync.conf가 아니라 rsyncd.conf란 것이다. 일부 tip에서 rsync.conf라고 하는데 이렇게 할 경우에는 rsync가 되지 않았다.



#vi /etc/rsyncd.conf



[www]

path = /usr/local/localSource

comment = webservice-dir

uid = root

gid = root

use chroot = yes

read only = yes

hosts allow = 192.168.1.2

max connections = 1

timeout = 300



여기서 [www] 은 닉네임이다. 즉 아래 설정 내용을 한번에 호칭하기 위해 사용하는 것이다. path는 rsync를 받고자 하는 소스가 존재하는 디렉토리를 정해주면 된다.

uid와 gid는 root로 하는 것이 좋다. nobody로 할 경우에는 일부 기능을 사용하지 못하는 경우가 발생했다.^^(정확한 이유는 모르겠다.^^)

hosts allow는 어느 아이피에서 rsync 서버에 붙어 소스를 가져가도록 허락할 것인지 설정해 주는 것이다.





rsync의 설정을 모두 마쳤다면 xinetd 데몬을 재 시작한다.



/etc/rc.d/init.d/xinetd restart





설정을 마치고 xinetd도 재시작했다면 873 포트가 열려 있는지 테스트 해보자.



#telnet localhost 873

Trying 127.0.0.1...

Connected to localhost.

Escape character is '^]'.

@RSYNCD: 26

Localhost rsync server

sysadmin = root@localhost.com



위와 같이 나온다면 정상적으로 설정이 된 것이다. 물론 2번째로 소스를 받아갈 B서버에서도 테스트를 해 봐야 한다.





#telnet 192.168.1.1 873

Trying 192.168.1.1...

Connected to 192.168.1.1.

Escape character is '^]'.

@RSYNCD: 26

Localhost rsync server

sysadmin = root@localhost.com





이렇게 되었다면 이제 rsync는 완전히 성공한 거나 다름 없다.

다음과 같이 테스트 해보자...^^



rsync -avzrt --delete 192.168.1.1::www /usr/local/localSource/





-a는 아카이브 모드. 심볼릭 링크, 속성, 퍼미션, 소유권 등 보존

-v 전송 상태를 보여줌

-z 전송시 압축을 함.

-r recursive (하위 디렉토리까지 포함)

-t 변경시간 전송 (이것이 없으면 전송한 시간으로 바뀜)



--delete A서버에는 없는데 B서버에 있다면 지우라는 명령



::는 873포트를 이용한 rsync에서 사용하며 ssh나 rsh를 사용할 경우에는 : 라고 써야 한다. 우리는 873 포트를 이용하므로 :: 라고 써야 한다.

www는 rsync 서버의 /etc/rsyncd.conf 파일에서 준 닉 이다. 바로 그 곳에서 설정한 path의 소스들을 /usr/local/localSource/ 디렉토리 밑으로 가져온다는 의미이다.



이해를 다 하셨다면 'Enter'를 힘차게 눌러보자.. 화면이 주르륵 하면서 소스를 가져오는 것이 보일 것이다.(안보이면 대략 낭패..-.-;)

처음에는 모든 파일을 다 가져오기에 조금 시간이 걸릴 것이다. 하지만 그 다음부터는 변경된 파일만 가져올 것이므로 그다지 부하는 걸리지 않을 것이다.^^ (예상하건데...)



이 명령어를 수동으로 매번 타이핑할 수 없으므로 /etc/cron.hourly/ 밑에 shell script 파일 하나를 만들자.



#vi rsync.sh



rsync -avzrt --delete 192.168.1.1::www /usr/local/localSource/



그리고 나서 chmod 700 rsync.sh 하면...^^ rsync 완료...





4. nfs의 설정



사이트에 소스만 있다면 이것으로 끝날 수 있다. 하지만 어찌 소스만 있으랴... nobody 권한으로 생성되는 각종 파일들(로그기록, 그림파일, 업로드 되는 파일들... 기타 등등)을 어떻게 두 서버에서 공유할 수 있단 말인가?

사용자가 운좋게 Round-Robin에서 잘 걸려서 A서버로 붙은 후 파일을 업로드 했다면 rsync로 샥~~ 파일을 가져오면 되는데... B서버에 붙어서 파일을 올렸다면 어찌 해 볼 도리가 없다. 그렇다고 B서버에 rsync 서버를 설치하고 거꾸로 다시 가져오는 것도 바보같은 짓이다.^^(설마 이렇게 하는 분들은 안계시겠죠?)



그래서 나온 것이 nfs이다. Network File System의 약자로 원격지에 있는 하드디스크를 마치 자신의 하드디스크인양 mount 해서 쓸 수 있는 것이다.

따라서 A서버에 있는 디렉토리를 B서버에서 마운트 한다면 어느 서버에서 파일을 올리던 한곳에 파일이 기록되게 되는 것이다. 물론 파일서버를 하나 더 두고 A, B 서버 모두 마운트 해서 사용해도 될 것이다(이렇게는 해 보지 않았다^^)



한가지 주의할 사항은 파일이 쌓이는 곳이 DocumentRoot 밖에 있어야 한다는 것이다. 그래야지만 rsync와 상관없이 실시간으로 파일을 공유할 수 있기 때문이다.



필자는 /localData 란 디렉토리를 하나 만들고 이곳에 nobody 권한으로 생기는 모든 파일을 잘 정리해서 사용하고 있었다.

그럼 nfs의 설정을 하나하나 살펴보도록 하자.





우선은 rsync와 마찬가지로 어느 디렉토리를 어떤 아이피와 공유할 것인지를 설정해야 한다. 따라서 A서버에서 다음과 같이 설정해 줘야 한다.



#vi /etc/exports



/localData 192.168.1.2(rw,no_root_squash)





여기서 /localData란 마운트 당할(?) 디렉토리명... 192.168.1.2는 접근 허용할 아이피, rw는 일고 쓰기 가능토록 권한을 주는 것..., no_root_squash는 B서버의 root도 해당 디렉토리에서 A서버의 루트 권한을 주는 것(맞나?)이다. 참고로 아이피는 도메인으로 설정해 줘도 되는데... 우리는 A서버와 B서버의 도메인이 같으므로 아이피로 하도록 한다.

이렇게 설정을 한 다음... nfs 데몬을 재시작 한다.



#/etc/rc.d/init.d/nfs restart



이렇게 하면 5개인가의 데몬이 주르륵 재시작된다.(stop, start 합치면 10개의 ok 사인이 떨어진다.^^)



이상태에서 바로 B 서버에서 mount를 하면 대략 난감이다. ^^(이거때문에 몇일을 헤메었는지 모른다.^^;;)

이렇게 다 했다면 가장 중요한 데몬 하나를 죽여줘야 한다.^^



#/etc/rc.d/init.d/nfslock stop



이놈이 뭐하는 놈인지 모르겠는데, 이 데몬이 살아 있다면 죽어도 B서버에서 A서버의 /localData를 mount 하지 못할 것이다.(하는 분이 나타난다면... 안되는데..^^;;)

어째든 여기까지 했다면 거의 다 성공한 것이다.



하지만 B서버에서도 설정해 줘야 할 것이 몇개 있다.^^



다음과 같이 dns에 질의하지 않고 바로 연결할 수 있도록 hosts파일을 편집해 줘야 한다.(성능상 좋다고 한다^^, hosts파일의 역할을 모르시는 분은 검색..^^)



#vi /etc/hosts



192.168.1.1 localhost.com localhost.com





그다음 마운트!!!



#mount -t nfs localhost.com:/localData /localData/



한번 마운트가 잘 되었는지 확인해 보자...^^



#cd /localData

#ls -al

drwxr-xr-x 8 nobody nobody 4096 2월 23 17:57 .

drwxr-xr-x 20 nobody nobody 4096 2월 24 13:10 ..

drwxr-xr-x 2 nobody nobody 4096 2월 25 10:44 adminCharge

drwxr-xr-x 2 nobody nobody 4096 2월 26 16:48 cafeConn

drwxr-xr-x 38 nobody nobody 4096 2월 11 13:23 history

drwxr-xr-x 38 nobody nobody 4096 7월 22 2003 ipLog

drwxr-xr-x 2 nobody nobody 8192 2월 27 2004 joinWord

drwxr-xr-x 2 nobody nobody 4096 1월 2 00:06 userAgent



이 다음 B서버에서 접속한 경우 nobody 권한으로 기록되는 파일들이 /localData에 제대로 기록되는지 테스트만 해 보면 된다.





마침...



현재 이런 셋팅에서 테스트 해본 결과 잘 되고 있습니. 다만 로드밸런싱을 하는 프로그램이 따로 없고 네임서버를 이용한 Round-Robin을 이용하다 보니 A, B 서버의 사양에 상관없이 균등하게 배분이 되며 한번 A서버에 붙은 사람은 B 서버로 잘 옮겨오지 못하는 경우가 발생합니다.

그렇게 큰 문제는 아니라고 생각되지만, 불편하신 분들은 더 좋은 로드밸런싱 프로그램을 사용하길 바랍니다. 아마도 돈을 조금 지불해야 되지 않을까 십네요^^

그리고 더 좋은 무료 로드밸런싱 제품이 있다면 저한테도 좀 알려주시기 바랍니다.^^





참고로 이 글은 제가 직접 쓴 글이므로(물론 많은 분들의 도움이 있었지만..^^) 옮겨가실 때에는 출처를 밝혀 주시고... 이대로 따라 하시다가 서버가 맛이 간다거나 해도 저의 책임이 없음을 미리 밝히는 바입니다.^^;



그럼 즐프하시고...

좋은 시간 되세요.



참 덧글도 좋은거 있어서 붙입니다.



덧글..



DNS를 사용해서 로드를 구성하신다면 보다 효율적인 분산을 위해서 TTL값이 작게 잡는것이 좋지 않을까요

www 60 IN A 192.168.1.1

www 60 IN A 192.168.1.2

- PHP 스쿨에서 공간사랑님이.. ^^



요즘 서버들 랜카드가 두개잖아요.

랜 포트 하나는 IP 공유기나 허브에 연결하시구.

NFS 는 사설아이피로만 허가하세요.

나머지 포트는 웹으로 사용하시구요.

그리고 DNS 를 . 1,2 번 웹서버에 각각 2번 찍으면 됩니다.

전 이방법으로 서버 4대 돌리고 있는데 트레픽도 내부적으로 하니까 좋습니다. 전 작년 10월부터 지금까지 이상없이 잘 사용하고 있습니다.

- PHP 스쿨에서 영완님이 ^^



NFS 가 편리하긴 하지만, 락이 걸릴 경우 시스템이 그대로 뻗어 버리는 경우가 종종 있습니다. 그래서 실시간으로 공유해야 할 부분에만 NFS를 사용하고, 그외에는 rsync 등을 사용해서 replication 을 해 주는 게 좋습니다. 그리고 서버가 여러대일 경우 NFS로 묶으면 IO쪽 부하가 심해지므로 고려해야 합니다. 만약 NFS를 구지 사용해야 한다면, TCP 기반의 NFS를 사용하는 게 여러가지 특성상 유리합니다.

- PHP 스쿨에서 Samuel Oh님이 ^^



일전에 로드밸런싱을 위하여 제가 작업했던 방식은 일단 l4에서 rr(라운드 로빈)로 각 웹서버의 접속세션을 분산시켜주고 해당 웹서버에서는 nfs서버의 웹파일들을 사용합니다. nfs서버와 웹서버와의 통신은 내부망을 통해서 연결되어 있고요.

이렇게 사용되면 디스크 쓰기 i/o나 읽기 i/o등이 nfs 서버로 분산 되어 웹서버 자체의 시스템적 부하는 줄어들고 서버 파일 관리가 용의해지겠지요. (만약 파일을 한곳에 모아 놓지 않는다면 완벽한 미러링 시스템이 필요하겠지요.)

nfs서버 자체가 그다지 미덥지 못하다면 데이터센터에서

스토리지 서비스를 받는 방법도 좋습니다. 스토리지 서비스를

받는다면 보안이나 운용에 큰 도움이 되겠지요.

- PHP 스쿨에서 santana님이 ^^

----------------------------------------------------------------------------> 다 좋지만 요 밑부분 괜찮습니다. ^^

실제로 운영한 것을 경험으로 정리해본다면..

L4로 웹서버 로드 밸런싱..

DB서버는 Replication 을 통한 로드 밸런싱..

웹소스는 NFS(개별서버) 를 통한 데이터 공유,

웹소스 백업은 rsync OR NFS서버에서의 백업후 백업서버로 이동

DB 백업은 개별 Slave DB(Repliction)에서의 백업후 백업서버로 이동

이와 같이 썼었습니다. 단점으론 서버가 좀 많이 듭니다.

실시간으로 웹소스 및 DB소스를 운용 가능하구요..

사용자가 늘어나면 늘어날수록 해당하는 웹서버와 DB서버를 증설하고.. 캐쉬기능을 보강하구.. 하면 꽤 좋은 성능을 내주더군요..

- PHP 스쿨에서 꾹꾹이 님이 ^^

<---------------------------------------------------------------------------- 요기까지? ^^.. ㅋㅋ



물론 저도 안해봤으니 책임 못집니다. ㅋㅋ

PHPSCHOOL 보다가 좋은글 있길래 뽑아왔습니다. 출처를 밝히시라네요 ^^

근데 자세히 안나와서 나온데로 밝히겠습니다. ^^



출처 : PHPSCHOOL에서 체리필터 님이.. ^^

댓글 없음: