DNS Failover 구성 방법
서버 앞단의 로드밸런서마저 죽거나, 아예 aws 리전이나 idc가 날아가는 대재앙이 발생했을때 최후의 보루로 DNS Failover (DNS 기반 장애 조치)에 대해서 알아보겠다.
DNS Failover (LB랑 차이) #
일반적으로 L4/L7 로드밸런서 AWS ALB, Nginx등은 하나의 네트워크 망에서 서버들끼리 트래픽을 분산한다.
하지만 로드밸런서 자체가 죽거나 해당 네트워크망이 끊기면 답이 없다.
DNS Failover는 아예 글로벌 단위의 이름 확인(domain to ip) 단계에서 방향을 틀어버리는 기술이다.
스마트한 DNS(AWS Route 53, Cloudflare)가 백엔드 서버들의 상태를 실시간으로 감시 health check하다가 메인 서버 a가 죽었다고 판단되면 클라이언트에게 예비 서버 b의 ip를 던져주는 방식이다.
- Health Check: DNS서버가 주기적으로 예시로 10초마다 핑 혹은 http request를 서버로 보내 생존을 확인한다.
- Routing Policy(라우팅 정책): 서버가 죽었을때 어떤 비율, 어떤 우선순위로 다른 ip를 반환할지 결정한다.
- TTL: 클라이언트나 통신사 kt skt 같은 DNS가 이 ip 주소를 알아내기위해 얼마나 오랫동안 캐싱(기억)할것인지를 결정하는 시간이다. DNS Failover의 가장 중요한 키워드임
DNS Failover 라우팅 정책 #
Active-Passive DR - 재해 복구형 #
가장 정석적인 Failover 방식이다
평상시에는 모든 트래픽이 100인 메인 서버 primary로만 요청이 향한다.
예비서버 secondary는 데이터 동기화만 받으면서 쉬고있다가 장애가 발생하면
즉 메인서버 health check가 실패하면 DNS는 예비 서버의 ip를 반환하기 시작한다.
장점은 인프라 관리가 직관적이고 평소 트래픽이 한곳으로 집중되어 캐시 효율이 좋다.
Active-Active - 가중치 기반 분산형 #
글로벌 서비스나 대규모 트래픽 환경에서 쓰는데 평상시 서울리전 A 50% 도쿄리전 B 50%등 가중치 weight를 두어 트래픽을 양분한다.
장애시 서울 리전이 죽으면 DNS는 A를 명단에서 빼버리고 모든 트래픽 100%를 살아있는 도쿄 리전으로 몰아준다.
장점은 비싼 예비 서버를 평소에도 써서 트래픽 분산이 가능하지만 관리가 좀 더 어려워진다.
DNS Failover TTL 딜레마 #
DNS Failover는 real-time 즉 즉각적이지 않다.
Route53에서 죽은 서버의 ip를 1초만에 예비 서버 ip로 교체했다하더라도, 사용자의 pc, 브라우저, 통신사 isp dns 서버에는 기존의 죽은 ip가 TTL 시간동안 캐싱이 되어있다.
TTL을 너무 길게 예를들어 막 1시간씩 잡으면 장애 발생시 1시간동안 사용자들은 죽은 서버로 요청을 보내고 접속을 시도해 에러를 보게된다. 장애복구 지연인건데 그렇다고 TTL을 너무 짧게잡으면 사용자들은 매분 DNS 서버에 쿼리를 날려야하므로 접속지연이 미세하게 증가하고 dns query 요금도 나온다.
여기서 타협은 Failover가 적용된 주요 도메인은 보통 TTL을 60초 혹은 30초로 짧게 잡고 장애 발생후 최대 1~2분안에 트래픽이 전환되도록 구성하는 방안이 있다.
Example #
AWS Route53을 기준으로 Active-Passive환경을 IaC로 구성하고 검증하는 방법을 보자.
AWS Route 53 Failover 구성
콘솔에서 클릭하는 대신, 아래 코드로 health check, failover 레코드를 한 번에 찍어낸다
# 1. Primary 서버 상태 검사 (Health Check) 생성
resource "aws_route53_health_check" "primary_hc" {
fqdn = "api-primary.mywebsite.com"
port = 443
type = "HTTPS"
resource_path = "/health" # 이 경로로 200 OK가 떨어져야 살았다고 판단
failure_threshold = 3 # 3번 연속 실패 시 죽은 것으로 간주
request_interval = 10 # 10초마다 찌름
}
# 2. 메인(Primary) DNS 레코드 (평소엔 여기로 트래픽이 감)
resource "aws_route53_record" "www_primary" {
zone_id = aws_route53_zone.main.zone_id
name = "www.mywebsite.com"
type = "A"
ttl = 60 # 장애 시 빠른 전환을 위해 TTL을 60초로 짧게 부여
records = ["13.123.45.67"] # 메인 서버 IP
failover_routing_policy {
type = "PRIMARY"
}
set_identifier = "primary-record"
health_check_id = aws_route53_health_check.primary_hc.id
}
# 3. 예비(Secondary) DNS 레코드 (Primary가 죽으면 이 IP를 반환)
resource "aws_route53_record" "www_secondary" {
zone_id = aws_route53_zone.main.zone_id
name = "www.mywebsite.com"
type = "A"
ttl = 60
records = ["52.98.76.54"] # DR(예비) 서버 IP
failover_routing_policy {
type = "SECONDARY"
}
set_identifier = "secondary-record"
}
장애 발생시 터미널 검증 dig
엔지니어가 pc에서 dns 레코드가 제대로 전환되는지 확인하는 방법인데
# 평상시 dns 쿼리 질의 짧게 보려고 +short붙여줌
dig www.mywebsite.com +short
13.123.45.67 # 메인서버 ip 반환
# 2. 장애 발생 시 (Primary 서버 다운 후, 약 1~2분 경과)
# 로컬 DNS 캐시를 무시하고 구글 퍼블릭 DNS(8.8.8.8)에 직접 질의
dig @8.8.8.8 www.mywebsite.com +short
52.98.76.54 # (Primary Health Check 실패가 감지되어, 자동으로 Secondary 예비 서버 IP로 교체되어 반환됨)
이렇게 dns 수준에서 트래픽을 우회시켰다면 예비 서버 DR 쪽에서는 데이터베이스가 기존 메인 서버와 동일한 데이터를 가지고있어야만 정상적인 서비스가 가능하다.