[섹션 리포트] Everything fails, all the time : 분산 시스템에서의 내장애성이 있는 설계에 대해

2023.04.24

안녕하세요, CX사업본부 Delivery부 정현재입니다.

도쿄에서는 4/20, 4/21에 AWS Summit Tokyo가 개최되었습니다! AWS 이벤트는 처음 참가했는데, 매우 재밌었고 유익한 경험이었습니다. 이번 블로그에서는「Everything fails, all the time : 분산 시스템에서의 내장애성이 있는 설계에 대해」섹션의 리포트를 쓰려고 합니다.

개요

발표자

小林 芙美님
아마존 웹 서비스 재팬, Global Automotive 사업부 시니어 아키텍처

섹션 개요

시스템은 언제나 고장납니다. 마이크로 서비스와 같은 분산 시스템이나 AWS의 관리형 서비스를 활용한 클라우드 네이티브 시스템은 잘 설계해야 높은 내장애성을 실현할 수 있습니다. 한편, 컴포넌트 간의 연계가 복잡해짐으로서 장애의 원인을 특정하고 거동을 완전히 예측하는 것은 어렵습니다. 이러한 분산 시스템에서 높은 내장애성을 갖춘 시스템을 설계하기 위한 방법을 말씀드리겠습니다.

목차

  1. 왜 마이크로 서비스로 분산하고 싶은가
  2. 분산 시스템에서 자주 일어나는 과제와 해결책
  3. 장애 패턴을 예측하는 것은 가능한가

내용

발표는 전체적으로 여행 예약 애플리케이션을 예로서, 모놀리식 아키텍처와 마이크로 서비스의 비교부터 시작해, 마이크로 서비스에서 발생하는 문제와 해결책에 대해서 알기 쉽게 설명해주셨습니다.

왜 마이크로 서비스로 분산하고 싶은가

모놀리식 아키텍처의 경우

  • 하나의 노드에 복수의 컴포넌트가 존재한다.
  • 하나의 컴포넌트만 스케일 아웃 하고 싶은 경우, 전체 애플리케이션을 스케일 아웃을 할 필요가 있다.
    • 예) 비행기 예약 컴포넌트만 스케일 아웃 하고 싶지만, 전체 애플리케이션을 스케일 아웃 해야한다.
  • 특정 기능을 추가하는 경우, 다른 컴포넌트에 영향이 없다고 할 수 없기 때문에, 전체 애플리케이션에 대해 테스트가 필요하다.
    • 예) 지불 컴포넌트에 추가 기능을 추가하였을 때, 전체 애플리케이션에 대한 리그레이션 테스트를 해야한다.

마이크로 서비스로 분산하였을 경우

  • 각 컴포넌트를 서로다른 노드로 분산한다.
    • 예) 비행기 예약 컴포넌트와 지불 컴포넌트가 다른 노드에 존재한다.
  • 특정 컴포넌트만 스케일 아웃하는 것이 가능하고, 하나의 컴포넌트의 변경이 다른 컴포넌트에 영향을 주지 않는다.

마이크로 서비스의 구성에서 생각해야할 것

  • 분산한 서비스들은 네트워크를 통해 통신을 하기 때문에, 네트워크의 중단이나 트래픽 증가 등의 경우, 장애가 발생할 가능성이 있다.
    • 예)네트워크 불량으로 인해, 지불 서비스와 비행기 예약 서비스 간의 통신이 되지 않아 처리가 정상적으로 되지 않는다.
    • 각 서비스들이 다른 데이터 소스를 사용할 경우, 데이터의 일관성도 보장할 수 없다.
    • 마이크로 서비스가 복잡하게 될 수록, 네트워크로 인한 장애가 발생할 가능성이 높아진다.
  • 장애를 전제로한 설계를 할 필요가 있다.

분산 시스템에서 자주 일어나는 과제와 해결책

