AWS 기술 블로그

AWS 에 구축하는 클라우드 디자인 패턴 시리즈 1부: 안정성

디자인 패턴은 클라우드 이전부터 객체 지향 설계 등에서 이미 익숙하게 사용했던 용어입니다. 소프트웨어의 설계와 개발, 운영 과정에서 여러가지 시행착오를 겪다보면 많은 부분에서 공통적인 문제가 발생하는 것을 알게 됩니다. 이러한 문제에 대한 해결책으로 재사용이 가능한 솔루션을 정의하게 되는데, 이것이 디자인 패턴입니다. 이는 알고리즘과 같이 코드로 바로 변환이 가능한 형태는 아니지만, 여러가지 구조적인 문제와 복잡한 비즈니스 로직을 보다 쉽게 구현할 수 있는 방식을 설명합니다.

전통적으로 모놀리식 애플리케이션은 단일 프로세스에서 실행되고, 하나의 데이터 저장소를 사용했으며 수직으로 확장가능한 서버에서 실행되었습니다. 하지만 마이크로서비스 애플리케이션은 세분화되고, 네트워크를 통한 서비스 실행, 하나 이상의 데이터 저장소와 수평으로 확장되는 형태를 갖고 있습니다. 요즘과 같이 점점 더 많은 애플리케이션이 마이크로서비스 아키텍처를 사용해 확장성, 민첩성, 안정성 등을 달성하고 있지만 구조의 복잡성이 증가함에 따라 이를 효과적으로 구현하는 어려움도 커지고 있습니다. 여기에서 다양한 디자인 패턴을 활용한다면 이러한 복잡한 로직을 구현하는데 분명 도움이 될 것입니다.

이번 5개의 시리즈로 구성된 블로그를 통해 개발자, 클라우드 아키텍트, 테크 리드와 같은 분들이 참고할 수 있도록 여러가지 디자인 패턴을 well-architected 형태에 기반한 클라우드 아키텍처와 함께 소개합니다. 여러가지 디자인 패턴을 통해 마이크로서비스 아키텍처의 시나리오에 대해 소개하고 각 패턴 별로 관련된 문제와 고려 사항, AWS 에 기반한 아키텍처 등에 관한 설명이 포함됩니다.

AWS 에 구축하는 클라우드 디자인 패턴 시리즈 1부: 안정성
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 2부: 연결성 및 조합
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 3부: 마이그레이션
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 4부: API 관리
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 5부: 데이터 관리

 

(1) 회로 차단기 (Circuit-breaker) 패턴

디자인패턴 개념

회로 차단기 (Circuit breaker) 패턴은 2007년 Michael Nygard 의 도서 Release It! 에서 처음 소개된 디자인 패턴입니다. 이는 전기 회로의 회로 차단기에서 착안한 것으로 외부 API, 서비스, 리소스 등에 관한 호출에 반복적인 실패가 발생할 때 발신자 (Caller) 가 다른 서비스 (Callee) 에 대한 호출의 다시 시도를 방지하는 패턴입니다.


이러한 패턴은 다음 세 가지의 상태를 구현함으로 구성이 가능합니다.

닫힘 (Closed) 호출을 타겟으로 라우팅하는 정상 상태 입니다.
열림 (Open) 장애 상태입니다. 더 이상 요청이 라우팅 되지 않습니다.
반 열림 (Half open) 장애 상태 (Open) 이후 일정 시간이 지난 상황입니다.

일반적으로 회로 차단기 패턴은 이러한 세 가지 상태들이 아래와 같은 동작 방식을 갖습니다.

  1. 시스템이 정상 상태일 때 회로 차단기는 닫힘 상태를 유지합니다.
  2. 실패 임계값 등 지정한 장애 상황이 발생할 경우 열린 상태로 전환됩니다.
  3. 열린 상태에서 일정 시간이 지나면 반 열림 상태로 전환됩니다. 이 때부터 호출이 성공하는지 카운트 합니다.
  4. 연속적으로 호출이 성공하면 다시 닫힘 상태로 되돌아 갑니다. 호출이 실패하면, 다시 열린 상태로 들어갑니다.

회로 차단기 패턴은 재시도 패턴과는 다르게 애플리케이션의 장애를 유발할 수 있는 시도 자체를 방지하는 더 빠르게 실패하는 (Fast fail) 방식을 취하고 있으며, 다음과 같은 이유로 필요합니다.

  • 마이크로서비스에서 하나의 서비스 중단이 전체 애플리케이션의 실패로 이어질 가능성이 있습니다.
  • 장애 상황에서도 발생하는 반복적인 호출은 추가적인 문제를 일으킬 가능성이 있습니다. 예를 들어, 네트워크 경합, DB 스레드 풀 소비, 전체 애플리케이션의 성능 저하 가능성과 같은 것입니다.
  • 성공 가능성이 없는 작업의 재시도는 무의미 합니다. 이는 재시도 패턴과의 차별점 입니다.

적용 대상 및 고려사항

