일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- aws
- AWS EKS
- kotlin
- MySQL
- 정보처리기사실기 기출문제
- PETERICA
- mysql 튜닝
- CKA 기출문제
- 정보처리기사 실기
- Linux
- CKA
- 정보처리기사 실기 기출문제
- 기록으로 실력을 쌓자
- Java
- 티스토리챌린지
- kotlin coroutine
- CloudWatch
- Elasticsearch
- Spring
- 코틀린 코루틴의 정석
- minikube
- AI
- Pinpoint
- IntelliJ
- Kubernetes
- kotlin querydsl
- 공부
- kotlin spring
- APM
- 오블완
- Today
- Total
피터의 개발이야기
[Kotlin] Resilience4j로 서킷브레이커 패턴 구현하기 본문
ㅁ 들어가며
Resilience4j는 마이크로서비스 아키텍처에서 내결함성을 제공하는 라이브러리로, 서킷브레이커 패턴을 쉽게 구현할 수 있게 도와준다.
여기서는 Resilience4j를 사용하여 서킷브레이커 패턴을 구현하는 방법을 예제 코드와 함께 설명한다.
ㅁ 서킷브레이커 패턴이란?
ㅇ 서킷브레이커 패턴은 시스템의 일부에서 장애가 발생했을 때, 그 장애가 전체 시스템으로 확산되는 것을 방지하기 위한 패턴이다.
ㅁ 서킷브레이커의 세 가지 상태
ㅇ 닫힘(CLOSED): 정상 상태로, 모든 요청이 통과한다.
ㅇ 열림(OPEN): 장애 상태로, 모든 요청이 즉시 실패한다.
ㅇ 반개방(HALF-OPEN): 테스트 상태로, 일부 요청만 통과하여 성공 여부를 확인한다.
ㅁ Resilience4j 설정
dependencies {
implementation("io.github.resilience4j:resilience4j-circuitbreaker:2.0.0")
}
ㅇ build.gradle.kts에 Resilience4j 의존성을 추가
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Duration
@Configuration
class CircuitBreakerConfiguration {
@Bean
fun circuitBreakerRegistry(): CircuitBreakerRegistry {
return CircuitBreakerRegistry.of(configurationCircuitBreaker())
}
private fun configurationCircuitBreaker(): CircuitBreakerConfig {
return CircuitBreakerConfig.custom()
.failureRateThreshold(40) // 실패율 임계값
.waitDurationInOpenState(Duration.ofMillis(10000)) // Open -> Half-Open으로 전환되기 전 대기 시간
.permittedNumberOfCallsInHalfOpenState(3) // Half-Open 상태에서 허용되는 호출 수
.slidingWindowSize(10) // 슬라이딩 윈도우 크기
.recordExceptions(RuntimeException::class.java) // 실패로 기록될 예외 목록
.build()
}
}
ㅇ CircuitBreakerConfiguration.kt 서킷브레이커 설정
ㅁ 서킷브레이커 사용
import io.github.resilience4j.circuitbreaker.CircuitBreaker
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
import io.github.resilience4j.circuitbreaker.CallNotPermittedException
import io.vavr.control.Try
import org.springframework.stereotype.Service
import java.util.function.Supplier
@Service
class CallAServerService(
private val apiClient: CallSomeApiClient,
private val circuitBreakerRegistry: CircuitBreakerRegistry
) {
fun callAServer(): String? {
val circuitBreaker = circuitBreakerRegistry.circuitBreaker("callA")
val decorateSupplier: Supplier<String> = CircuitBreaker.decorateSupplier(circuitBreaker) {
apiClient.callAServerApi()
}
return try {
Try.ofSupplier(decorateSupplier)
.recover { throwable -> callFallback() }
.get()
} catch (e: CallNotPermittedException) {
"Service is blocked because CircuitBreaker blocked this request"
} catch (e: Exception) {
"Unknown exception occurred"
}
}
private fun callFallback(): String {
return "Fallback method running"
}
}
ㅇ 서킷브레이커를 사용하여 API 호출을 감싸는 CallAServerService 클래스를 작성한다.
ㅁ API 클라이언트
import org.springframework.stereotype.Component
@Component
class CallSomeApiClient {
fun callAServerApi(): String {
// 실제 API 호출 로직
return "API response"
}
}
ㅇ API 호출을 담당하는 CallSomeApiClient 인터페이스를 정의한다.
ㅁ 테스트 코드
import io.github.resilience4j.circuitbreaker.CircuitBreaker
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.mockito.Mockito.*
class CallAServerServiceTest {
private val apiClientMock = mock(CallSomeApiClient::class.java)
private val circuitBreakerRegistryMock = mock(CircuitBreakerRegistry::class.java)
private val circuitBreakerMock = mock(CircuitBreaker::class.java)
private val callAServerService = CallAServerService(apiClientMock, circuitBreakerRegistryMock)
@Test
fun `반개방 상태 테스트`() {
`when`(circuitBreakerRegistryMock.circuitBreaker(anyString())).thenReturn(circuitBreakerMock)
`when`(apiClientMock.callAServerApi()).thenThrow(RuntimeException::class.java)
for (i in 1..5) {
callAServerService.callAServer()
}
Thread.sleep(1000)
assertEquals(CircuitBreaker.State.HALF_OPEN, circuitBreakerMock.state)
}
}
ㅇ 서킷브레이커의 상태 변화를 테스트하는 코드를 작성한다.
ㅇ 이 테스트 코드는 서킷브레이커가 반개방 상태로 전환되는지 확인한다.
ㅁ 마무리
ㅇ Resilience4j를 사용하면 서킷브레이커 패턴을 쉽게 구현할 수 있다.
ㅇ 이를 통해 시스템의 내결함성을 높이고, 장애가 발생했을 때 전체 시스템으로 확산되는 것을 방지할 수 있다.
ㅁ 함께 보면 좋은 사이트
ㅇ resilience4j 로 알아보는 서킷브레이커패턴(CircuitBreaker)
ㅇ Protecting your Kotlin microservices with Circuit Breaker pattern
'Programming > Kotlin' 카테고리의 다른 글
[Kotlin] QueryDSL와 MapStruct를 사용하여 DTO에서 필요한 부분만 업데이트하기 (0) | 2024.07.27 |
---|---|
[Kotlin] Kotlin의 스프레드 연산자 (Spread Operator) 이해하기 (0) | 2024.07.26 |
[Kotlin] Kotlin Spring에서 API 요청 시 응답 후 비동기 처리, 코루틴 비동기처리 (0) | 2024.07.23 |
[Kotlin] Entity list에서 id 추출하기 (0) | 2024.07.22 |
[Kotlin] QueryDSL java.lang.NoSuchFieldError: TREATED_PATH (0) | 2024.07.20 |