일시적인 네트워크 에러로 리퀘스트가 실패하는 경우

  • 자동 재시도 구현
    • 별다른 작업 없이 복구를 할 수 있다.
    • 네트워크의 복구가 늦어질 경우, 반대로 네트워크 부하를 올리는 결과를 초래할 수 있다.
  • 지수 백오프(Exponential Backoff)
    • 첫 1회 실패 시 1초 간격을 두고 재실행, 2회 실패 시 3초 간격을 두고 재실행, 3회 실패 시 6초 간격을 두고 재실행 등과 같은 방식
    • 자동 재시도보다는 서버의 부하를 덜 수 있지만, 역시 여러 요청이 동일한 타이밍에 백오프가 되면 부하가 증가할 수 밖에 없다.
  • 지터(Jitter)
    • 각각 요청 별로 재시도를 하는 간격을 랜덤으로 지정
    • 요청이 동일한 타이밍에 백오프 되는 것을 줄일 수 있다.

원인 불명의 문제로 인해, 특정 서비스에 지속적인 장애가 발생하고 있는 경우

  • 처리가 끝날 때까지 대기
    • 대기 시간 동안 복구가 되지 않을 경우, 긴 시간 대기를 하였는데도 불구하고 타임 아웃으로 인해 실패한다.
    • 서비스가 복구 중에 있을 때에도 계속하여 부하가 늘어난다.
  • 서킷 브레이커 패턴
    • 요청하려는 서비스에 장애가 발생하고 있는 경우, 호출을 중지한다.
      • 예) 지불 서비스와 비행기 예약 서비스 간의 요청을 서킷 브레이커 패턴으로 구현하여, 지불 서비스에 장애가 발생하고 있는 경우, 지불 서비스로의 요청을 중단한다.
    • 서킷 브레이커의 상태에는 크게 이하의 상태가 있다.
      • Closed : 정상상태
      • Open : 장애 발생
    • 구현 방법
      • Hystrix와 같은 라이브러리를 이용하여 애플리케이션 측에서 구현
      • AWS App Mesh과 같은 서비스를 이용하여 구현
      • AWS Step Functions와 같은 워크 플로우 관리 툴로 구현
    • AWS Step Functions로의 구현 예
      • 각 서비스의 장애 상태에 대해서는 DynamoDB에서 관리한다. DynamoDB에는 서비스 종류, 호출을 정지하는 기간, 서킷 상태 등이 담긴 아이템을 관리한다. 해당 서비스에 대한 아이템이 존재하고, 호출을 정지하는 기간 이내일 경우를 상태 이상으로 판단한다.
      • 서비스에서 요청 처리 시, DynamoDB를 참조하여 아이템이 없는 경우, 정상 상태(Closed)로 판단하여 다음 람다를 호출하여 처리를 진행한다.
      • 다음 람다에서 DynamoDB를 참조하여 해당 서비스의 아이템이 존재하고 Open 상태라면 바로 그 시점에서 호출을 정지한다.
      • 만약, DynamoDB에 아이템은 없지만 실패를 하게 된다면, DynamoDB에 아이템을 생성한 후, 호출을 정지한다.
      • 각각의 아이템은 TTL(Time To Live)을 설정해, 호출을 정지하는 기간이 지나고 복구 되었을 경우 삭제하도록 한다.

데이터 소스가 분산되어있을 경우

  • 폴리글랏 퍼시스턴스(Polyglot Persistence)
    • 서비스 별로 각각 다른 데이터베이스를 사용하는 것을 말함.
      • 예) 비행기 예약 서비스는 MySQL을 사용하고 호텔 예약은 DynamoDB를 사용.
    • 이 경우, 서비스 간의 처리가 실패하였을 경우, 데이터의 일관성을 유지하기 어렵다.
      • 예) 비행기 예약, 호텔 예약의 처리는 성공했지만 마지막 순서인 지불 처리가 실패한 경우.
  • Saga 패턴을 사용하여 분산 트랜잭션 관리
    • 일련의 처리 과정 중, 하나의 서비스에서 처리에 실패한 경우, 그 전의 성공한 처리들을 취하하여 데이터의 일관성을 유지한다.

