MSA 방식의 아키텍쳐를 택한 서비스를 개발하는 중 아래와 같이 다른 MS(Micro Service)를 호출하는 경우는 상당히 많다.
1
2
|
const authService = new AuthService()
authService.login(loginDto)
|
cs |
오류 처리까지 포함한다면 아래와 같은 코드가 작성 될 수 있다.
1
2
3
4
5
6
|
try {
const authService = new AuthService()
authService.login(loginDto)
} catch (err) {
throw new Error("Cannot call rpc");
}
|
cs |
트래픽이 얼마 없는 환경에서는 위 코드는 문제 없이 동작하는 것 처럼 보인다.
하지만, 트래픽이 꽤(추상적이지만..) 발생하고 있는 운영중인 서비스라고 가정을 한다면
로그인 API 호출이 발생할때마다 위 코드는 실행이 될 것이고
Auth서버가 어떠한 이유로(서버 자체의 문제, DB 문제, 또 다른 MS와의 통신 문제 등) 동작을 하지 않아 timeout 이 난다면?
timeout 에러가 발생하기 전까지 우리의 코드는 계속해서 어딘가에 해당 정보들을 저장하고 있을것이다.
메모리, 스레드, DB connection과 같은 자원들을 계속해서 잡아먹고 있을 것이고 결국 Memory가 모자라 이 서버까지 문제가 생길 수 있다.
예외처리를 했기 때문에 문제가 없다고 생각했겠지만, 이러한 코드가 반복되었다면 하나의 MS의 문제가 전체 MSA의 영향을 끼치는 큰 문제가 발생 할 수 있다.(MSA를 사용하는 목적과 크게 부합된다.... 하나의 MS가 죽어도 다른 MS들은 정상적으로 동작하여야 한다!)
회로차단 패턴(Circuit Break Pattern)은 이러한 문제를 방지하기 위한 패턴이다.
즉 실패 할 수 있는(실패의 가능성이 있는) 작업을 반복적으로 실행하지 않도록 하기 위한 패턴이다.
Circuit Break Pattern 이라는 이름이 붙은 이유는 회로도에서 스위치를 이용하여 회로를 차단하는방법과 유사하기 때문이다.
코드로 위와 같은 기능을 구현한다면, 서버가 호출이 가능할 때에는 로직이 실행이 되고 호출이 불가능 할때에는 로직이 실행이 되지 않도록 작성을 하면 된다.
위 이미지에서는 3개의 상태를 이용하여 Circuit Breaker Pattern을 구현하기 위한 다이어그램이다.
Open : API 호출이 불가능한 상태(회로 스위치가 열려 회로가 끊어진 상태)
Closed : API 호출이 가능한 상태(회로 스위치가 닫혀 회로가 연결 된 상태)
Half Open : API 호출이 가능할수도 불가능할수도 있는 상태
세가지 상태로 구분이 된다.
간단한 의사코드를 작성하기에 앞서, 구현을 위한 몇가지 옵션을 정해보자.
1. 3번의 실패가 발생 할 시 회로를 차단하여 API 호출을 하지 않도록 한다.
2. 회로가 Open 상태가 된다면 3분의 시간 후 Half Open상태로 변경한다.
3. Half Open 상태에서 API 호출이 성공한다면 Closed 상태로 변경하고, 실패한다면 다시 3분 동안 Open 상태로 전환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
const status = {
OPEN: 0,
CLOSED: 1,
HALF_OPEN: 2
}
const currentState = status.CLOSED
const halfOpenTime = 0;
const failedCount = 0
function login() {
try {
const authService = new AuthService()
authService.login(loginDto)
} catch (err) {
throw new Error("Cannot call rpc");
}
}
function callCircuitBreakerFn(cb) {
if (currentState === status.CLOSED) {
try {
cb()
} catch (err) {
failedCount++
if(failedCount >= 3) {
currentState = status.OPEN
halfOpenTime = Date.now() + (60 * 3)
}
}
} else {
if (Date.now() >= halfOpenTime) {
currentState = status.HALF_OPEN
}
if (currentState === status.HALF_OPEN) {
try {
cb()
} catch (err) {
currentState = status.OPEN
halfOpenTime = Date.now() + (60 * 3)
}
}
}
}
|
cs |
깔끔하지 않은 의사코드이지만, 대충 이런 형태의 코드가 작성 될 수 있을 것 같다.
실제 서비스에 적용을 한다면 여러개의 MS를 관리하기 위한 Class를 생성해야 할 것이고, 고려해야 할 사항들이 조금 더 생길 것 같다.
실제 서비스에 적용을 해보고 시행착오와 최종 코드등은 이후에 공유해봐야겠다.
참고
https://topswagcode.com/2016/02/07/Circuit-Breaker-Pattern/
'공부 > MSA' 카테고리의 다른 글
[Pattern]Circuit Breaker Pattern - 회로 차단 패턴 Node js 구현 (0) | 2021.08.22 |
---|---|
[Pattern] Monolithic Architecture(모놀리식 아키텍처) (0) | 2021.07.16 |