개발

Scale-out 할 때 쓸만한 여러 컴포넌트들

우리로 2022. 4. 20. 17:37

https://medium.com/everything-full-stack/design-patterns-and-principles-that-support-large-scale-systems-f3c9adf89ad

 

Design Patterns and Principles That Support Large Scale Systems

Today even small startups may have to work with terabytes of data or build services that support hundreds of thousands of events per minute…

medium.com

 

이 분이 쓴 다른 글들도 참 좋다. 읽어봄직한듯!

 

Large-Scale 시스템을 다룰 때 주로 보게 되는 세가지는 다음과 같다.

  • Availabilty(가용성) : 유저가 사용가능해야한다. 
  • Performance(성능) : 빠른 시간 내에 결과를 확인할 수 있어야 한다. 접속 후 1분동안 화면이 안보이면 유저는 다 떠난다!
  • Reliabilty(신뢰성) : 데이터를 정확하게 처리하고 결과도 알맞게 줘야한다. 내가 1+1 을 입력했는데 결과가 3이 나오는 계산기를 쓸 사람은 없다.

결국 '사용 가능해야하고 기대한 대로 동작하면서 빨라야 한다.'로 축약된다. 이것만 잘 지켜줘도 굉장히 훌륭한 시스템이다.

 

간단하게 장비의 성능을 높이는 방법도 있지만, 이건 한계가 있다. 그래서 Scale-Out 이 필요하다. 

 

Idempotence(멱등성)

멱등성은 수학에서 f(f(x)) = f(x) 와 같다. 우리가 x라는 변수에 대해 f 라는 함수를 몇번이나 곱하더라도 같은 결과가 나오는 함수의 속성이다. 예를 들면 f(x) = x 라는 함수가 있으면 함수를 몇번이나 곱해도 같은 결과를 보장한다.

이 속성이 만족되면 요청이 실패했더라도 부가작업없이 같은 요청을 (안심하고) 다시 보낼 수 있다.

 

게다가 큰 규모의 작업을 잘게 쪼개서 병렬로 실행할 때도 도움이 된다. 쪼개진 작업 중 일부가 실패했더라도 다른 성공한 작업은 멱등성을 만족할 것이므로 실패한 작업만 다시 시행해도 된다.

 

Embracing Async(비동기 도입)

동기 작업은 이전 작업이 끝나야만 그 다음 작업을 할 수 있다. 만약 선행 작업이 오랜 시간동안 끝나지 않는다면 후행 작업은 무한히 기다려야 하는 문제가 있다. 

비동기적 동작을 도입하면 시스템 리소스를 절약하고 더 높은 퍼포먼스를 보일 수 있다.

 

HealthCheck(헬스체크)

MSA 구조에서 많이 등장한다. 각 서비스는 /health 와 같은 헬스체크 API 를 열어두고 이 API를 이용해서 주기적으로 서비스가 살아있는지 확인한다. 만약 Health Check 에 실패한다면 해당 서비스가 장애인 것으로 판명해서 빠르게 알람을 전송해서 장애를 해결할 수 있다.

 

Circuit Breaker

하나의 컴포넌트가 죽더라도 이 컴포넌트와 다른 서비스의 연결을 끊음으로써 다른 컴포넌트가 영향을 받지않도록 한다. 이를 통해 장애의 영향을 최소화할 수 있다. fail-fast 라는 철학에 기반을 두고있고 Neftlix 의 Hystrix 가 그 예시이다.

 

과도한 전류가 흐르면 차단기가 내려가면서 더 큰 사고를 막는 것과 같은 원리다.  

 

Kill Switch / Feature Flag

특정 기능을 배포했을 때 장애가 발생할 경우 대처하기 위한 방법이다. 배포한 기능을 빠르게 Off로 전환함으로써 장애로 인해 UX 가 훼손되는 걸 방지한다. 

 

Bulkhead

Bulkhead 는 격벽이라는 뜻이다.

배의 특정 부분이 침수가 되더라도 다른 부분은 침수가 되지않게 배의 밑판은 격벽으로 구획이 나뉘어진다. 그래서 한 곳이 침수되더라도 다른 곳으로 전파되지않기 때문에 배는 침몰하지 않는다. 

예를 들면 Thread Pool 을 서비스마다 나눔으로써 장애 영향도를 최소화 한다. 또 서비스마다 다른 DB 를 연결하는 것도 Bulkhead 의 한 형태라 볼 수 있다.

 

Service Discovery(Service Registry)

