L4 DSR 에서 arp_ignore, arp_announce 설정의 정확한 이해

on-premise 환경에서 L4 로드 밸런서를 DSR(Direct Server Return) 모드로 구성할 때, 리눅스 서버의 kernel parameter 중 arp_ignore, arp_announce를 적절히 설정해야 한다. 이 parameter들의 용도에 대해 잘못 이해하고 있는 경우가 많아서 그 정확한 의미를 정리했다. ARP의 동작 방식에 대해 더 깊이 이해하는 데도 도움이 될 것이다.

DSR 모드의 개요

Direct Server Return의 준말인데, 정식 용어가 아니라 편의상 이렇게 부르는 것이다. L4 로드 밸런서의 부담을 줄이기 위해 real server가 클라이언트에 패킷을 바로 전송하게 하는 구성이다.

트래픽의 흐름이 아래와 같다.
클라이언트 -> L4 로드 밸런서 (virtual server) -> real server -> 클라이언트

현재는 L4 로드 밸런서의 성능이 충분해서 성능 때문에 이렇게 구성할 필요는 별로 없지만, 클라이언트의 source IP를 보존할 수 있다는 장점 때문에 아직도 많이 쓰이는 방법이다.

이 포스트에서 DSR 모드의 전반적인 구성이나 설정 방법을 자세히 다루지는 않는다. 만약 DSR 모드나 ARP에 대한 사전 지식이 충분치 않다면 관련 내용을 먼저 파악하고 이 포스트를 읽으면 더 쉽게 이해할 수 있을 것이다.

요점

인터넷에서 찾을 수 있는 문서들은 대부분 /etc/sysctl.conf를 아래처럼 설정하도록 안내한다. 대부분 이렇게 설정하고 있을 것이다.

1net.ipv4.conf.all.arp_ignore = 1
2net.ipv4.conf.all.arp_announce = 2
3
4net.ipv4.conf.lo.arp_ignore = 1
5net.ipv4.conf.lo.arp_announce = 2

위에서 loopback interface인 lo에 한 설정이 의미가 없다는 것이 이 포스트의 요점이다. 이 parameter들은 패킷을 수신하는 실제 interface에 설정해야 효력이 있다. 불필요한 설정이 추가된 것이라서 동작에는 문제가 없지만 정확한 의미를 알아야 트러블슈팅을 잘할 수 있다.

DSR 모드로 구성하려면, real server의 loopback interface에 L4 로드 밸런서의 VIP를 추가해야 한다. L4 로드 밸런서는 클라이언트에서 받은 패킷의 source IP, destination IP(L4 VIP)의 값을 그대로 보존한 채로 MAC address만 real server의 것으로 바꿔서 real server에 전달한다.

destination IP가 VIP인 이 패킷을 real server가 수신하게 하려고 loopback interface에 VIP를 추가한다. 이렇게 하면 real sever가 VIP를 자신의 IP처럼 인식한다.

하지만 real server가 VIP를 자신의 것으로 인식하는 것은 L4 로드 밸런서가 보낸 패킷을 받는 경우에만 국한되어야 한다. 만약 다른 호스트가 L4 로드 밸런서에 보낸 패킷까지 real server가 수신하고 응답하면 통신이 엉망이 된다.

이런 문제를 막으려면, 같은 L2 network에 있는 호스트와 라우터가 VIP에 해당하는 MAC address를 L4 로드 밸런서의 것으로 정확히 알고 있어야 한다. 즉, L4 로드 밸런서의 것이 아닌 real server의 MAC address로 잘못 알면 안된다.

real server에 arp_ignore, arp_announce parameter를 설정하는 이유가 바로 이 때문이다.

이 parameter들로 VIP에 대한 real sever의 ARP 관련 동작을 정하는 것이다. 그런데 VIP를 loopback interface에 설정하니 이 parameter를 loopback interface에 설정하는 것이 언뜻 자연스러워보인다. 그래서 정확하지 않은 내용이 널리 알려지게 된 것 같다.

올바른 설정 방법

/etc/sysctl.conf 의 내용이 아래와 같아야 한다.

1#/etc/sysctl.conf 
2net.ipv4.conf.default.arp_ignore = 1
3net.ipv4.conf.default.arp_announce = 2
4#loopback interface에는 설정할 필요가 없지만 맥락을 분명하게 하기 위해 아래처럼 했다.
5net.ipv4.conf.lo.arp_ignore = 0 
6net.ipv4.conf.lo.arp_announce = 0 

이 parameter들은 아래와 같은 형식으로 사용한다.

1 * net.ipv4.conf.(<target-interface>|all|default).arp_ignore
2 * net.ipv4.conf.(<target-interface>|all|default).arp_announce

‘default’ 대신 ‘all’을 써도 원하는 결과를 얻을 수 있으나 all을 선택하면 개별 interface마다 다른 설정을 할 수 없으니 default가 더 유연하다.