장애 패턴을 예측하는 것은 가능한가

마이크로 서비스의 경우 각 서비스의 변경이 빈번하게 일어나고 호출 순서나 패턴이 다양하기 때문에, 어떤 시점에서 시스템 전체에 대한 스냅샷을 찍는 것이 매우 어렵다. 만약 한 AZ(Availability Zone)에서 장애가 발생한 경우 비지니스 적으로 시스템 전체의 정상상태를 지킬 수 있어야한다.

  • 카오스 엔지니어링
    • 실제 프로덕션 환경에 장애를 일으켜 장애 패턴에 대해 상정대로 움직이고 있는가를 체크하는 방식.
    • 발견하지 못했던 숨겨진 문제점을 발견하는 것이 가능. 다른 서비스의 구성이 어떻게 되어 있는지 모르기 때문에, 다른 서비스에 문제가 있는지 테스트하는 것이 가능하다.
    • 가시화 되어 있지 않은 메트릭스나 로그를 발견하는 것이 가능.
    • 내결함성 및 성능 향상으로도 이어진다.
    • 하지만, 프로덕션에서의 테스트이기 때문에 막무가내로 하는 것은 위험하다. 이상적인 페이즈가 정의 되어 있다.
      • 정의 : 정상 상태에 대해 정의한다.
      • 가설 : 동작에 대한 가설을 세운다.
      • 실험 : 여러가지 변수들을 적용하여 실험한다.
      • 검증 : 세운 가설과 동일한 동작을 하는지 검증한다.
      • 개선 : 테스트를 통해 발견한 문제점을 개선한다.
    • 카오스 엔지니어링의 과제
      • 툴마다 대응하는 플랫폼이나 언어가 다르기 때문에, 복수의 툴을 사용하거나 스스로 스크립트를 만들어야 한다.
      • 프로덕션 환경에 영향을 주지 않고 실행하는 것이 어렵다.
      • AWS Fault Injection Simulator를 사용하여 안전히 테스트 하는 것이 가능. AWS의 여러가지 서비스에 대해 장애를 투입하여 실험할 수 있는 관리형 서비스로, 테스트 중 문제 발생 시 테스트를 중지시켜 영향을 최소화 할 수 있다.

감상

이번 블로그에서는 간단히 「Everything fails, all the time : 분산 시스템에서의 내장애성이 있는 설계에 대해」섹션의 내용을 정리해보았습니다. 이 섹션에서는 마이크로 서비스에서의 장애 패턴과 각 패턴에 대한 해결 방법, 장애의 예측 방법 등에 대해서 설명해주셨습니다. 섹션을 듣기 전까지는 지수 백오프 정도의 장애 대응 수법 밖에 이해하고 있지 못했지만 서킷 브레이커 패턴, Saga 패턴 등등 여러 가지 수법에 대해서 새롭게 알 수 있게 되었습니다. 최근 마이크로 서비스로 구축되는 애플리케이션이 점점 증가하고 있다고 생각하는데, 애플리케이션 구축 시, 이런 장애 대응에 대해서도 깊게 고민하고 구현을 해야할 필요가 있다고 느꼈습니다.

실제 발표에서는 여러가지 구성도와 그림을 이용하여 정말 알기 쉽게 설명을 해주셨기 때문에, 관심이 있으신 분들은 섹션의 동영상이 공개 되면 꼭 시청해주세요! AWS Summit Tokyo 홈페이지에서 온디맨드 신청을 통해 시청하실 수 있습니다.

그럼, 섹션을 발표해주신 小林 芙美님께 감사의 인사를 올리며 블로그를 마무리 하도록 하겠습니다.