AWS Multi-AZ와 DNS 캐시

Jeongbong Seo
bgpworks
Published in
5 min readMay 6, 2022
보험으로 구매하는 AWS의 Multi-az 기능. 그런데 막상동작하지 않는다면 무슨 소용일까.

AWS의 Managed DB를 서비스에서 사용할 경우, 고가용성을 위한 보험으로 비싼 돈을 주고 Multi-AZ를 같이 구매한다. 그런데 정작 서버에서 네트워크 관련 설정을 올바르게 하지 않으면 기능이 기대한 대로 동작하지 않아 비싼 보험비를 날리게 된다.

기본적으로는 아래 설정들을 확인해볼 필요가 있다.

  • DNS cache 시간
  • Connection Pool 설정

Multi-AZ와 DNS

Multi-AZ 동작 방식은 Stand-by 서버를 한대 더 띄워놓고, DB 서버에 문제가 발생할 경우 Stand-by 서버로 빠르게 전환시켜 서비스 중단 시간을 최소화 시켜준다. 이 때 전환시키는 방식은 DB 서버의 domain에 연결된 IP 주소를 stand-by 서버의 IP 주소로 변경하는 방식으로 이루어 진다.

그런데 AWS는 설정을 변경했지만 내 어플리케이션은 이 변경사항을 전달 받지 못하는 경우가 발생한다. DNS 자체가 거대한 분산형 DB인데다, 중간에 캐시들이 많이 껴 있어서 변경사항이 빠르게 반영이 안될 때가 있기 때문이다.

DNS 캐시

DNS resolve는 비교적 시간이 오래 걸리는 작업이기 때문에, 여러 단계 레이어에서 캐시를 한다. (심지어 브라우저도 캐시를 한다!)

a) 언어 Runtime이 제공하기도 하고,
b) OS 레벨에서 재공하기도 한다. (또는 로컬 DNS cache 서비스)
c) 네임서버(미 설정 시 ISP의 네임서버)가 재공한다.
d) AWS의 네임서버. 여기가 원본 데이터!

a)에서 c) 중에 누군가가 캐시 결과를 밷어서 내 어플리케이션이 변경사항을 전달받지 못할 수 있다. 😢

서비스마다 다르지만, 크롤링이나 프록시 서비스가 아닌 경우에는 API 서버가 임의의 다양한 도메인 주소와 통신할 일은 별로 없다. 어짜피 지속적으로 통신하는 서비스와는 보통 Connection Pool을 사용하기 때문에 DNS 캐시를 비활성화 시키는 것도 한 방법이다.

ISP의 네임서버

AWS RDS를 사용할 경우 보통 서버도 AWS에서 돌리기 때문에 이 부분은 보통은 문제가 되진 않는다. 그 외의 경우에 문제가 발생한다면 사실 할 수 있는게 거의 없다. 가장 유명한 구글의 네임서버(8.8.8.8)나 CloudFlare(1.1.1.1)의 네임서버 조차도 가끔은 즉각적으로 변경된 결과를 주지 못할 때가 있다.

OS 레벨의 DNS 캐시

OSX나 Window는 OS 레벨에서 DNS 캐시를 재공한다. Linux 자체에는 DNS 캐시가 없지만, 대신 로컬 DNS cache 서비스가 있을 수 있다. (Systemd-Resolved, DNSMasq, Nscd 등등) 혹시나 이런 서비스가 있는지 확인해보고 설정을 바꾸거나 비활성화 시키자. 참고

언어 런타임의 DNS 캐시

Heroku나 Vercel, Beanstalk 같은 PaaS를 사용해서 서버를 운영할 경우 위 두 단계는 설정할 수도 없고, 문제가 되는 경우도 거의 없다. 대신 내가 쓰는 언어가 내부적으로 DNS 캐시를 할 수 있다. Node.js 는 내부적으로 DNS 캐시가 없지만 Java는 JVM에 자체적인 DNS 캐시 기능이 있다.

Java 프로젝트에 적용하기

사용하는 라이브러리와 언어에 따라 세부사항은 모두 다를 수 있기 때문에 일반적으로 체크할 내용들만 집어보겠다.

JVM의 DNS Cache 끄기

AWS 문서에서도 친절하게 설명하고 있다. 다만 Java distribution이 다양하기 때문에 자신이 사용하는 구현체의 기본 설정값과 설정 방법을 살펴볼 필요가 있다. 설정을 바꾸는 방법으로는 크게

a) 환경 설정 파일을 바꾸는 방법과
b) JVM을 켤 때 인자를 넘겨서 설정하는 방법,
c) 마지막으로 내 코드의 bootstrap 과정에서 System 함수 호출로 직접 설정하는 방법이 있다.

a)와 b) 방법을 선택하면 Dockerize 하는 과정에서 적용할 수 있어서 인프라적인 요소를 비지니스 코드와 분리할 수 있는 장점이 있다. c) 방법을 선택하면 배포 구조가 간단해지고 코드 스스로가 자기 완성적으로 모든 설정을 유지할 수 있는 장점이 있다. 취향에 맞게 선택하면 된다.

커넥션 풀 설정 확인

커넥션 풀이 오류가 난 연결은 빠르게 포기하고 새로운 연결을 맺도록 설정을 해야 한다. 커넥션 풀 라이브러리의 max-lifetime, connection timeout, validation timeout, idle timeout, socket timeout 등의 설정 등을 살펴보자.

추가로 사용하는 JDBC driver의 timeout 설정들도 살펴보자. 커넥션 풀 라이브러리에 설정하면 동일하게 적용이 되는 경우가 많지만 그렇지 않은 경우도 있다. JDBC Postgres의 경우 connection string에서 connectTimeout을 설정할 수 있다.

Failover 테스트 해보기

AWS 문서를 참고하여 실제로 잘 동작하는 지 확인해보자. 반드시 필요한 과정인데 이를 빼먹는 경우가 많다.

닫으며

사실 Java의 DNS 캐시 문제는 Multi-az에 국한된 문제는 아니긴 하다. 많은 서비스들이 고 가용성을 위해 여러 서버로 운영되는건 비일비재하기 때문이다. 그래서 로직 중에 외부 서비스 API를 활용하고 있는 부분이 있으면 잘 돌아가던 서비스가 갑자기 어느 순간 동작이 안되다가, 껐다켜면 마법같이 고쳐지는 문제가 발생하기도 한다. 이런 문제가 너무 잦아서 였을까, 어떤 서비스는 자사의 JAVA SDK에 DNS 캐시를 끄는 기능을 몰래 넣어버리기도 했었다.

프로젝트를 처음에 셋업할 때는 신경쓸 내용들이 한 둘이 아니다. 나중에 확인해야 하고 미뤄두다가 빼먹고 체크 안하는 경우도 비일비재하다. 간만에 시간을 내어 TODO 리스트를 돌이켜보며 내가 빼먹은 부분은 없는지 점검해보자.

BGPworks 는 항상 같이 성장해 나갈 인재를 모집하고 있습니다.

--

--