실패 사례를 통해 알아본 서킷 브레이커
며칠 전 예상치 못한 문제에 직면했습니다.
좌절감이 크게 밀려왔습니다. 문제를 해결하고 싶었습니다. 호기심 때문에라도 계속 나아갈 수밖에 없었습니다.
다시 한번 문제에 매달렸습니다. 그리고 해결책을 찾아냈습니다. 그것은 바로 서킷 브레이커(circuit breaker)입니다.
소프트웨어에서 서킷 브레이커는 단 한 번의 장애가 전체 시스템을 중단시키는 것을 방지합니다. 집에서 사용하는 차단기(breaker)와 유사한 방식으로 작동합니다.
서킷 브레이커에는 세 가지 상태가 있습니다:
- CLOSED: 모든 것이 정상 작동합니다. 모든 요청이 통과됩니다. 시스템은 실패를 추적합니다. 실패가 한계치에 도달하면 회로가 열립니다.
- OPEN: 시스템이 즉시 모든 요청을 중단합니다. 이는 장애가 발생한 서비스가 복구할 시간을 벌어줍니다.
- HALF_OPEN: 시스템이 몇 개의 테스트 요청을 허용합니다. 요청이 성공하면 회로가 닫히고, 실패하면 회로가 다시 열립니다.
다음은 코드로 구현한 간단한 예시입니다:
export class CircuitBreaker {
constructor(failureThreshold, cooldownMs) {
this.failureThreshold = failureThreshold
this.cooldownMs = cooldownMs
this.state = "CLOSED"
this.failureCount = 0
this.lastFailureTime = null
}
openCircuit() {
this.state = "OPEN"
this.lastFailureTime = Date.now()
}
closeCircuit() {
this.state = "CLOSED"
this.failureCount = 0
this.lastFailureTime = null
}
halfOpenCircuit() {
this.state = "HALF_OPEN"
}
async execute(fn) {
if (this.state === "OPEN") {
const cooldownExpired = Date.now() - this.lastFailureTime >= this.cooldownMs
if (!cooldownExpired) {
throw new Error("Circuit is open.")
}
this.halfOpenCircuit();
}
try {
const result = await fn()
if (this.state === "HALF_OPEN") {
this.closeCircuit()
}
return result;
} catch (error) {
if (this.state === "HALF_OPEN") {
this.openCircuit()
throw error;
}
this.failureCount++
if (this.failureCount >= this.failureThreshold) {
this.openCircuit()
}
throw error
}
}
}
이 메커니즘이 최근 제가 겪은 문제를 해결해 주었습니다. 에러의 범람이 애플리케이션을 마비시키는 것을 막아줍니다.
댓글로 여러분의 생각을 공유해 주세요. 저도 여전히 배우는 중입니다.
Source: https://dev.to/neel-vekariya/circuit-breaker-explained-through-real-failure-experience-3aeg