주로 하나의 서비스의 장애가 전체 애플리케이션의 장애로 전파되지 않게 하여 안정성을 높이는 것에 초점을 두게 됩니다. 이러한 방식은 타임 아웃이나 응답을 기다리기 보다는 실패할 가능성이 높은 요청을 빠르게 거부하여 전체 시스템의 응답 시간을 일정하게 유지하는데 도움을 줍니다. 이러한 이유로 다음과 같은 상황에 적용해 볼 수 있습니다.

  • 호출하는 발신자 (Caller) 가 실패할 가능성이 높은 호출을 계속 하는 상황에 적용하면 유리합니다.
  • 타겟이 되는 수신 서비스 (Callee) 의 높은 지연 시간이 서비스 자체의 타임아웃을 유발하는 경우 이를 방지할 수 있습니다.
  • 발신자가 동기호출을 했을 때 수신자에서 높은 지연 시간이 발생하거나 장애 상황인 경우 이 패턴을 적용할 수 있습니다.

반면에 비즈니스 로직의 예외 처리 등에는 이 패턴을 적용하기에 적합하지 않습니다.

회로 차단기 패턴을 구현할 때 고려해야 할 사항은 다음과 같습니다.

  • 독립적으로 구현하여 운영 중인 서비스에 구애받지 않아야 합니다.
  • 수신 서비스 (Callee) 가 주도적으로 회로를 닫아 (Closed) 서비스를 정상화 할 수 있어야 합니다. 이 때, 회복 가능성을 위해 너무 오랜 기간 열림 (Open) 상태를 유지하면 안됩니다. 이는 이슈가 해결되더라도 예외가 발생시킬 수 있습니다. 하지만, 너무 빠르게 반 열림 (Half open) 상태로 전환하게 되면 안됩니다.
  • 어드민이 완전 제어가 가능해야 한다는 점입니다. 실패한 작업의 복구 시간은 가변적일 수 있기 때문에 이를 수동으로 재 설정할 수 있는 옵션이 포함되어야 합니다.
  • 다중 스레드 호출을 주의해야 합니다. 동시 호출이 발생하는 상황에서는 첫번째 호출이 회로를 열어야 (Open) 하고, 이 때부터 타임아웃 값을 설정하는 것이 좋습니다.
  • 회로 차단기에서도 가시성 (Observability) 는 중요합니다. 어드민이 운영 상태를 모니터링 할 수 있어야 하고, 실패한 요청에 대해서 로깅이 되어야 합니다.

하이 레벨 아키텍처

다음의 예시에서 Trip svc 가 발신자 (Caller), Recommendation svc 가 수신자 (Callee) 로 동작합니다.

[1. 마이크로서비스가 정상적으로 동작하는 상태로 회로 차단기는 닫힌 상태 입니다]


[2. 장애 상황시 회로 차단기는 열린 상태로 전환됩니다. 이 때 Recommendation 서비스에 장애가 발생했지만, 회로 차단기가 열린 상태이기 때문에 더 이상 Trip 서비스로부터 요청이 전달되지 않습니다]


[3. 일정 시간이 지난 뒤 반 열림 상태로 전환됩니다. 이 때부터 호출이 성공하는지 카운트 합니다]


[4. 연속적으로 호출이 성공하면 회로 차단기는 닫힘 상태로 전환됩니다. 서비스는 다시 정상화 됩니다]

AWS 기반의 구현

AWS 에서 회로 차단기 패턴을 구현할 때 사용할 수 있는 가장 대표적인 서비스는 시각적 워크플로를 사용하여 분산 애플리케이션과 마이크로서비스의 구성 요소를 손쉽게 조정할 수 있는 완전 관리형 서비스인 AWS Step Functions 서비스입니다. 이를 통해 자동으로 각 단계를 트리거 및 추적하여 회로 차단기의 상태를 손쉽게 구현하고, 전환할 수 있습니다.

실제 AWS 에서의 구현 예제는 다음의 aws-samples 에서 참고할 수 있습니다.

(2) 백오프를 활용한 재시도 (Retry with backoff) 패턴

디자인패턴 개념

분산 환경의 시스템에서는 언제든지 일시적인 오류가 발생할 수 있는데, 일반적으로 이러한 오류는 자동으로 재시도하도록 구성하게 됩니다. 하지만 여기에서 ‘재시도’ 하는 클라이언트는 작업의 성공을 위해 서버 시간을 더 많이 소비하는 경우가 자주 발생합니다. 오류의 종류에 따라 달라지겠지만, 가령 부하 때문에 장애가 발생한 경우는 이러한 재시도가 문제를 크게 악화시킬 수 있습니다. 문제가 해결된 뒤에도 높은 부하가 계속 유지되어 복구에 지연이 발생하게 됩니다.
다양한 재시도 패턴 중 백오프는 Amazon 에서 가장 선호하는 방식입니다. 이는 실패가 발생했을 때 즉각적으로 재시도하기 보다는 재시도 간에 일정한 수준의 대기 시간을 유지하는 방법으로 일시적인 오류로 인해 실패한 작업을 투명하게 재시도하여 애플리케이션의 안정성을 향상 시킬 수 있는 방법입니다. 여기에서 가장 일반적인 패턴은 ‘지수 백오프 (Exponential backoff)’ 로 매 시도 후 대기 시간을 기하급수적으로 증가시키는 방식입니다.

