출쳐 : http://www.ibm.com/developerworks/kr/library/l-linux-ha/index.html
5단계로 간편하게 완료되는 웹 서버 클러스터 설치
Linux Virtual Server와 Linux-HA.org의 Heartbeat를 사용한 웹 서버 클러스터 구축
난이도 : 중급
Eli Dow, Software Engineer, IBM
Frank LeFevre, Senior Software Engineer, IBM
원문 게재일 : 2007 년 8 월 22 일
번역 게재일 : 2009 년 4 월 21 일
Linux Virtual Server와 Heartbeat v2를 사용하여 간단한 5단계 과정만으로 여러 물리적 또는 가상 Linux® 서버를 기반으로 하는 고가용성 Apache 웹 서버 클러스터를 구축합니다.
다양한 소프트웨어 복구 기술과 함께 워크로드를 여러 프로세스로 분배하는 기술을 활용하여 고가용성 환경을 구축하고 전반적인 RAS(Reliability, Availability, and Serviceability)를 향상시킬 수 있다. 예기치 않은 중단을 빠르게 복구할 수 있을 뿐만 아니라 일반 사용자의 예정된 중단으로 인한 손실도 최소화할 수 있다.
이 기사를 이해하려면 Linux와 기본적인 네트워크 작업에 익숙해야 하며 Apache 서버가 이미 구성되어 있어야 한다. 이 기사의 예제는 표준 SLES10(SUSE Linux Enterprise Server 10) 설치를 기반으로 하므로 다른 배포판에 익숙한 사용자라면 이 기사에서 제공하는 방법을 해당 배포판에 맞게 변경할 수 있어야 한다.
이 기사에서는 6개의 Apache 서버 노드(예제에서 설명하는 단계를 수행하는 데는 3개의 노드로 충분함)와 3개의 LVS(Linux Virtual Server) 디렉터로 구성된 강력한 Apache 웹 서버 스택을 설명한다. 그리고 테스트하는 동안 워크로드 처리 속도를 높이고 큰 규모의 배치 환경을 시뮬레이션하기 위해 6개의 Apache 서버 노드를 사용했다. 사용자의 리소스가 충분하다면 여기에서 제시하는 아키텍처를 확장하여 디렉터 및 백엔드 Apache 서버를 추가하는 것이 좋다. (그러나 이 기사에서는 확장하지 않았다.) 그림 1에서는 Linux Virtual Server와 linux-ha.org 구성 요소를 사용하여 구현한 아키텍처를 보여 준다.
그림 1. Linux Virtual Server와 Apache
그림 1에서 외부 클라이언트는 LVS 디렉터 시스템 중 한 시스템에 존재하는 단일 IP 주소로 트래픽을 보낸다. 디렉터 시스템은 웹 서버 풀을 모니터링하여 작업을 릴레이할 대상 웹 서버를 찾는다.
그림 1에서 워크로드는 왼쪽에서 오른쪽으로 진행된다. 이 클러스터에 대한 유동 리소스 주소는 임의의 시점에 LVS 디렉터 인스턴스 중 하나에 존재하게 된다. 그래픽 구성 유틸리티를 통해 서비스 주소를 수동으로 이동할 수도 있지만 일반적으로 서비스 주소는 LVS 디렉터의 상태에 따라 자체적으로 관리된다. 연결 중단, 소프트웨어 오류 등으로 인해 사용할 수 없는 디렉터가 발생하면 사용 가능한 다른 디렉터에게 자동으로 서비스 주소가 다시 할당된다.
유동 서비스 주소는 물리적 시스템 중 하나에서 오류가 발생할 경우에도 작업을 계속할 수 있도록 두 개 이상의 서로 다른 하드웨어 인스턴스에 연결되어 있어야 한다. 이 기사의 구성에서는 각 LVS 디렉터가 물리적 위치에 상관 없이 실제 Apache 웹 서버로 패킷을 전달하거나 유동 서비스 주소를 제공하는 인접한 활성 디렉터에게 패킷을 전달할 수 있다. 이 기사에서는 각 LVS 디렉터가 Apache 서버를 적극적으로 모니터링하여 작동 중인 백엔드 서버에만 요청을 보내는 방법을 보여 준다.
이 구성을 통해 유동 서비스 주소를 사용하는 서비스(일반적으로 http 및 https 요청)의 사용자에게 지속적으로 서비스를 제공하면서 전체 Linux 인스턴스를 성공적으로 수행했다.
![]() |
|
이 기사에서 소개하는 구성은 linux-ha.org에서 제공하는 Heartbeat 기술 구성 요소로 구성된 완전 오픈 소스 소프트웨어 스택과 mon 및 Apache를 통해 모니터링하는 서버를 사용하여 복제할 수 있다. 언급한 대로 구성을 테스트하기 위해 SUSE Linux Enterprise Server를 사용한다.
LVS 시나리오에 사용되는 모든 시스템은 같은 서브넷에 존재하고 NAT(Network Address Translation) 구성을 사용한다. Linux Virtual Server 웹 사이트(참고자료 참조)에서 다른 여러 가지 네트워크 토폴로지에 대한 설명을 볼 수 있으며 이 기사에서는 간단하게 설명하기 위해 NAT를 사용한다. 보안 강화를 위해 LVS 간에 전달되는 유동 IP 주소만 허용되도록 방화벽을 통과하는 트래픽을 제한해야 한다.
Linux Virtual Server 제품군을 사용하면 여러 가지 방법으로 투명한 고가용성 백엔드 인프라를 구축할 수 있으며 방법마다 나름대로의 장단점을 가지고 있다. LVS-NAT는 디렉터 서버에서 작동하며, 구성에 지정된 포트를 대상으로 하는 수신 패킷을 잡아서 패킷 헤더의 대상 주소를 동적으로 다시 기록한다. 디렉터는 패킷의 데이터 컨텐츠를 처리하지 않고 실제 서버에게 전달한다. 클러스터의 지정된 실제 서버를 가리키도록 패킷의 대상 주소가 다시 기록된다. 그런 다음 패킷은 실제 서버에게 전달되기 위해 네트워크에 다시 배치되고 실제 서버는 이때까지 진행된 상황을 아무 것도 인식하지 못한다. 실제 서버의 입장에서는 단지 외부에서 직접 요청을 받았을 뿐이다. 그런 다음 실제 서버의 응답이 디렉터에게 다시 전송되면 응답 패킷에 클라이언트를 가리키는 유동 IP 주소의 소스 주소가 다시 기록된 후 원래 클라이언트에게 패킷이 전송된다.
LVS-NAT 방법을 사용하려면 실제 서버에 간단한 TCP/IP 기능이 있어야 한다. LVS-DR 및 VS-Tun 등의 다른 LVS 작업 모드에서는 좀 더 복잡한 네트워킹 개념이 사용된다. LVS-NAT를 선택할 경우 얻을 수 있는 주요 장점은 실제 서버의 구성을 거의 변경하지 않아도 된다는 것이다. 실제로 가장 어려운 작업은 라우팅 명령문을 적절하게 설정하는 것이다.
먼저 각각의 인스턴스에서 Apache 웹 서버를 실행하고 있는 Linux 서버 인스턴스 풀을 만든 후 웹 브라우저에서 모든 실제 서버의 IP 주소를 하나씩 입력해 보면서 서버가 설계대로 작동하는지 확인한다. 일반적으로 표준 설치는 해당 IP 주소(즉, 각 실제 서버의 고유 IP 주소)의 포트 80을 수신하도록 구성된다.
그런 다음 페이지를 호스팅하는 시스템의 호스트 이름이 포함된 정적 페이지를 표시하도록 각 서버의 기본 웹 페이지를 구성한다. 이렇게 하면 테스트하는 동안 어느 시스템이 연결되어 있는지 항상 알 수 있다.
다음 명령을 실행하여 이러한 시스템에서 IP 전달이 OFF로 설정되어 있는지 미리 확인한다.
# cat /proc/sys/net/ipv4/ip_forward
OFF로 설정되어 있지 않은 경우에는 다음 명령을 실행하여 IP 전달을 비활성화해야 한다.
# echo "0" >/proc/sys/net/ipv4/ip_forward
외부 시스템에서 포트 검사를 수행하면 각 실제 서버에서 http 포트(80)를 올바르게 수신하고 있는지 쉽게 확인할 수 있다. 네트워크를 통해 서버에 연결되어 있는 일부 시스템의 경우 nmap 유틸리티를 사용하여 서버가 수신 중인지 확인할 수 있다.
Listing 1. nmap을 사용하여 서버가 수신 중인지 확인하기
| <PRE class=displaycode> # nmap -P0 192.168.71.92Starting nmap 3.70 ( http://www.insecure.org/nmap/ ) at 2006-01-13 16:58 ESTInteresting ports on 192.168.71.92:(The 1656 ports scanned but not shown below are in state: closed)PORT STATE SERVICE22/tcp open ssh80/tcp filtered http111/tcp open rpcbind631/tcp open ipp</PRE> |
조직에서 nmap과 같은 포트 검사 도구의 사용을 선호하지 않는 경우에는 조직의 승인을 받은 후에 도구를 사용한다.
그런 다음 웹 브라우저에서 각 실제 서버의 실제 IP 주소를 입력하여 각 서버에서 예상대로 해당 페이지를 제공하는지 확인한다. 이 작업이 완료되면 단계 2로 이동한다.
![]() |
![]()
|
이제 필요한 세 개의 LVS 디렉터 인스턴스를 만들 준비가 완료되었다. 각 LVS 디렉터를 위해 SUSE Linux Enterprise Server 10을 처음 설치하는 경우에는 heartbeat, ipvsadm 및 mon과 관련된 고가용성 패키지를 선택해야 한다. 기존 설치가 있는 경우에는 기본 설치 후에 언제라도 YAST와 같은 패키지 관리 도구를 사용하여 이들 패키지를 추가할 수 있다. 각각의 실제 서버를 /etc/hosts 파일에 추가하는 것이 좋다. 이렇게 하면 수신 요청을 처리할 때 DNS 관련 지연이 발생하지 않는다.
이제 각 디렉터에서 다음과 같이 각각의 실제 서버에 대해 ping을 실행하여 적절한 시간 내에 응답이 수신되는지 다시 한번 확인한다.
Listing 2. 실제 서버에 대해 ping 실행하기
| <PRE class=displaycode> # ping -c 1 $REAL_SERVER_IP_1 # ping -c 1 $REAL_SERVER_IP_2 # ping -c 1 $REAL_SERVER_IP_3 # ping -c 1 $REAL_SERVER_IP_4 # ping -c 1 $REAL_SERVER_IP_5 # ping -c 1 $REAL_SERVER_IP_6 </PRE> |
위 작업을 완료한 후 네이티브 패키지 관리 도구의 ipvsadm, Heartbeat 및 mon을 서버에 설치한다. Heartbeat는 디렉터 간 통신에 사용되고 mon은 각 디렉터에서 각 실제 서버의 상태 정보를 관리하는 데 사용된다.
![]() |
![]()
|
단계 3: 디렉터에 Heartbeat 설치 및 구성하기
이전에 LVS 작업 경험이 있는 경우에는 SLES10에서 Heartbeat 버전 2를 구성하는 작업과 SLES9에서 Heartbeat 버전 1을 구성하는 작업이 약간 다르다는 점에 주의해야 한다. Heartbeat 버전 1에서는 /etc/ha.d/ 디렉토리에 저장된 파일(haresources, ha.cf 및 authkeys)을 사용했지만 버전 2에서는 새로운 XML 기반 CIB(Cluster Information Base)를 사용한다. 권장되는 업그레이드 방법은 haresources 파일을 사용하여 새 cib.xml 파일을 생성하는 것이다. Listing 3에서는 일반적인 ha.cf 파일의 컨텐츠를 보여 준다.
이 예제에서는 버전 2에서 사용하기 위해 SLES9 시스템의 ha.cf 파일을 가져와서 맨 아래 세 개의 행(respawn, pingd 및 crm)을 추가했다. 기존 버전 1 구성이 있다면 이 예제와 동일하게 작업할 수 있다. 이러한 지침에 따라 새로 설치하는 경우에는 Listing 3을 복사한 후 프로덕션 환경에 맞게 수정할 수 있다.
Listing 3. /etc/ha.d/ha.cf 구성 파일 예제
| <PRE class=displaycode> # Log to syslog as facility "daemon" use_logd on logfacility daemon # List our cluster members (the realservers) node litsha22 node litsha23 node litsha21 # Send one heartbeat each second keepalive 3 # Warn when heartbeats are late warntime 5 # Declare nodes dead after 10 seconds deadtime 10 # Keep resources on their "preferred" hosts - needed for active/active #auto_failback on # The cluster nodes communicate on their heartbeat lan (.68.*) interfaces ucast eth1 192.168.68.201 ucast eth1 192.168.68.202 ucast eth1 192.168.68.203 # Failover on network failures # Make the default gateway on the public interface a node to ping # (-m) -> For every connected node, add <integer> to the value set # in the CIB, * Default=1 # (-d) -> How long to wait for no further changes to occur before # updating the CIB with a changed attribute # (-a) -> Name of the node attribute to set, * Default=pingd respawn hacluster /usr/lib/heartbeat/pingd -m 100 -d 5s # Ping our router to monitor ethernet connectivity ping litrout71_vip #Enable version 2 functionality supporting clusters with > 2 nodes crm yes</PRE> |
respawn 지시문은 실행 중에 실행하고 모니터링할 프로그램을 지정하는 데 사용된다. 이 프로그램은 종료 코드 100 이외의 종료 코드로 종료될 경우 자동으로 다시 시작된다. 첫 번째 매개변수는 프로그램을 실행할 사용자 ID이고, 두 번째 매개변수는 실행할 프로그램이다. -m 매개변수는 pingd 속성을 100으로 설정한다. 이 값은 현재 시스템에서 도달할 수 있는 ping 노드의 수를 나타낸다. -d 매개변수는 CIB에서 pingd 속성을 수정하기 전에 5초 동안 대기하도록 지시한다. ping 지시문은 Heartbeat에 대한 PingNode를 선언하고 crm 지시문은 Heartbeat가 1.x 버전의 클러스터 관리자를 실행할지 또는 3개 이상의 노드를 지원하는 2.x 버전의 클러스터 관리자를 실행할지 여부를 지정한다.
이 파일은 모든 디렉터에서 동일해야 한다. hacluster 디먼에서 파일을 읽을 수 있도록 파일 권한을 적절하게 설정해야 한다. 권한이 적절하게 설정되어 있지 않으면 디버깅하기 어려운 경고가 로그 파일에 발생할 수 있다.
1.x 버전의 Heartbeat 클러스터의 경우, haresources 파일은 노드 이름 및 네트워킹 정보(유동 IP, 연관된 인터페이스 및 브로드캐스트)를 지정한다. 이 기사에서는 이 파일을 변경하지 않는다.
litsha21 192.168.71.205/24/eth0/192.168.71.255
이 파일은 cib.xml 파일을 생성할 때만 사용된다.
authkeys 파일은 디렉터 간 통신에 사용되는 공유 비밀 키를 지정한다. 공유 비밀 키는 모든 heartbeat 노드에서 알고 있는 암호로 heartbeat 노드 간에 통신하는 데 사용된다. 비밀 키를 사용하면 heartbeat 서버 노드에 영향을 주려고 시도하는 무단 사용자를 막을 수 있다. 이 파일도 변경하지 않는다.
auth 1
1 sha1 ca0e08148801f55794b23461eb4106db
이후 몇몇 단계에서는 버전 1 haresources 파일을 새로운 버전 2 XML 기반 구성 형식(cib.xml)으로 변환하는 방법을 보여 준다. 처음 시작할 때 Listing 4의 구성 파일을 간단히 복사해서 사용할 수도 있겠지만 사용자의 전개 환경에 맞게 구성을 변경하는 것이 좋다.
파일 형식을 사용자의 전개 환경에서 사용할 XML 기반 CIB(Cluster Information Base)로 변환하려면 다음 명령을 실행한다.
python /usr/lib64/heartbeat/haresources2cib.py /etc/ha.d/haresources > /var/lib/heartbeat/crm/test.xml
Listing 4에서 보여 준 것과 유사한 구성 파일이 /var/lib/heartbeat/crm/test.xml에 생성된다.
| <PRE class=displaycode> <cib admin_epoch="0" have_quorum="true" num_peers="3" cib_feature_revision="1.3" generated="true" ccm_transition="7" dc_uuid="114f3ad1-f18a-4bec-9f01-7ecc4d820f6c" epoch="280" num_updates="5205" cib-last-written="Tue Apr 3 16:03:33 2007"> <configuration> <crm_config> <cluster_property_set id="cib-bootstrap-options"> <attributes> <nvpair id="cib-bootstrap-options-symmetric_cluster" name="symmetric_cluster" value="true"/> <nvpair id="cib-bootstrap-options-no_quorum_policy" name="no_quorum_policy" value="stop"/> <nvpair id="cib-bootstrap-options-default_resource_stickiness" name="default_resource_stickiness" value="0"/> <nvpair id="cib-bootstrap-options-stonith_enabled" name="stonith_enabled" value="false"/> <nvpair id="cib-bootstrap-options-stop_orphan_resources" name="stop_orphan_resources" value="true"/> <nvpair id="cib-bootstrap-options-stop_orphan_actions" name="stop_orphan_actions" value="true"/> <nvpair id="cib-bootstrap-options-remove_after_stop" name="remove_after_stop" value="false"/> <nvpair id="cib-bootstrap-options-transition_idle_timeout" name="transition_idle_timeout" value="5min"/> <nvpair id="cib-bootstrap-options-is_managed_default" name="is_managed_default" value="true"/> <attributes> <cluster_property_set> <crm_config> <nodes> <node uname="litsha21" type="normal" id="01ca9c3e-8876-4db5-ba33-a25cd46b72b3"> <instance_attributes id="standby-01ca9c3e-8876-4db5-ba33-a25cd46b72b3"> <attributes> <nvpair name="standby" id="standby-01ca9c3e-8876-4db5-ba33-a25cd46b72b3" value="off"/> <attributes> <instance_attributes> <node> <node uname="litsha23" type="normal" id="dc9a784f-3325-4268-93af-96d2ab651eac"> <instance_attributes id="standby-dc9a784f-3325-4268-93af-96d2ab651eac"> <attributes> <nvpair name="standby" id="standby-dc9a784f-3325-4268-93af-96d2ab651eac" value="off"/> <attributes> <instance_attributes> <node> <node uname="litsha22" type="normal" id="114f3ad1-f18a-4bec-9f01-7ecc4d820f6c"> <instance_attributes id="standby-114f3ad1-f18a-4bec-9f01-7ecc4d820f6c"> <attributes> <nvpair name="standby" id="standby-114f3ad1-f18a-4bec-9f01-7ecc4d820f6c" value="off"/> <attributes> <instance_attributes> <node> <nodes> <resources> <primitive class="ocf" provider="heartbeat" type="IPaddr" id="IPaddr_1"> <operations> <op id="IPaddr_1_mon" interval="5s" name="monitor" timeout="5s"/> <operations> <instance_attributes id="IPaddr_1_inst_attr"> <attributes> <nvpair id="IPaddr_1_attr_0" name="ip" value="192.168.71.205"/> <nvpair id="IPaddr_1_attr_1" name="netmask" value="24"/> <nvpair id="IPaddr_1_attr_2" name="nic" value="eth0"/> <nvpair id="IPaddr_1_attr_3" name="broadcast" value="192.168.71.255"/> <attributes> <instance_attributes> <primitive> <resources> <constraints> <rsc_location id="rsc_location_IPaddr_1" rsc="IPaddr_1"> <rule id="prefered_location_IPaddr_1" score="200"> <expression attribute="#uname" id="prefered_location_IPaddr_1_expr" operation="eq" value="litsha21"/> <rule> <rsc_location> <rsc_location id="my_resource:connected" rsc="IPaddr_1"> <rule id="my_resource:connected:rule" score_attribute="pingd"> <expression id="my_resource:connected:expr:defined" attribute="pingd" operation="defined"/> <rule> <rsc_location> <constraints> <configuration> <cib></PRE> |
구성 파일이 생성되면 test.xml의 이름을 cib.xml로 변경한 후 소유자를 hacluster로, 그룹을 haclient로 변경한 다음 heartbeat 프로세스를 다시 시작한다.
heartbeat 구성이 완료되면 각 디렉터에서 부팅 시에 시작하도록 heartbeat를 설정한다. 이 작업을 수행하려면 각 디렉터에서 다음 명령(또는 사용자의 배포판에서 동일한 기능을 수행하는 명령)을 실행한다.
# chkconfig heartbeat on
각각의 LVS 디렉터를 다시 시작하여 부팅 시에 heartbeat 서비스가 올바르게 시작되는지 확인한다. 먼저 유동 리소스 IP 주소를 가지고 있는 시스템을 중지하면 다른 LVS 디렉터 이미지가 몇 초 내에 쿼럼을 설정하고 새로 선택된 기본 노드에서 서비스 주소가 인스턴스화되는 것을 볼 수 있다. 중지된 디렉터 이미지를 온라인 상태로 다시 되돌리면 이 시스템으로 유동 리소스 IP 주소가 다시 전송되면서 모든 노드에 대한 쿼럼이 다시 설정된다. 이러한 전체 프로세스는 몇 초만에 수행된다.
또한 이 상황에서 heartbeat 프로세스용 그래픽 유틸리티인 hb_gui(그림 2 참조)를 통해 다양한 노드를 대기 또는 활성 상태로 설정하여 클러스터 내에서 IP 주소를 수동으로 이동할 수 있다. 이러한 단계를 여러 차례 수행하여 활성 또는 비활성 상태에 있는 여러 시스템을 비활성화한 후 활성화하는 작업을 반복한다. 이전에 선택한 구성 정책을 사용하는 경우에는 쿼럼을 설정할 수 있고 적어도 한 개의 노드를 사용할 수 있는 한 유동 리소스 IP 주소는 작동 상태로 유지된다. 테스트를 수행하는 동안 간단한 ping을 사용하여 패킷 유실이 발생하지 않는지 확인할 수 있다. 테스트를 마치고 나면 현재 구성이 얼마나 강력한지 알 수 있을 것이며 이후로는 유동 리소스 IP의 고가용성 구성에 대한 강한 확신을 갖게 될 것이다.
그림 2. heartbeat 프로세스를 위한 그래픽 구성 유틸리티 hb_gui
그림 2는 로그인 후 표시되는 그래픽 콘솔로 관리되는 리소스 및 연관된 구성 옵션을 보여 준다. 애플리케이션을 처음 시작할 때 hb_gui 콘솔에 로그인해야 하며 사용되는 자격 증명은 사용자의 전개 환경에 따라 달라진다.
그림 2를 보면 클러스터에 있는 노드 중 litsha2* 시스템이 실행 중 상태에 있음을 알 수 있다. litsha21 시스템은 현재 활성 노드이며, 이는 바로 아래에 들여쓰여진 리소스(IPaddr_1)가 추가되어 있는 것으로 알 수 있다.
또한 "No Quorum Policy"의 선택 사항 값이 "stop"으로 설정되어 있다. 이는 격리된 노드가 소유하지 않은 리소스를 해제한다는 것을 의미한다. 이러한 결정에는 임의의 시점에 두 개의 heartbeat 노드가 활성 상태에 있어야만 쿼럼을 설정할 수 있다는 의미가 내포되어 있다(즉, 다수결 원리). 100% 작동 중인 단일 활성 노드가 네트워크 장애로 인해 피어 시스템과의 연결이 끊어지거나 비활성 피어 노드가 모두 동시에 중지될 경우, 리소스는 자발적으로 해제된다.
![]() |
![]()
|
다음으로 수행할 단계는 유동 리소스 IP 주소를 가져온 후 이 주소를 기반으로 빌드하는 작업이다. LVS는 원격 웹 브라우저 클라이언트에 투명하게 작동해야 하므로 모든 웹 요청은 디렉터를 거쳐서 실제 서버 중 하나로 전달되어야 한다. 그리고 모든 결과는 디렉터에게 다시 전달되어야 하며, 그런 다음 디렉터가 웹 페이지 요청을 보낸 클라이언트에게 응답을 리턴한다.
이와 같은 방식으로 요청과 응답을 처리하려면 다음 명령을 실행하여 IP 전달을 사용하도록 각 LVS 디렉터를 구성한다. (이렇게 하면 요청을 실제 서버로 전달할 수 있다.)
# echo "1" >/proc/sys/net/ipv4/ip_forward
# cat /proc/sys/net/ipv4/ip_forward
성공적으로 구성이 완료된 경우, 두 번째 명령을 실행하면 터미널에 "1"이 출력된다. 이 구성을 영구적으로 추가하기 위해
'' IP_FORWARD="yes"
위 구문을 /etc/sysconfig/sysctl에 추가한다.
그런 다음 수신 HTTP 요청을 실제 서버의 고가용성 유동 IP 주소로 전달하도록 지시하기 위해 ipvsadm 명령을 사용한다.
먼저 다음 명령을 실행하여 기존 ipvsadm 테이블을 지운다.
# /sbin/ipvsadm -C
새 테이블을 구성하려면 먼저 LVS 디렉터에서 사용할 워크로드 분배 유형을 결정해야 한다. 클라이언트의 연결 요청이 수신되면 디렉터는 "스케줄"에 따라 실제 서버를 해당 클라이언트에게 할당한다. 사용자는 ipvsadm 명령을 사용하여 스케줄 유형을 설정한다. 다음과 같은 스케줄러를 사용할 수 있다.
- RR(Round Robin): 새 수신 연결이 차례대로 각 실제 서버에 할당된다.
- WRR(Weighted Round Robin): 실제 서버에 장착된 CPU 속도, 메모리 용량 등의 성능 차이를 보완하기 위해 가중치가 추가된 RR 스케줄링이다.
- LC(Least Connected): 최소 개수의 연결을 가지고 있는 실제 서버에게 새 연결이 할당된다. 이 경우 반드시 사용량이 가장 적은 실제 서버에게 할당되는 것은 아니지만 대체로 이 기준이 충족된다.
- WLC(Weighted Least Connection): 가중치가 적용된 LC이다.
테스트를 위해서는 확인하기 쉬운 RR 스케줄링을 사용하는 것이 좋다. WRR 및 LC를 테스트 루틴에 추가하여 예상대로 작동하는지 확인할 수도 있다. 이 기사의 예제에서는 RR 스케줄링 및 변형을 사용하는 것으로 간주한다.
이제 실제 서버로 전달하는 ipvsadm 서비스를 활성화하는 스크립트를 작성한 후 스크립트 사본을 각 LVS 디렉터에 저장한다. 이 스크립트는 나중에 mon을 구성하여 활성 실제 서버를 자동으로 모니터링하게 되면 필요하지 않지만 그 전까지는 ipvsadm 구성 요소를 테스트할 때 유용하게 사용할 수 있다. 이 스크립트를 실행하기 전에 네트워크와 각 실제 서버에 대한 http/https 연결이 적절하게 구성되어 있는지 확인해야 한다.
| <PRE class=displaycode> #!/bin/sh # The virtual address on the director which acts as a cluster address VIRTUAL_CLUSTER_ADDRESS=192.168.71.205 REAL_SERVER_IP_1=192.168.71.220 REAL_SERVER_IP_2=192.168.71.150 REAL_SERVER_IP_3=192.168.71.121 REAL_SERVER_IP_4=192.168.71.145 REAL_SERVER_IP_5=192.168.71.185 REAL_SERVER_IP_6=192.168.71.186 # set ip_forward ON for vs-nat director (1 on, 0 off). cat /proc/sys/net/ipv4/ip_forward echo "1" >/proc/sys/net/ipv4/ip_forward # director acts as the gw for realservers # Turn OFF icmp redirects (1 on, 0 off), if not the realservers might be clever and # not use the director as the gateway! echo "0" >/proc/sys/net/ipv4/conf/all/send_redirects echo "0" >/proc/sys/net/ipv4/conf/default/send_redirects echo "0" >/proc/sys/net/ipv4/conf/eth0/send_redirects # Clear ipvsadm tables (better safe than sorry) /sbin/ipvsadm -C # We install LVS services with ipvsadm for HTTP and HTTPS connections with RR # scheduling /sbin/ipvsadm -A -t $VIRTUAL_CLUSTER_ADDRESS:http -s rr /sbin/ipvsadm -A -t $VIRTUAL_CLUSTER_ADDRESS:https -s rr # First realserver # Forward HTTP to REAL_SERVER_IP_1 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_1:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_1:https -m -w 1 # Second realserver # Forward HTTP to REAL_SERVER_IP_2 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_2:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_2:https -m -w 1 # Third realserver # Forward HTTP to REAL_SERVER_IP_3 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_3:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_3:https -m -w 1 # Fourth realserver # Forward HTTP to REAL_SERVER_IP_4 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_4:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_4:https -m -w 1 # Fifth realserver # Forward HTTP to REAL_SERVER_IP_5 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_5:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_5:https -m -w 1 # Sixth realserver # Forward HTTP to REAL_SERVER_IP_6 using LVS-NAT (-m), with weight=1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:http -r $REAL_SERVER_IP_6:http -m -w 1 /sbin/ipvsadm -a -t $VIRTUAL_CLUSTER_ADDRESS:https -r $REAL_SERVER_IP_6:https -m -w 1 # We print the new ipvsadm table for inspection echo "NEW IPVSADM TABLE:" /sbin/ipvsadm</PRE> |
Listing 5에서 볼 수 있는 것처럼 이 스크립트는 단순히 ipvsadm 서비스를 활성화한 후 거의 동일한 구문을 사용하여 각각의 실제 서버에게 웹 및 SSL 요청을 전달한다. 이 예제에서는 -m 옵션을 사용하여 NAT를 지정하고 각각의 실제 서버에 동일하게 가중치 1(-w 1)을 적용한다. 기본 가중치가 항상 1이므로 지정된 가중치는 일반적인 라운드 로빈 스케줄링을 사용할 때 충분한 가중치이다. 가중치 기반 라운드 로빈을 선택할 수 있는 옵션만 제공된다. 그렇게 하려면 라운드 로빈 사용에 대한 주석 아래의 두 행에 있는 rr을 wrr로 변경한 후 가중치를 적절하게 조정한다. 다양한 스케줄러에 대한 자세한 정보는 ipvsadm의 man 페이지에서 볼 수 있다.
수신 웹 및 SSL 요청을 다시 쓴 후 작업을 실제 서버에 전달하는 방식으로 유동 서비스 IP에 대한 수신 웹 및 SSL 요청을 처리하도록 각 디렉터를 구성했다. 그러나 요청을 보낸 클라이언트에게 요청을 되돌려 보내기 전에 실제 서버로부터 트래픽을 다시 받아서 프로세스를 반대로 수행하려면 디렉터의 네트워킹 설정 중 일부를 변경해야 한다. 이 작업은 LVS 디렉터와 실제 서버를 모든 노드가 같은 서브넷에 존재하는 플랫 네트워크 토폴로지로 구현하기로 결정했기 때문에 수행해야 한다. Apache 응답 트래픽이 직접 전달되지 않고 디렉터를 통해 전달되도록 하기 위해 다음 단계를 수행해야 한다.
echo "0" > /proc/sys/net/ipv4/conf/all/send_redirects
echo "0" > /proc/sys/net/ipv4/conf/default/send_redirects
echo "0" > /proc/sys/net/ipv4/conf/eth0/send_redirects
이 작업은 활성 LVS 디렉터에서 같은 서브넷에 존재하는 실제 서버 및 유동 서비스 IP에게 서로 직접 통신하도록 통지하여 TCP/IP 단축 경로를 받는 것을 방지하기 위해 수행했다. 일반적으로 리디렉션을 사용하면 네트워크 연결에서 불필요한 중단 단계가 없어지면서 성능이 향상된다. 그러나 이 경우에는 클라이언트에 대해 투명해야 하므로 응답 트래픽을 다시 쓸 수 없다. 실제로 LVS 디렉터에서 리디렉션을 사용하지 않는 경우, 실제 서버에서 클라이언트로 직접 전달되는 트래픽은 클라이언트에서 불필요한 네트워크 응답으로 인식되어 버려진다.
이제 요청을 보낸 클라이언트에게 되돌려 보내기 전에 모든 응답을 디렉터에게 전달하여 패킷을 다시 쓰기 위해 각 실제 서버의 기본 경로를 서비스 유동 IP 주소를 가리키도록 설정해야 한다.
디렉터에서 리디렉션 기능을 해제하고 모든 트래픽이 유동 서비스 IP를 통과하도록 실제 서버를 구성한 후에는 고가용성 LVS 환경을 테스트할 수 있다. 지금까지 수행한 작업을 테스트하려면 원격 클라이언트의 웹 브라우저에서 LVS 디렉터의 유동 서비스 주소를 입력한다.
실험실 환경에서 테스트하기 위해 이 기사에서는 Gecko 기반 브라우저(Mozilla)를 사용했지만 원하는 임의의 브라우저를 사용해도 무관하다. 성공적으로 전개되었는지 확인하기 위해 브라우저의 캐시 기능을 해제한 후 새로 고침 단추를 여러 번 클릭한다. 새로 고쳐질 때마다 실제 서버에서 구성한 자체 식별 페이지 중 하나가 웹 페이지에 표시되어야 한다. RR 스케줄링을 사용하는 경우에는 각 실제 서버의 페이지가 차례대로 표시되어야 한다.
부팅 시에 LVS 구성을 자동으로 시작하는 방법은 아직 사용하지 않는 것이 좋다. 마지막으로 실제 서버에 대한 모니터링을 수행하여 작업 요청을 처리하는 데 사용할 수 있는 Apache 노드를 보여 주는 동적 목록을 유지하기 위해 필요한 단계 5가 남아 있다.
![]() |
![]()
|
지금까지 고가용성 서비스 IP 주소를 설정한 후 실제 서버 인스턴스 풀에 바인딩했다. 하지만 개별 Apache 서버가 항상 정상적으로 작동할 것이라고 생각한면 안 된다. RR 스케줄링을 선택할 경우 지정된 임의의 실제 서버가 중단되거나 네트워크 트래픽에 대한 응답이 시기 적절하게 이루어지지 않으면 HTTP 요청의 1/6이 실패하게 된다.
따라서 서비스 풀에서 실제 서버를 동적으로 추가 또는 제거할 수 있도록 각 LVS 디렉터에 실제 서버를 모니터링하는 기능을 구현해야 한다. 또 하나의 잘 알려져 있는 오픈 소스 패키지인 mon이 이 작업에 적합하다.
mon 솔루션은 보통 LVS 실제 노드를 모니터링하는 데 사용된다. mon은 비교적 구성하기가 쉽고 쉘 스크립트에 익숙한 개발자의 경우 쉽게 확장하여 사용할 수 있다. mon을 사용하려면 설치, 서비스 모니터링 구성 및 경고 작성 등의 세 가지 주요 필수 단계를 수행해야 한다. 패키지 관리 도구를 사용하여 mon을 설치할 수 있다. 설치가 완료된 후에는 모니터링 구성을 조정하고 일부 경고 스크립트를 작성하기만 하면 된다. 경고 스크립트는 모니터에서 오프라인으로 전환되거나 온라인으로 다시 전환된 실제 서버가 감지될 때 트리거된다.
heartbeat v2를 설치하면 모든 실제 서버 서비스를 리소스로 만들어서 실제 서버를 모니터링할 수 있다. 또는 Heartbeat ldirectord 패키지를 사용할 수 있다.
기본적으로 mon에는 바로 사용할 수 있는 여러 가지 모니터 메커니즘이 있다. 이 기사에서는 HTTP 서비스를 사용하기 위해 /etc/mon.cf에 있는 샘플 구성 파일을 변경했다.
mon 구성 파일의 헤더에 올바른 경로가 입력되어 있는지 확인한다. SLES10은 64비트 Linux 이미지이지만 함께 제공되는 샘플 구성은 기본(31 또는 32비트) 위치를 위한 것이다. 샘플 구성 파일에서는 경고 및 모니터가 /usr/lib에 있는 것으로 간주하지만 이 기사에서 설명하는 환경에는 맞지 않기 때문에 매개변수를 다음과 같이 변경했다.
alertdir = /usr/lib64/mon/alert.d
mondir = /usr/lib64/mon/mon.d
단순히 lib를 lib64로 변경했을 뿐이다. 사용자의 배포 환경에 따라 이러한 변경이 필요하지 않을 수도 있다.
구성 파일에서 다음으로 변경한 작업은 모니터링할 실제 서버의 목록을 지정하는 것이다. 이 작업은 다음과 같은 6개의 지시문을 사용하여 수행했다.
| <PRE class=displaycode> hostgroup litstat1 192.168.71.220 # realserver 1 hostgroup litstat2 192.168.71.150 hostgroup litstat3 192.168.71.121 hostgroup litstat4 192.168.71.145 hostgroup litstat5 192.168.71.185 hostgroup litstat6 192.168.71.186 # realserver 6 </PRE> |
실제 서버를 추가하려면 여기에 항목을 추가하면 된다.
모든 정의를 완료한 후에는 실패 감시 방법과 실패 시 수행할 작업을 mon에게 알려줘야 한다. 이를 수행하기 위해 다음과 같은 모니터 섹션(실제 서버 당 한 섹션)을 추가한다. 섹션을 추가한 후에는 각각의 heartbeat 클러스터 노드에서 모든 실제 서버를 개별적으로 모니터링할 수 있도록 mon 구성 파일과 경고를 각각의 LVS heartbeat 노드에 배치해야 한다.
| <PRE class=displaycode> # # global options # cfbasedir = /etc/mon alertdir = /usr/lib64/mon/alert.d mondir = /usr/lib64/mon/mon.d statedir = /var/lib/mon logdir = /var/log maxprocs = 20 histlength = 100 historicfile = mon_history.log randstart = 60s # # authentication types: # getpwnam standard Unix passwd, NOT for shadow passwords # shadow Unix shadow passwords (not implemented) # userfile "mon" user file # authtype = getpwnam # # downtime logging, uncomment to enable # if the server is running, don't forget to send a reset command # when you change this # #dtlogfile = downtime.log dtlogging = yes # # NB: hostgroup and watch entries are terminated with a blank line (or # end of file). Don't forget the blank lines between them or you lose. # # # group definitions (hostnames or IP addresses) # example: # # hostgroup servers www mail pop server4 server5 # # For simplicity we monitor each individual server as if it were a "group" # so we add only the hostname and the ip address of an individual node for each. hostgroup litstat1 192.168.71.220 hostgroup litstat2 192.168.71.150 hostgroup litstat3 192.168.71.121 hostgroup litstat4 192.168.71.145 hostgroup litstat5 192.168.71.185 hostgroup litstat6 192.168.71.186 # # Now we set identical watch definitions on each of our groups. They could be # customized to treat individual servers differently, but we have made the # configurations homogeneous here to match our homogeneous LVS configuration. # watch litstat1 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1 watch litstat2 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1 watch litstat3 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1 watch litstat4 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1 watch litstat5 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1 watch litstat6 service http description http check servers interval 6s monitor http.monitor -p 80 -u /index.html allow_empty_group period wd {Mon-Sun} alert dowem.down.alert -h upalert dowem.up.alert -h alertevery 600s alertafter 1</PRE> |
Listing 7은 기본적으로 mon과 함께 제공되는 http.monitor의 사용 방법을 mon에게 알려 준다. 또한 포트 80이 사용할 포트로 지정되어 있다. Listing 7은 요청할 특정 페이지도 제공한다. 효율성을 높이기 위해 웹 서버의 복잡한 기본 html 페이지 대신 html의 일부만을 성공의 증거로 전송하도록 선택할 수도 있다.
alert 및 upalert 행에서는 구성 파일의 상단에서 지정한 alertdir에 있는 스크립트를 호출한다. 이 디렉토리는 일반적으로 배포판 기본값(예: "/usr/lib64/mon/alert.d")이다. 경고는 LVS에게 가용 항목 목록에서 Apache 서버를 추가 또는 제거하도록 알려 준다. (이 경우 경고는 잠시 후에 살펴볼 ipvsadm 명령을 호출한다.)
실제 서버 중 하나가 http 테스트에 실패하면 mon이 여러 인수를 사용하여 자동으로 dowem.down.alert를 실행한다. 마찬가지로, 실제 서버가 온라인 상태로 돌아오면 mon 프로세스가 여러 인수를 사용하여 dowem.up.alert를 자동으로 실행한다. 경고 스크립트의 이름을 사용자의 전개 환경에 맞게 자유롭게 변경할 수 있다.
이 파일을 저장하고 경고를 alertdir에 만든다(간단한 bash 스크립트 사용). Listing 8에서는 실제 서버 연결이 다시 설정될 때 mon이 호출하는 bash 스크립트 경고를 보여 준다.
| <PRE class=displaycode> #! /bin/bash # The h arg is followed by the hostname we are interested in acting on # So we skip ahead to get the -h option since we don't care about the others REALSERVER=192.168.71.205 while [ $1 != "-h" ] ; do shift done ADDHOST=$2 # For the HTTP service /sbin/ipvsadm -a -t $REALSERVER:http -r $ADDHOST:http -m -w 1 # For the HTTPS service /sbin/ipvsadm -a -t $REALSERVER:https -r $ADDHOST:https -m -w 1</PRE> |
Listing 9에서는 실제 서버 연결이 끊어졌을 때 mon이 호출하는 bash 스크립트 경고를 보여 준다.
| <PRE class=displaycode> #! /bin/bash # The h arg is followed by the hostname we are interested in acting on # So we skip ahead to get the -h option since we dont care about the others REALSERVER=192.168.71.205 while [ $1 != "-h" ] ; do shift done BADHOST=$2 # For the HTTP service /sbin/ipvsadm -d -t $REALSERVER:http -r $BADHOST # For the HTTPS service /sbin/ipvsadm -d -t $REALSERVER:https -r $BADHOST</PRE> |
이러한 두 스크립트 모두 ipvsadm 명령행 도구를 사용하여 LVS 테이블에서 실제 서버를 동적으로 추가 및 제거한다. 이러한 스크립트는 완벽한 스크립트가 아니다. 간단한 웹 요청에 대한 http 포트만을 모니터링하는 mon을 사용하기 때문에 여기에서 설명하는 아키텍처는 지정된 실제 서버가 http 요청에만 올바르게 작동하고 SSL 요청에 대해서는 올바르게 작동하지 않는 상황에서 취약점을 가지고 있다. 이러한 환경에서는 https 후보 목록에서 적절하지 않은 실제 서버를 제거할 수 없다. 물론 이 문제점은 각 유형의 웹 요청에 대한 고급 경고를 구체적으로 설정하고 mon 구성 파일에서 각 실제 서버에 대한 두 번째 https 모니터를 활성화하여 해결할 수 있다. 이에 대한 구체적인 방법은 독자들의 연습 과제로 남겨둔다.
모니터링이 활성화되어 있는지 확인하기 위해 각 실제 서버의 Apache 프로세스를 차례대로 활성화 및 비활성화하여 이벤트에 대한 각 디렉터의 반응을 살펴본다. 각 디렉터가 각각의 실제 서버를 올바르게 모니터링하고 있는지 확인한 후 chkconfig 명령을 사용하여 mon 프로세스가 부팅 시에 자동으로 시작되는지 확인한다. 여기에서 사용된 구체적인 명령은 chkconfig mon on이지만 사용자의 배포판에 따라 달라질 수 있다.
이 작업을 끝으로 교차 시스템 고가용성 웹 서버 인프라를 구축하는 단계가 모두 완료되었다. 물론, 원한다면 고급 단계의 작업을 추가로 수행할 수도 있다. 예를 들어, 이 예제에서는 mon 디먼이 자체적으로 모니터링되지 않지만(heartbeat 프로젝트가 mon을 모니터링할 수 있음) 이 마지막 단계를 통해 기본적인 토대가 마련되었다.
![]() |
![]()
|
고가용성 클러스터에서 활성 노드가 자발적 또는 비자발적으로 정상적인 작동을 멈추는 데는 노드 간 네트워크 연결이 끊어지거나, heartbeat 프로세스가 중지되거나, 작동 환경과 관련된 여러 문제 중 하나가 발생하는 등의 여러 가지 이유가 있다. 활성 노드를 정상적으로 중지시키기 위해 해당 노드에 대한 중지 명령을 실행하거나 hb_gui(clean take down) 명령을 사용하여 해당 노드를 대기 모드로 설정할 수 있다. 환경의 안정성을 확인하기 위해 플러그를 뽑는 등의 좀 더 공격적인 방법을 사용할 수도 있다.
Linux 고가용성 heartbeat 시스템의 시스템 관리자는 두 가지 유형의 로그 파일 표시기를 사용할 수 있다. 로그 파일은 시스템이 유동 리소스 IP 주소의 수신자인지 여부에 따라 달라진다. 유동 리소스 IP 주소를 수신하지 않은 클러스터 멤버의 로그 결과는 다음과 같다.
| <PRE class=displaycode> litsha21:~ # cat /var/log/messages Jan 16 12:00:20 litsha21 heartbeat: [3057]: WARN: node litsha23: is dead Jan 16 12:00:21 litsha21 cib: [3065]: info: mem_handle_event: Got an event OC_EV_MS_NOT_PRIMARY from ccm Jan 16 12:00:21 litsha21 cib: [3065]: info: mem_handle_event: instance=13, nodes=3, new=1, lost=0, n_idx=0, new_idx=3, old_idx=6 Jan 16 12:00:21 litsha21 crmd: [3069]: info: mem_handle_event: Got an event OC_EV_MS_NOT_PRIMARY from ccm Jan 16 12:00:21 litsha21 crmd: [3069]: info: mem_handle_event: instance=13, nodes=3, new=1, lost=0, n_idx=0, new_idx=3, old_idx=6 Jan 16 12:00:21 litsha21 crmd: [3069]: info: crmd_ccm_msg_callback:callbacks.c Quorum lost after event=NOT PRIMARY (id=13) Jan 16 12:00:21 litsha21 heartbeat: [3057]: info: Link litsha23:eth1 dead. Jan 16 12:00:38 litsha21 ccm: [3064]: debug: quorum plugin: majority Jan 16 12:00:38 litsha21 ccm: [3064]: debug: cluster:linux-ha, member_count=2, member_quorum_votes=200 Jan 16 12:00:38 litsha21 ccm: [3064]: debug: total_node_count=3, total_quorum_votes=300 .................. Truncated For Brevity .................. Jan 16 12:00:40 litsha21 crmd: [3069]: info: update_dc:utils.c Set DC to litsha21 (1.0.6) Jan 16 12:00:41 litsha21 crmd: [3069]: info: do_state_transition:fsa.c litsha21: State transition S_INTEGRATION -> S_FINALIZE_JOIN [ input=I_INTEGRATED cause=C_FSA_INTERNAL origin=check_join_state ] Jan 16 12:00:41 litsha21 crmd: [3069]: info: do_state_transition:fsa.c All 2 cluster nodes responded to the join offer. Jan 16 12:00:41 litsha21 crmd: [3069]: info: update_attrd:join_dc.c Connecting to attrd... Jan 16 12:00:41 litsha21 cib: [3065]: info: sync_our_cib:messages.c Syncing CIB to all peers Jan 16 12:00:41 litsha21 attrd: [3068]: info: attrd_local_callback:attrd.c Sending full refresh .................. Truncated For Brevity .................. Jan 16 12:00:43 litsha21 pengine: [3112]: info: unpack_nodes:unpack.c Node litsha21 is in standby-mode Jan 16 12:00:43 litsha21 pengine: [3112]: info: determine_online_status:unpack.c Node litsha21 is online Jan 16 12:00:43 litsha21 pengine: [3112]: info: determine_online_status:unpack.c Node litsha22 is online Jan 16 12:00:43 litsha21 pengine: [3112]: info: IPaddr_1 (heartbeat::ocf:IPaddr): Stopped Jan 16 12:00:43 litsha21 pengine: [3112]: notice: StartRsc:native.c litsha22 Start IPaddr_1 Jan 16 12:00:43 litsha21 pengine: [3112]: notice: Recurring:native.c litsha22 IPaddr_1_monitor_5000 Jan 16 12:00:43 litsha21 pengine: [3112]: notice: stage8:stages.c Created transition graph 0. .................. Truncated For Brevity .................. Jan 16 12:00:46 litsha21 mgmtd: [3070]: debug: update cib finished Jan 16 12:00:46 litsha21 crmd: [3069]: info: do_state_transition:fsa.c litsha21: State transition S_TRANSITION_ENGINE -> S_IDLE [ input=I_TE_SUCCESS cause=C_IPC_MESSAGE origin=do_msg_route ] Jan 16 12:00:46 litsha21 cib: [3118]: info: write_cib_contents:io.c Wrote version 0.53.593 of the CIB to disk (digest: 83b00c386e8b67c42d033a4141aaef90)</PRE> |
Listing 10을 보면, 한 바퀴 순회가 이루어지고 투표에 참여할 수 있는 쿼럼 멤버가 충분하다. 투표가 이루어진 후 추가 조치 없이 정상 작동이 재개된다.
이와는 반대로 유동 리소스 IP 주소를 수신한 클러스터 멤버의 로그 결과는 다음과 같다.
| <PRE class=displaycode> litsha22:~ # cat /var/log/messages Jan 16 12:00:06 litsha22 syslog-ng[1276]: STATS: dropped 0 Jan 16 12:01:51 litsha22 heartbeat: [3892]: WARN: node litsha23: is dead Jan 16 12:01:51 litsha22 heartbeat: [3892]: info: Link litsha23:eth1 dead. Jan 16 12:01:51 litsha22 cib: [3900]: info: mem_handle_event: Got an event OC_EV_MS_NOT_PRIMARY from ccm Jan 16 12:01:51 litsha22 cib: [3900]: info: mem_handle_event: instance=13, nodes=3, new=3, lost=0, n_idx=0, new_idx=0, old_idx=6 Jan 16 12:01:51 litsha22 crmd: [3904]: info: mem_handle_event: Got an event OC_EV_MS_NOT_PRIMARY from ccm Jan 16 12:01:51 litsha22 crmd: [3904]: info: mem_handle_event: instance=13, nodes=3, new=3, lost=0, n_idx=0, new_idx=0, old_idx=6 Jan 16 12:01:51 litsha22 crmd: [3904]: info: crmd_ccm_msg_callback:callbacks.c Quorum lost after event=NOT PRIMARY (id=13) Jan 16 12:02:09 litsha22 ccm: [3899]: debug: quorum plugin: majority Jan 16 12:02:09 litsha22 crmd: [3904]: info: do_election_count_vote:election.c Election check: vote from litsha21 Jan 16 12:02:09 litsha22 ccm: [3899]: debug: cluster:linux-ha, member_count=2, member_quorum_votes=200 Jan 16 12:02:09 litsha22 ccm: [3899]: debug: total_node_count=3, total_quorum_votes=300 Jan 16 12:02:09 litsha22 cib: [3900]: info: mem_handle_event: Got an event OC_EV_MS_INVALID from ccm Jan 16 12:02:09 litsha22 cib: [3900]: info: mem_handle_event: no mbr_track info Jan 16 12:02:09 litsha22 cib: [3900]: info: mem_handle_event: Got an event OC_EV_MS_NEW_MEMBERSHIP from ccm Jan 16 12:02:09 litsha22 cib: [3900]: info: mem_handle_event: instance=14, nodes=2, new=0, lost=1, n_idx=0, new_idx=2, old_idx=5 Jan 16 12:02:09 litsha22 cib: [3900]: info: cib_ccm_msg_callback:callbacks.c LOST: litsha23 Jan 16 12:02:09 litsha22 cib: [3900]: info: cib_ccm_msg_callback:callbacks.c PEER: litsha21 Jan 16 12:02:09 litsha22 cib: [3900]: info: cib_ccm_msg_callback:callbacks.c PEER: litsha22 .................. Truncated For Brevity .................. Jan 16 12:02:12 litsha22 crmd: [3904]: info: update_dc:utils.c Set DC to litsha21 (1.0.6) Jan 16 12:02:12 litsha22 crmd: [3904]: info: do_state_transition:fsa.c litsha22: State transition S_PENDING -> S_NOT_DC [ input=I_NOT_DC cause=C_HA_MESSAGE origin=do_cl_join_finalize_respond ] Jan 16 12:02:12 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Update (client: 3069, call:25): 0.52.585 -> 0.52.586 (ok) .................. Truncated For Brevity .................. Jan 16 12:02:14 litsha22 IPaddr[3998]: INFO: /sbin/ifconfig eth0:0 192.168.71.205 netmask 255.255.255.0 broadcast 192.168.71.255 Jan 16 12:02:14 litsha22 IPaddr[3998]: INFO: Sending Gratuitous Arp for 192.168.71.205 on eth0:0 [eth0] Jan 16 12:02:14 litsha22 IPaddr[3998]: INFO: /usr/lib64/heartbeat/send_arp -i 500 -r 10 -p /var/run/heartbeat/rsctmp/send_arp/send_arp-192.168.71.205 eth0 192.168.71.205 auto 192.168.71.205 ffffffffffff Jan 16 12:02:14 litsha22 crmd: [3904]: info: process_lrm_event:lrm.c LRM operation (3) start_0 on IPaddr_1 complete Jan 16 12:02:14 litsha22 kernel: send_arp uses obsolete (PF_INET,SOCK_PACKET) Jan 16 12:02:14 litsha22 kernel: klogd 1.4.1, ---------- state change ---------- Jan 16 12:02:14 litsha22 kernel: NET: Registered protocol family 17 Jan 16 12:02:15 litsha22 crmd: [3904]: info: do_lrm_rsc_op:lrm.c Performing op monitor on IPaddr_1 (interval=5000ms, key=0:f9d962f0-4ed6-462d-a28d-e27b6532884c) Jan 16 12:02:15 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Update (client: 3904, call:18): 0.53.591 -> 0.53.592 (ok) Jan 16 12:02:15 litsha22 mgmtd: [3905]: debug: update cib finished </PRE> |
Listing 11에서 보여 주는 /var/log/messages 파일을 보면 이 노드가 유동 리소스를 받았음을 알 수 있다. ifconfig 행을 보면 eth0:0 장치가 서비스를 유지 관리하기 위해 동적으로 생성되고 있음을 알 수 있다.
Listing 11을 보면, 한 바퀴 순회가 이루어지고 투표에 참여할 수 있는 쿼럼 멤버가 충분하다. 투표가 이루어진 후 유동 리소스 IP 주소를 요청하기 위해 ifconfig 명령이 실행된다.
실패가 발생했음을 나타내는 또 다른 방법은 클러스터 멤버에 로그인한 후 hb_gui 명령을 실행하는 것이다. 이렇게 하면 유동 리소스를 가지고 있는 시스템을 시각적으로 확인할 수 있다.
마지막으로, 이 기사에서는 쿼럼이 없는 상황에 대한 샘플 로그 파일을 설명하지 않았다. 단일 노드에서 해당 피어 중 하나와 통신할 수 없게 되면 쿼럼이 유실된다(세 멤버가 투표 당사자인 경우 2/3가 다수이므로). 이 경우 노드는 쿼럼이 유실되었음을 파악하고 No Quorum Policy 핸들러를 호출한다. Listing 12에서는 그러한 이벤트로 인해 생성된 로그 파일 예제를 보여 준다. 쿼럼이 유실되면 이를 나타내는 로그 항목이 표시된다. 이 로그 항목이 표시된 클러스터 노드는 유동 리소스가 자신의 리소스가 아님을 알린다. ifconfig down 명령문이 해당 리소스를 해제한다.
Listing 12. 쿼럼 유실을 보여 주는 로그 항목
| <PRE class=displaycode> litsha22:~ # cat /var/log/messages .................... Jan 16 12:06:12 litsha22 ccm: [3899]: debug: quorum plugin: majority Jan 16 12:06:12 litsha22 ccm: [3899]: debug: cluster:linux-ha, member_count=1, member_quorum_votes=100 Jan 16 12:06:12 litsha22 ccm: [3899]: debug: total_node_count=3, total_quorum_votes=300 .................. Truncated For Brevity .................. Jan 16 12:06:12 litsha22 crmd: [3904]: info: crmd_ccm_msg_callback:callbacks.c Quorum lost after event=INVALID (id=15) Jan 16 12:06:12 litsha22 crmd: [3904]: WARN: check_dead_member:ccm.c Our DC node (litsha21) left the cluster .................. Truncated For Brevity .................. Jan 16 12:06:14 litsha22 IPaddr[5145]: INFO: /sbin/route -n del -host 192.168.71.205 Jan 16 12:06:15 litsha22 lrmd: [1619]: info: RA output: (IPaddr_1:stop:stderr) SIOCDELRT: No such process Jan 16 12:06:15 litsha22 IPaddr[5145]: INFO: /sbin/ifconfig eth0:0 192.168.71.205 down Jan 16 12:06:15 litsha22 IPaddr[5145]: INFO: IP Address 192.168.71.205 released Jan 16 12:06:15 litsha22 crmd: [3904]: info: process_lrm_event:lrm.c LRM operation (6) stop_0 on IPaddr_1 complete Jan 16 12:06:15 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Update (client: 3904, call:32): 0.54.599 -> 0.54.600 (ok) Jan 16 12:06:15 litsha22 mgmtd: [3905]: debug: update cib finished</PRE> |
Listing 12에서 볼 수 있듯이 지정된 임의의 노드에 대한 쿼럼이 유실되면 No Quorum Policy 구성의 선택으로 인해 어떠한 리소스도 사용되지 않는다. No Quorum Policy의 선택 여부는 사용자에게 달려 있다.
Linux 고가용성 시스템을 적절하게 구성한 후에는 추가 조치를 수행하지 않아도 클러스터 멤버가 다시 인스턴스화된다. Linux 인스턴스를 활성화하기만 해도 노드가 피어와 자동으로 연결된다. 기본 노드(즉, 모든 노드 중에서 유동 리소스를 우선적으로 받는 노드)를 구성한 경우 이 노드는 유동 리소스를 자동으로 다시 받는다. 기본 노드가 아닌 시스템은 단순히 사용 가능한 시스템 풀에 추가되고 일반적인 방법으로 처리된다.
다른 Linux 인스턴스를 풀에 추가하면 각 노드에 통지되고 쿼럼이 다시 설정된다(가능한 경우). 쿼럼을 다시 설정할 수 있으면 노드 중 하나에서 유동 리소스가 다시 설정된다.
| <PRE class=displaycode> litsha22:~ # tail -f /var/log/messages Jan 16 12:09:02 litsha22 heartbeat: [3892]: info: Heartbeat restart on node litsha21 Jan 16 12:09:02 litsha22 heartbeat: [3892]: info: Link litsha21:eth1 up. Jan 16 12:09:02 litsha22 heartbeat: [3892]: info: Status update for node litsha21: status init Jan 16 12:09:02 litsha22 heartbeat: [3892]: info: Status update for node litsha21: status up Jan 16 12:09:22 litsha22 heartbeat: [3892]: debug: get_delnodelist: delnodelist= Jan 16 12:09:22 litsha22 heartbeat: [3892]: info: Status update for node litsha21: status active Jan 16 12:09:22 litsha22 cib: [3900]: info: cib_client_status_callback:callbacks.c Status update: Client litsha21/cib now has status [join] Jan 16 12:09:23 litsha22 heartbeat: [3892]: WARN: 1 lost packet(s) for [litsha21] [36:38] Jan 16 12:09:23 litsha22 heartbeat: [3892]: info: No pkts missing from litsha21! Jan 16 12:09:23 litsha22 crmd: [3904]: notice: crmd_client_status_callback:callbacks.c Status update: Client litsha21/crmd now has status [online] .................... Jan 16 12:09:31 litsha22 crmd: [3904]: info: crmd_ccm_msg_callback:callbacks.c Quorum (re)attained after event=NEW MEMBERSHIP (id=16) Jan 16 12:09:31 litsha22 crmd: [3904]: info: ccm_event_detail:ccm.c NEW MEMBERSHIP: trans=16, nodes=2, new=1, lost=0 n_idx=0, new_idx=2, old_idx=5 Jan 16 12:09:31 litsha22 crmd: [3904]: info: ccm_event_detail:ccm.c CURRENT: litsha22 [nodeid=1, born=13] Jan 16 12:09:31 litsha22 crmd: [3904]: info: ccm_event_detail:ccm.c CURRENT: litsha21 [nodeid=0, born=16] Jan 16 12:09:31 litsha22 crmd: [3904]: info: ccm_event_detail:ccm.c NEW: litsha21 [nodeid=0, born=16] Jan 16 12:09:31 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Local-only Change (client:3904, call: 35): 0.54.600 (ok) Jan 16 12:09:31 litsha22 mgmtd: [3905]: debug: update cib finished .................... Jan 16 12:09:34 litsha22 crmd: [3904]: info: update_dc:utils.c Set DC to litsha22 (1.0.6) Jan 16 12:09:35 litsha22 cib: [3900]: info: sync_our_cib:messages.c Syncing CIB to litsha21 Jan 16 12:09:35 litsha22 crmd: [3904]: info: do_state_transition:fsa.c litsha22: State transition S_INTEGRATION -> S_FINALIZE_JOIN [ input=I_INTEGRATED cause=C_FSA_INTERNAL origin=check_join_state ] Jan 16 12:09:35 litsha22 crmd: [3904]: info: do_state_transition:fsa.c All 2 cluster nodes responded to the join offer. Jan 16 12:09:35 litsha22 attrd: [3903]: info: attrd_local_callback:attrd.c Sending full refresh Jan 16 12:09:35 litsha22 cib: [3900]: info: sync_our_cib:messages.c Syncing CIB to all peers ......................... Jan 16 12:09:37 litsha22 tengine: [5119]: info: send_rsc_command:actions.c Initiating action 4: IPaddr_1_start_0 on litsha22 Jan 16 12:09:37 litsha22 tengine: [5119]: info: send_rsc_command:actions.c Initiating action 2: probe_complete on litsha21 Jan 16 12:09:37 litsha22 crmd: [3904]: info: do_lrm_rsc_op:lrm.c Performing op start on IPaddr_1 (interval=0ms, key=2:c5131d14-a9d9-400c-a4b1-60d8f5fbbcce) Jan 16 12:09:37 litsha22 pengine: [5120]: info: process_pe_message:pengine.c Transition 2: PEngine Input stored in: /var/lib/heartbeat/pengine/pe-input-72.bz2 Jan 16 12:09:37 litsha22 IPaddr[5196]: INFO: /sbin/ifconfig eth0:0 192.168.71.205 netmask 255.255.255.0 broadcast 192.168.71.255 Jan 16 12:09:37 litsha22 IPaddr[5196]: INFO: Sending Gratuitous Arp for 192.168.71.205 on eth0:0 [eth0] Jan 16 12:09:37 litsha22 IPaddr[5196]: INFO: /usr/lib64/heartbeat/send_arp -i 500 -r 10 -p /var/run/heartbeat/rsctmp/send_arp/send_arp-192.168.71.205 eth0 192.168.71.205 auto 192.168.71.205 ffffffffffff Jan 16 12:09:37 litsha22 crmd: [3904]: info: process_lrm_event:lrm.c LRM operation (7) start_0 on IPaddr_1 complete Jan 16 12:09:37 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Update (client: 3904, call:46): 0.55.607 -> 0.55.608 (ok) Jan 16 12:09:37 litsha22 mgmtd: [3905]: debug: update cib finished Jan 16 12:09:37 litsha22 tengine: [5119]: info: te_update_diff:callbacks.c Processing diff (cib_update): 0.55.607 -> 0.55.608 Jan 16 12:09:37 litsha22 tengine: [5119]: info: match_graph_event:events.c Action IPaddr_1_start_0 (4) confirmed Jan 16 12:09:37 litsha22 tengine: [5119]: info: send_rsc_command:actions.c Initiating action 5: IPaddr_1_monitor_5000 on litsha22 Jan 16 12:09:37 litsha22 crmd: [3904]: info: do_lrm_rsc_op:lrm.c Performing op monitor on IPaddr_1 (interval=5000ms, key=2:c5131d14-a9d9-400c-a4b1-60d8f5fbbcce) Jan 16 12:09:37 litsha22 cib: [5268]: info: write_cib_contents:io.c Wrote version 0.55.608 of the CIB to disk (digest: 98cb6685c25d14131c49a998dbbd0c35) Jan 16 12:09:37 litsha22 crmd: [3904]: info: process_lrm_event:lrm.c LRM operation (8) monitor_5000 on IPaddr_1 complete Jan 16 12:09:38 litsha22 cib: [3900]: info: cib_diff_notify:notify.c Update (client: 3904, call:47): 0.55.608 -> 0.55.609 (ok) Jan 16 12:09:38 litsha22 mgmtd: [3905]: debug: update cib finished</PRE> |
Listing 13에서는 쿼럼이 다시 설정되었음을 알 수 있다. 쿼럼이 다시 설정되면 투표가 수행되고 litsha22가 유동 리소스를 가지고 있는 활성 노드가 된다.
![]() |
![]()
|
고가용성은 일련의 도전 과제이며 여기에서 설명한 솔루션에서는 첫 번째 단계를 설명한다. 이제 여러 가지 방법으로 환경을 개선할 수 있다. 중복 네트워킹, 실제 서버를 지원하는 클러스터 파일 시스템 또는 클러스터링을 직접 지원하는 고급 미들웨어를 추가할 수도 있다.
교육
- Wikipedia에 실려 있는 기본 네트워킹에 대한 기사는 기본적인 컴퓨터 토폴로지 및 네트워킹 작업을 이해하는 데 도움이 되는 유용한 리소스이다. Wikipedia에는 NAT(Network Address Translation)에 대한 자세한 정보도 있다.
- 기본적인 Apache 구성에 익숙하지 않다면 Apache HTTP server project의 홈 페이지를 방문하자. 이 사이트에서는 유용한 문서와 사용법 정보를 볼 수 있다. 사용자의 배포판에서 제공하는 Apache man 페이지에서도 추가 정보를 볼 수 있다.
- LVS(Linux Virtual Server) project에서는
ipvsadm을 비롯하여 이 기사에서 사용한 LVS 기술을 제공한다. 이 사이트에는 다양한 튜토리얼과 기타 유용한 문서가 있으며 메일링 목록도 있다.
- Linux-HA 웹 사이트에는 이 기사에서 설명한 고가용성 및 Heartbeat 구성 요소에 대한 유용한 정보가 있다.
- mon은 서비스 중단 및 복구를 모니터링하고 체크아웃하기 위한 프레임워크이다.
- IBM Cluster Systems Management 소프트웨어를 사용하여 대규모 Linux 클러스터를 설정하는 방법에 대해 설명하는 2편으로 구성된 연재 기사를 읽어보자.
- "Installing a large Linux cluster, Part 1: Introduction and hardware configuration"(developerWorks, 2006년 12월)
- "Installing a large Linux cluster, Part 2: Management server configuration and node installation"(developerWorks, 2007년 1월)
- "Craft a load-balancing cluster with ClusterKnoppix"(developerWorks, 2004년 12월)에서는 ClusterKnoppix Live CD를 사용하여 클러스터를 빌드하는 방법에 대해 설명한다.
- developerWorks Linux 영역에서는 Linux 튜토리얼과 지난 1개월 동안 조회 수가 높은 Linux 기사 및 튜토리얼을 포함하여 Linux 개발자에게 유용한 여러 가지 리소스를 볼 수 있다.
- developerWorks 기술 행사 및 웹 캐스트를 통해 최신 정보를 얻을 수 있다.
제품 및 기술 얻기
- DB2®, Lotus®, Rational®, Tivoli® 및 WebSphere®와 관련된 최신 Linux용 IBM 평가판 소프트웨어가 포함된 2개의 DVD 세트인 SEK for Linux를 주문하자.
- developerWorks에서 직접 다운드할 수 있는 IBM 평가판 소프트웨어를 사용하여 Linux와 관련된 후속 개발 프로젝트를 구현해 보자.
토론
- developerWorks spaces에 있는 개발자 블로그, 포럼, 포드캐스트 및 커뮤니티 항목을 통해 developerWorks 커뮤니티에 참여하자.
![]() | ||
![]() |
Eli M. Dow는 뉴욕 포킵시에 있는 IBM Test and Integration Center for Linux의 소프트웨어 엔지니어이다. Clarkson University에서 컴퓨터 과학 및 철학과 학사 학위를 받고 컴퓨터 과학과 석사 학위를 받았다. Clarkson Open Source Institute의 동문인 그는 GNOME 데스크탑, HCI(Human Computer Interaction), 가상화 및 Linux 시스템 프로그래밍에 관심을 갖고 있으며 IBM Redbook Linux for IBM System z9 and IBM zSeries의 공동 저자이다. | |
![]() | ||
![]() |
Frank LeFevre는 뉴욕 포킵시에 있는 IBM Systems and Technology Group의 Senior Software Engineer이다. IBM 메인프레임 하드웨어 및 운영 체제 분야에서 28년 이상의 경력을 가지고 있으며 Linux Virtual Server Platform Evaluation Test 팀의 Team Leader로 활동하고 있다. | |