default는 interace가 처음 생성될 때 복사되는 값이고 all은 모든 interace에 영향을 주는 값이다.
all에 설정된 값과 interface별로 설정된 값 중에 실제로 어떤 값이 효력을 가질지는 kernel parameter 별로 다르니 자세한 내용은 여기를 참고한다.

참고로, /etc/rc.local 스크립트에서 sysctl 명령을 실행하면 안되고 /etc/sysctl.conf에 설정해야 한다. /etc/rc.local은 시스템 초기 셋업 (System V init)의 후반부에 실행되기 때문에 interface가 올라오면서 자신의 MAC address를 L2 network에 알리기 위해 Gratuitous ARP를 전송하는 시점에는 스크립트가 실행되지 않는다.

arg_ignore

ARP request를 받았을 때 응답을 할지 여부를 결정한다.

  • L4 로드 밸런서의 VIP를 real server의 loopback interface에 추가했을 때, real server의 default 동작은 이 VIP에 대한 ARP request에 응답을 하는 것이다
  • real server가 VIP에 대한 ARP request에 응답하면 안되니 arp_ignore 설정을 default 값인 0이 아닌 1로 해야 한다
  • arp_ignore는 interface 별로 설정할 수 있는데, loopback interface에 하는 것이 아니라 실제로 통신이 일어나는 interface에 해야 한다

설정값의 의미

  • 0 (default) : ARP request가 도착했을 때, 조회 대상 IP가 이 시스템의 어떤 interface이건 (loopback 포함) 있기만 하면 응답
  • 1 : arp_ignore가 1로 설정된 interface를 통해 ARP request가 도착하면 조회 대상 IP가 이 interface에 직접 설정되어 있을 때만 응답

ARP request는 loopback이 아니라 실제 통신이 일어나는 interface에 도착하므로 그 interface의 arp_ignore 가 1이어야 한다. lookback interface에는 ARP request 등 외부 패킷이 도달하지 않으므로 lo에 설정하는 것은 의미가 없다.

arp_announce

ARP request를 보낼 때 ‘sender IP 주소’에 어떤 값을 쓸지 정하는 parameter이다.

여기서 sender IP 주소는 IP header의 source IP가 아니라 ARP request 내용(payload)의 일부분이다. ARP는 L2(Ethernet 등)에서 통신하는 protocol이기 때문에 IP 헤더가 없다.

ARP 패킷의 구조:

이 parameter를 사용하는 목적은 아래와 같다.

호스트의 ARP cache는 ARP reply를 받았을 때 업데이트되는 것이 기본이다. 그런데 호스트가 ARP request를 수신했을 때도 패킷의 내용(payload)에 포함된 sender IP 주소와 sender MAC 주소를 사용해서 ARP cache를 업데이트한다. 따라서 real server에서 ARP request를 보낼 때 sender IP 값이 VIP이면 이 패킷을 받는 서버들이 자신의 ARP cache에서 VIP의 MAC 주소를 real server의 것으로 업데이트한다. 이렇게 되면 트래픽이 엉뚱한 곳으로 가게되는데 이 parameter를 이용해 방지할 수 있다.

설정값의 의미

  • 0 (default) : sender IP 주소로 시스템에 설정된 어떤 IP든 사용할 수 있음
  • 2 : sender IP 주소로 가능하면 ARP request를 실제 전송하는 interface에 설정된 IP를 사용. 실제 기준은 좀 더 복잡하니 정확한 것은 여기를 참고할 것

테스트 방법

설정을 잘못해서 real server가 VIP에 대한 ARP request에 응답하는 현상을 확인하는 방법이다.

host A, host B 모두 eth0 으로 10.41.66.0/24 네트웍에서 통신하고 있을 때 아래처럼 확인할 수 있다. host A가 real server 역할이고 10.41.66.100이 VIP이다. host B는 L4 로드 밸런서의 로드밸런싱 구성에 포함되지 않는 서버이다.

host A:

1sudo sysctl -w net.ipv4.conf.eth0.arp_ignore = 0  
2sudo ifconfig lo:0 10.41.66.100 netmask 255.255.255.255  # lo에 VIP 추가

host B:

1$ sudo arping -I eth0 -b 10.41.66.100  # VIP에 대한 ARP request를 L2 network에 broadcast
2
3ARPING 10.41.66.100 from 10.41.66.45 eth0
4Unicast reply from 10.41.66.100 [00:22:19:BA:D1:DF]  0.641ms   => 00:22:19:BA:D1:DF 은  host A의 MAC 주소
5Unicast reply from 10.41.66.100 [00:22:19:BA:D1:DF]  0.609ms
6Unicast reply from 10.41.66.100 [00:22:19:BA:D1:DF]  0.614ms

위의 결과에서 보다시피 host A는 lookback interface에 설정된 10.41.66.100 에 대한 ARP request를 받았을 때도 자신의 MAC 주소로 응답한다.

참고로, 이런 테스트 환경은 Vagrant로 VM들의 로컬 네트워크를 구성하면 쉽게 만들수 있다.

참고 문서

comments powered by Disqus