10분만에 구현하는 CircuitBreaker

2023. 1. 29. 14:00· Spring

Spring AOP를 활용하여 CircuitBreaker를 구현해 보자.

 

Annotation 기반의 AOP를 활용하기 위해 Annotation과 Aspect를 다음과 같이 만들어주자.

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CircuitBreaker {}

 

@Aspect
@Component
public class CircuitBreakerAspect {

    @Around("@annotation(com.ms.circuitbreaker.CircuitBreaker)")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
    	// TODO 세부구현
        return joinPoint.proceed();
    }

}

 

CircuitBreaker를 적용할 코드도 하나 만들자

@Service
public class FooService {

    @CircuitBreaker
    public String getFoo() {
        return "foo";
    }

}

 

실패 개수와 마지막 실패 시간을 가지고 있는 metadata와 Exception을 만들자

class CircuitBreakerMetadata {

        private final AtomicInteger failures = new AtomicInteger();

        private volatile long lastFailure;

        CircuitBreakerMetadata() {
        }

        private long getLastFailure() {
            return this.lastFailure;
        }

        private void setLastFailure(long lastFailure) {
            this.lastFailure = lastFailure;
        }

        private AtomicInteger getFailures() {
            return this.failures;
        }

    }

 

public final class CircuitBreakerOpenException extends RuntimeException {}

 

기본적인 뼈대는 만들어졌다.

이제 CircuitBreaker 동작을 Aspect에서 구현해 보자

 

요구사항은 간단하다.

1. @CircuitBreaker가 선언된 곳에서 에러가 연속으로 5회를 넘게 되면

2. 1초 동안 CircuitBreaker가 발동한다. 

3. 에러 없이 성공하면 실패 개수를 초기화한다. 

 

@Aspect
@Component
public class CircuitBreakerAspect {

    private static final int THRESHOLD = 5;
    
    private static final long HALF_OPEN_AFTER = 1000;
    
    private static final ConcurrentMap<Object, CircuitBreakerMetadata> METADATA_MAP = new ConcurrentHashMap<>();

    @Around("@annotation(com.ms.circuitbreaker.CircuitBreaker)")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {

        final Object target = joinPoint.getTarget();

        CircuitBreakerMetadata metadata = METADATA_MAP.get(target);

        if (metadata == null) {
            METADATA_MAP.putIfAbsent(target, new CircuitBreakerMetadata());
            metadata = METADATA_MAP.get(target);
        }

        if (metadata.getFailures().get() >= THRESHOLD &&
                System.currentTimeMillis() - metadata.getLastFailure() < HALF_OPEN_AFTER) {
            throw new CircuitBreakerOpenException();
        }

        try {
            final Object result = joinPoint.proceed();
            metadata.getFailures().set(0);
            return result;
        } catch (Exception e) {
            metadata.getFailures().incrementAndGet();
            metadata.setLastFailure(System.currentTimeMillis());
            throw e;
        }

    }
}

 

CircuitBrekaer를 구현해 보았다.

Spring에서 제공하는 @CircuitBreaker를 사용하다가 어떻게 구현되어있는지 보니 생각에 비해 간단/간결하게 작성되어 있었다.

사실 위에서 작성한 코드는 spring-integration의 RequestHandlerCircuitBreakerAdvice 클래스이다.

 

프레임워크와 라이브러리가 제공해 준다고 해서 그저 가져다 쓰기보다는 어떻게 구현되었는지 궁금해하고 찾다 보면 더 좋은 개발자가 되리라 생각한다.

저작자표시 비영리 변경금지 (새창열림)

'Spring' 카테고리의 다른 글

Spring Batch 5 뭐가 달라졌나?  (2) 2023.02.19
WebFlux에서 micrometer로 모니터링 데이터 수집하기  (0) 2023.01.11
JPA를 이용하여 cursor 기반 페이징 구현  (4) 2019.12.29
Spring WebFlux는 어떻게 적은 리소스로 많은 트래픽을 감당할까?  (43) 2019.06.22
Spring Cache 구현 원리  (1) 2019.03.24
'Spring' 카테고리의 다른 글
  • Spring Batch 5 뭐가 달라졌나?
  • WebFlux에서 micrometer로 모니터링 데이터 수집하기
  • JPA를 이용하여 cursor 기반 페이징 구현
  • Spring WebFlux는 어떻게 적은 리소스로 많은 트래픽을 감당할까?
AlwaysPr
AlwaysPr
AlwaysPr
민수's 기술 블로그
AlwaysPr
전체
오늘
어제
  • All (38)
    • Programming (8)
    • Java (10)
    • Spring (13)
    • JavaScript (1)
    • Book (1)
    • Seminar (1)
    • Diary (4)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 개발자
  • StepBuilder
  • stringtemplates
  • 자바21
  • nonblocking
  • Reactor
  • lombok.config
  • @EnableBatchProcessing
  • JobBuilder
  • virtual thread
  • Webflux
  • @Cachable
  • 웹플럭스
  • 스프링배치5
  • scopedValue
  • r2dbc
  • 가상스레드
  • java17
  • 고졸개발자
  • structured-concurrency
  • DefaultBatchConfiguration
  • Spring
  • FFM
  • record pattern
  • eventdriven
  • loom project
  • aop
  • Spring batch5
  • Java21
  • 레코드매칭

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.0
AlwaysPr
10분만에 구현하는 CircuitBreaker
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.