하지만 이 경우에도 그래프와 같이 실패한 호출이 동시에 백오프를 하게 되어 재 시도가 또 다시 경합을 야기합니다. 이에 대해 임의성을 추가하기 위해 다음과 같은 지터를 활용합니다.

sleep = random_between(0, min(cap, base * 2 ** attempt))

그러면 경합 상황이 완화된 위와 같은 시계열 그래프를 얻을 수 있습니다. 재 시도가 초기 급증 이후 일정하게 유지되어 시스템의 안정성이 올라가게 됩니다.

적용 대상 및 고려사항

일반적으로 재 시도를 시도하는 거의 모든 애플리케이션에서 이러한 재시도 패턴을 적용할 수 있습니다.

  • 운영 중인 서비스에서 병목을 방지하기 위해 요청을 제한하거나 429 Too Many Requests 예외가 자주 발생하는 경우에 이러한 재시도 패턴을 적용하면 장애 완화를 기대할 수 있습니다.
  • 분산 아키텍처에서 네트워크 이슈는 잘 드러나지 않는 경우가 많습니다. 일시적인 네트워크 이슈가 전체 시스템의 장애를 유발하는 경우에 이러한 재시도 패턴을 적용하면 안정성이 높아집니다.
  • 요청을 처리해야 하는 서비스가 일시적으로 동작하지 않을 때 장애가 발생한다면, 잦은 재시도가 서비스 성능을 저하시킬 수 있습니다. 이러한 경우에도 백오프를 통한 제한 시간을 도입해야 합니다.

이러한 백오프를 활용한 재시도 패턴을 구현할 때 고려해야할 내용은 다음과 같습니다.

  • 안전한 재시도를 보장하기 위해 멱등성을 고려해야 합니다.
  • 회로 차단기 패턴과 같이 더 빠르게 실패하는 (Fail fast) 시나리오가 더 적합한 경우가 존재합니다.
  • 백오프 비율에 관한 고민이 필요합니다. 이 때 고려해볼만한 것이 앞서 설명한 임의성을 위한 지터입니다.

AWS 기반의 구현

AWS SDK 에서는 이미 지수 백오프 알고리즘을 통한 재시도를 많이 지원하고 있습니다. 이러한 내용은 AWS 의 레퍼런스 가이드에서 확인할 수 있습니다.
하지만 AWS 서비스를 활용해 분산 환경에서 이러한 재시도 패턴을 구현한다면 AWS Step Functions 를 활용해 볼 수 있습니다.

여기에서 다음과 같이 워크플로를 개발해 볼 수 있습니다.

"Book trip": 
{ 
  "Type": "Task", 
  "Resource": "${HotelSvcFunctionArn}", 
 "Retry": [ { "ErrorEquals": [ "States.TaskFailed" ], "MaxAttempts": 2, "IntervalSeconds": 3, "BackoffRate": 1.5 } ], 
  "Next": "Process rewards" 
}

Amazon 에서 실제로 적용 중인 시간 제한, 재시도 및 지터를 사용한 백오프에 관해 더 자세한 내용은 다음의 Amazon Builder’s Library 에서 확인 가능합니다.

마치며

안정성과 관련된 두 가지 디자인 패턴에 관해 살펴보고, AWS 에 구성할 경우 참고해볼 수 있는 내용에 관해 짧게 설명했습니다. 점점 더 복잡해지는 시스템에서 강조되는 것이 안정성이 아닐까 생각됩니다. 위에서 설명해드린 디자인 패턴을 참고하여 여러분의 애플리케이션을 보다 가용성 높게 설계하는데 도움이 되시길 바랍니다.

이번 디자인 패턴에 대한 블로그 포스팅은 총 5개의 시리즈로 구성했습니다.  아래 링크를 통해 확인 하실 수 있습니다.

AWS 에 구축하는 클라우드 디자인 패턴 시리즈 1부: 안정성
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 2부: 연결성 및 조합
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 3부: 마이그레이션
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 4부: API 관리
AWS 에 구축하는 클라우드 디자인 패턴 시리즈 5부: 데이터 관리

Hyobin An

Hyobin An

안효빈 솔루션즈 아키텍트는 2015년부터 AWS 에 합류해 서울 리전 런칭 프로젝트에 참여했습니다. 솔루션즈 아키텍트로 근무하며 스타트업, 금융, 게임과 엔터프라이즈 등 다양한 산업의 고객들이 성공적으로 클라우드에 안정적이고 효율적인 아키텍처를 구성할 수 있게 돕고 있습니다. 특히 데이터 분석과 서버리스 기반의 마이크로서비스 아키텍처, 애플리케이션 현대화, 운영 전략 등에 관한 다양한 프로젝트를 수행하고 있습니다.