서울에서 브라우저에 IP를 입력하고, 친구가 상파울루에서 같은 IP를 입력하면, 두 사람은 서로 다른 대륙에 있는 서로 다른 두 대의 기계와 대화한다. 리다이렉트도 아니고, 각자에게 다른 주소를 건네준 DNS 트릭도 아니고, 중간에서 트래픽을 가르는 로드 밸런서도 아니다. 같은 32비트의 목적지 주소인데, 패킷이 그냥 서로 다른 곳으로 간다. 둘 다 눈치채지 못한다. 눈치챌 필요도 없다.
그게 anycast다. 이게 정확히 무슨 일을 하는지 처음으로 제대로 이해하는 순간, 어쩐지 불법처럼 들린다. IP 주소는 하나의 호스트를 가리키게 되어 있다. anycast는 그 주소 하나를 수십, 수백 곳에서 동시에 광고한다. 각 위치가 인터넷 라우팅 시스템을 향해 자기가 그 주소라고 우긴다. “진짜”라는 개념이 없는 라우팅 시스템은 그냥 어깨를 으쓱하고, 가장 가까운 주장자에게 당신의 패킷을 배달한다.
거짓말, 그리고 그걸 믿는 쪽
믿는 쪽은 BGP다 — Border Gateway Protocol, 인터넷의 독립적인 네트워크들을 꿰매 붙이는 라우팅 접착제. BGP가 하는 일은 임의의 목적지 프리픽스에 대해 패킷을 어느 방향으로 보낼지 알아내는 것이다. 이웃들이 “나는 이 주소 블록에 도달할 수 있다”고 광고하는 걸 들으며 도달 가능성을 학습하고, 경쟁하는 광고들 사이에서 여러 지표로 하나를 고른다. 대표 지표는 AS-path 길이 — 대략, 가장 적은 네트워크를 거치는 경로다.
anycast는 바로 이걸 악용한다. 주소 블록을 운영하는 모든 사이트에서 광고한다. 이제 인터넷의 모든 라우터는 똑같이 참인 여러 주장을 듣는다 — “이 프리픽스는 여기 있다”, “아니, 여기 있다” — 그리고 자기가 아는 유일한 방식으로 해소한다: 가장 가까운 걸 고른다. 지리적 킬로미터가 아니라 경로 길이와 정책이라는 BGP의 의미에서 가깝다. 보통은 지리와 맞아떨어진다. 가끔은 피어링의 기벽 때문에 지도상으로는 터무니없어 보이는 곳으로 패킷이 간다. 핵심은 당신이 고르지 않는다는 것이다. 라우팅 직물이 모든 클라이언트마다 독립적으로 고르고, 그 선택은 “가까운 쪽”이다.
이건 옆에 덧붙인 꼼수가 아니다. RFC 4786 Operation of Anycast Services가 2006년 12월에 이 운영 관행을 표준화했다. 메커니즘은 언제나 그냥 BGP가 늘 하던 일을, 의도적으로 모호한 목적지를 향해 시킨 것뿐이었다.
모두가 제기했던 반박, 그리고 그게 틀렸던 이유
여기서부터가 흥미롭다. 수년간, anycast에는 명확한 한계가 있다는 자신만만한 합의가 있었기 때문이다: 무상태(stateless)의 단발성 요청에는 괜찮지만 그 외에는 위험하다는 것. UDP 위의 DNS? 완벽하다 — 질의 하나와 응답 하나, 기억 없음, 어느 인스턴스가 답하든 아무도 신경 쓰지 않는다. 그런데 TCP는 상태가 있다(stateful). TCP 연결은 시퀀스 번호와 버퍼 더미로서 특정한 한 대의 기계 위에 산다. 연결 도중에 BGP가 다시 수렴해 당신의 패킷을 다른 anycast 인스턴스로 몰기 시작하면, 그 기계는 당신의 연결을 들어본 적이 없다. 당신의 데이터에 RST로 답한다. 세션이 죽는다.
그래서 교과서적 답은 이렇게 굳었다: DNS에는 anycast, 중요한 나머지에는 unicast. 합리적이다. 그리고, 알고 보니, 대체로 틀렸다.
이 걱정의 결함은 그 전제에 있다 — BGP 경로가 TCP 연결의 시간 척도에서 펄럭인다는 것. 그렇지 않다. 건강한 네트워크에서 경로는 한번 정해지면 몇 분에서 몇 시간 동안 안정적이다. 웹 요청이 사는 몇 초보다 압도적으로 길다. 재수렴이 당신의 연결 도중에 떨어지면서 당신의 인스턴스를 바꾸는 창은 미미하다. 연구자들이 실제 운영 중인 anycast CDN 위의 장기 TCP 흐름을 측정했을 때, 연결 도중 인스턴스 전환이 일으킨 실패는 미미한 비율이었다 — 0.1%에 한참 못 미쳤고, 인터넷에서 어차피 일어나는 평범한 패킷 손실과 reset에 묻혔다.
증거는 당신이 거의 확실히 지금 이걸 쓰고 있다는 것이다. Cloudflare는 사실상 네트워크 전체를 anycast로 돌린다. 같은 주소 블록을 수백 개 도시의 데이터센터에서 광고하며, 수십억 개의 TCP·TLS 연결을 나른다 — 완전한 HTTPS, 상태 있는, 정확히 교과서가 할 수 없다고 한 그것이다. Fastly와 다른 곳들도 똑같이 한다. “anycast는 TCP를 못 나른다”는 규칙은, 그게 작동하기를 필요로 한 사람들이 조심스럽게 만들어 버티게 하자 살아남지 못했다.
실제로 무엇을 얻는가
상태 있는 트래픽이 그 위에서 살아남는다는 걸 받아들이고 나면, anycast는 호기심거리이길 멈추고 네트워킹에서 가장 값싼 분산 메커니즘이 된다. 마법이 전부 네트워크 안에 있고 클라이언트에는 아무것도 없기 때문이다.
근접성이 자동이다. 리졸버로 사용자 위치를 추측하는 geo-DNS도 없고, 클라이언트 측 서버 선택도 없다. 패킷이 가까운 인스턴스를 찾아가는 건 “가까움”이 말 그대로 라우팅이 이미 작동하는 방식이기 때문이다.
장애 조치(failover)도 자동이고, 이게 운영자들이 사랑하는 부분이다. 한 사이트가 죽으면 그 BGP 광고를 철회한다 — 아니면 사이트가 꺼지면서 스스로 철회한다. 다른 사이트들은 여전히 같은 주소를 광고하고 있다. 라우팅이 몇 초 만에 재수렴하고, 죽은 사이트로 가던 모든 클라이언트가 이제 그다음으로 가까운 사이트로 간다. 기다릴 DNS TTL도, 바꿀 레코드도, 다른 주소로 재시도해야 하는 클라이언트도 없다. Cloudflare 자신의 표현은 직설적이다: 데이터센터 하나를 통째로 오프라인으로 내려도 트래픽은 그냥 다음으로 가까운 곳으로 흐른다.
그리고 공격은 집중되는 대신 희석된다. 하나의 anycast 주소를 겨냥한 대규모 DDoS는 한 대의 기계에 쌓이지 않는다. 그 주소를 광고하는 모든 사이트로 갈라지고, 각 사이트는 그 공격자 무리에 라우팅상 가장 가까운 조각을 흡수한다. 이것이 바로 DNS 루트 서버들이 2000년대에 플러딩을 당한 뒤 옮겨간 아키텍처다 — 13개의 유명한 주소, 그러나 그 뒤에는 1,900대가 넘는 물리 인스턴스가 있다. 단 하나의 기계도 표적이 되지 않도록 정확히 그렇게.
하나의 주소. 여러 대의 서버. 그것들이 모두 이름을 공유하게 기꺼이 내버려둔 라우팅 프로토콜, 그리고 누구의 예상보다 훨씬 기꺼이 함께 올라타준 상태 있는 인터넷.