http://www.fendsell.com/christian-louboutin-c-1001.html http://www.fendsell.com/christian-louboutin-christian-louboutin-shoes-c-1001_1059.html http://www.fendsell.com/christian-louboutin-christian-louboutin-boots-c-1001_1005.html http://www.fendsell.com/christian-louboutin-christian-louboutin-pumps-c-1001_1003.html http://www.fendsell.com/christian-louboutin-christian-louboutin-sandals-c-1001_1002.html http://www.fendsell.com/christian-louboutin-christian-louboutin-wedges-c-1001_1004.html http://www.fendsell.com/herve-leger-dress-c-1098.html http://www.fendsell.com/moncler-clothing-c-1093.html http://www.fendsell.com/moncler-clothing-moncler-kids-c-1093_1094.html http://www.fendsell.com/moncler-clothing-moncler-men-c-1093_1095.html http://www.fendsell.com/moncler-clothing-moncler-vest-c-1093_1097.html http://www.fendsell.com/moncler-clothing-moncler-wowen-c-1093_1096.html http://www.fendsell.com/ugg-australia-bags-c-1078.html http://www.fendsell.com/ugg-australia-boots-c-1067.html http://www.fendsell.com/ugg-australia-boots-ugg-classic-metallic-5812-c-1067_1068.html http://www.fendsell.com/ugg-australia-boots-ugg-classic-tall-5815-c-1067_1069.html http://www.fendsell.com/ugg-australia-boots-ugg-classic-mini-5854-c-1067_1070.html http://www.fendsell.com/ugg-australia-boots-ugg-classic-cardy-5819-c-1067_1071.html http://www.fendsell.com/ugg-australia-boots-ugg-classic-short-5825-c-1067_1072.html http://www.fendsell.com/ugg-australia-boots-ugg-tall-romantic-flower-c-1067_1073.html http://www.fendsell.com/ugg-australia-boots-ugg-ultra-tall-5245-c-1067_1074.html http://www.fendsell.com/ugg-australia-boots-ugg-ultra-short-5225-c-1067_1075.html http://www.fendsell.com/ugg-australia-boots-ugg-nightfall-5359-c-1067_1076.html http://www.fendsell.com/ugg-australia-boots-ugg-sundance-ii-5325-c-1067_1077.html http://www.fendsell.com/ugg-australia-boots-ugg-kids-c-1067_1079.html http://www.fendsell.com/ugg-australia-boots-ugg-bailey-button-c-1067_1080.html http://www.fendsell.com/ugg-australia-boots-ugg-boots-roxy-c-1067_1081.html http://www.fendsell.com/ugg-australia-boots-ugg-womens-sandals-c-1067_1083.html http://www.fendsell.com/ugg-australia-boots-ugg-womens-short-boots-c-1067_1084.html http://www.fendsell.com/ugg-australia-boots-ugg-tasmina-sandals-c-1067_1085.html http://www.fendsell.com/ugg-australia-boots-ugg-sundance-limited-edition-c-1067_1086.html http://www.fendsell.com/giuseppe-zanotti-c-1099.html http://www.fendsell.com/giuseppe-zanotti-giuseppe-zanotti-boots-c-1099_1101.html http://www.fendsell.com/giuseppe-zanotti-giuseppe-zanotti-sandal-c-1099_1100.html http://www.fendsell.com/manolo-blahnik-c-1060.html http://www.fendsell.com/chanel-shoes-c-1088.html http://www.fendsell.com/ferragamo-c-1090.html http://www.fendsell.com/gucci-shoes-c-1066.html http://www.fendsell.com/jimmy-choo-c-1065.html http://www.fendsell.com/mbt-shoes-c-1091.html http://www.fendsell.com/mbt-shoes-mbt-chapa-shoes-c-1091_1092.html http://www.fendsell.com/tory-burch-c-1102.html http://www.fendsell.com/yves-saint-lauret-c-1087.html http://www.fendsell.com/alexander-mcqueen-c-1089.html http://www.fendsell.com/louis-vuitton-bag-c-1006.html http://www.fendsell.com/louis-vuitton-bag-2009-new-style-c-1006_1021.html http://www.fendsell.com/louis-vuitton-bag-bright-series-c-1006_1010.html http://www.fendsell.com/louis-vuitton-bag-damier-canvas-c-1006_1012.html http://www.fendsell.com/louis-vuitton-bag-epi-leather-c-1006_1015.html http://www.fendsell.com/louis-vuitton-bag-fashion-leather-c-1006_1018.html http://www.fendsell.com/louis-vuitton-bag-fuchsia-c-1006_1011.html http://www.fendsell.com/louis-vuitton-bag-geant-canvas-c-1006_1016.html http://www.fendsell.com/louis-vuitton-bag-monogram-canvas-c-1006_1020.html http://www.fendsell.com/louis-vuitton-bag-monogram-jokes-c-1006_1014.html http://www.fendsell.com/louis-vuitton-bag-multicolor-c-1006_1013.html http://www.fendsell.com/louis-vuitton-bag-tahiti-series-c-1006_1019.html http://www.fendsell.com/chanel-bags-c-1008.html http://www.fendsell.com/chanel-bags-2-55-series-c-1008_1036.html http://www.fendsell.com/chanel-bags-2009-new-style-c-1008_1061.html http://www.fendsell.com/chanel-bags-antisnake-bags-c-1008_1039.html http://www.fendsell.com/chanel-bags-ball-pattern-leather-bags-c-1008_1041.html http://www.fendsell.com/chanel-bags-bright-leather-bags-c-1008_1040.html http://www.fendsell.com/chanel-bags-canvas-bags-c-1008_1044.html http://www.fendsell.com/chanel-bags-crack-turtle-bags-c-1008_1038.html http://www.fendsell.com/chanel-bags-embroidery-bags-c-1008_1037.html http://www.fendsell.com/chanel-bags-fabric-leather-bags-c-1008_1035.html http://www.fendsell.com/chanel-bags-handgrab-bags-c-1008_1034.html http://www.fendsell.com/chanel-bags-handbags-c-1008_1033.html http://www.fendsell.com/chanel-bags-rain-leather-bags-c-1008_1043.html http://www.fendsell.com/chanel-bags-sheepskin-leather-bags-c-1008_1042.html http://www.fendsell.com/chanel-bags-shoulder-bags-c-1008_1031.html http://www.fendsell.com/chanel-bags-skew-bags-c-1008_1032.html http://www.fendsell.com/gucci-bags-c-1007.html http://www.fendsell.com/gucci-bags-2009-new-style-c-1007_1030.html http://www.fendsell.com/gucci-bags-handgrab-bags-c-1007_1029.html http://www.fendsell.com/gucci-bags-leather-bags-c-1007_1027.html http://www.fendsell.com/gucci-bags-logo-handbags-c-1007_1024.html http://www.fendsell.com/gucci-bags-logo-shoulder-bags-c-1007_1023.html http://www.fendsell.com/gucci-bags-logo-skew-bags-c-1007_1022.html http://www.fendsell.com/gucci-bags-man-style-bags-c-1007_1028.html http://www.fendsell.com/gucci-bags-pvc-fabric-bags-c-1007_1025.html http://www.fendsell.com/gucci-bags-waterproof-series-c-1007_1026.html http://www.fendsell.com/coach-bags-c-1009.html http://www.fendsell.com/coach-bags-bright-leather-bags-c-1009_1049.html http://www.fendsell.com/coach-bags-handbags-c-1009_1048.html http://www.fendsell.com/coach-bags-shoulder-bags-c-1009_1046.html http://www.fendsell.com/coach-bags-skew-bags-c-1009_1047.html http://www.fendsell.com/wallets-c-1050.html http://www.fendsell.com/wallets-chanel-wallet-c-1050_1053.html http://www.fendsell.com/wallets-coach-wallet-c-1050_1054.html http://www.fendsell.com/wallets-gucci-wallet-c-1050_1052.html http://www.fendsell.com/wallets-louis-vuitton-wallet-c-1050_1051.html http://www.fendsell.com/hemers-bags-c-1055.html http://www.fendsell.com/prada-bags-c-1057.html