MSA 구성으로 시스템이 운용될 때 어떤 서비스/Pod/instance 가 구동 중인지 파악하기 힘들 때가 있다. 이 때 Service Discovery 가 도움이 된다. 서비스 A가 서비스 B로 요청을 보낼 때 서비스 B가 어떤 Pod/Instace 에서 구동중인지 파악해서 요청을 라우팅할 수 있다.

 

Timeouts, Sleep & Retries

네트워크 상황에 따라, 혹은 서비스의 상태에 따라 요청은 언제든지 실패할 수 있다. 이 때 명시적인 500 에러를 리턴받지 못했다고해서 계속 응답을 기다린다면 리소스 낭비도 심하고 퍼포먼스도 굉장히 안좋아진다. 그래서 얼마간의 시간이 지나면 자동으로 요청이 실패한 것으로 처리되는데 이를 TimeOut이라 한다.

요청이 실패된 뒤 보통 다시 요청을 보내는데 만약 실패하자마자 요청을 보낸다면 Retry Strom 이 몰아칠 확률이 크다. 그래서 exponential backoff 를 활용해서 재시도 주기를 조절한다.

 

Fallbacks

Plan "B" 를 의미한다. 당초 예상했던 시나리오대로 시스템이 운영되지 않을 때, 어떻게 할 것인지를 생각해둬야한다. 서킷 브레이커도 Fallback 의 일종으로 볼 수 있다.

 

Metrics, Monitoring & Alarms

대용량 시스템의 경우 장애를 100% 피하려 하지말고, 어떻게 장애를 대응할지 고민하는게 낫다. 장애가 1000만 요청 당 1번만 발생한다고 치더라도 대용량 시스템에서는 빈번하게 발생하는 꼴이기 때문이다.

 

장애 대응을 위해 필요한게 Metric, Monitoring, Alarm 이다.

 

구글은 네 개의 메트릭을 Golden Signals 로 정의했다. 이것만 있으면 괜찮다! 이런 건 아니고, 어떤 메트릭을 더 넣을지는 시스템 성격에 따라 다르기 때문에 이건 알아서(?) 넣으면 된다. 위 글에서는 메트릭을 세 개의 카테고리로 분류한다.

  • Business Metrics : 비즈니스 맥락(Context)에서 필요한 메트릭이다. 예를 들면 주문 입력, 취소 메트릭 등.
  • Infrastructure Metrics : CPU / 메모리 등 인프라에 관련된 메트릭이다. 
  • Feature Metrics : 특정 피처에 대한 메트릭이다. 예를 들면 A/B 테스트 결과를 확인하기 위한 메트릭 등

 

Rate Limiting ( throttling )

진입되는 트래픽량을 조절함으로써 시스템 부하를 줄일 수 있다. 세 가지 유형이 있다.

 

BackPressure ( 배압 )

Upstream 서비스에서 현재 서비스가 감당할 수 있는 양보다 더 많은 트래픽이 올 경우 사용할 수 있는 방법이다. Upstream 쪽에 "나는 OOO 정도만 받아낼 수 있어."라고 얘기해서 Upstream 쪽의 트래픽을 조절한다. 

 

Http Status Code 중에 429번이 있다. "too many requests" 라는 의미를 지니고 있고 "Retry-After" 헤더에 값을 넣어서 요청을 보낸 클라이언트가 몇 초 뒤에 요청을 보내야할 지 명시할 수 있다. 

 

위 글에서는 backpressure 에 대해서 이 링크를 참고차 알려준다. 

https://www.infoq.com/news/2019/10/reactiveconf-2019-backpressure/

 

Four Strategies to Handle Backpressure - Jay Phelps at ReactiveConf 2019

Jay Phelps, RxJS core team member, recently presented at ReactiveConf 2019 in Prague what backpressure really is, when it happens, and the strategies which can be applied to deal with it.

www.infoq.com

 

Canary release

예전에 탄광에서는 카나리새를 통해 탄광에 진입가능한지 파악했다고 한다.(불쌍한 카나리아 ㅠㅠㅠ) 마찬가지로 몇몇 서비스부터 먼저 릴리즈를 해서 현재 배포본이 문제가 있을지 없을지 파악한다.

이를 위해선 카나리 인스턴스를 다른 인스턴스와 분리해서 모니터링 가능해야한다. 

 

이외에도 다양한 방법이 있다. MSA 로 서비스를 구성하는 곳이 많아지는 느낌이라 더 열심히 공부해야겠다!