[Spring Cloud] - 7. Hystrix๋ฅผ ์ด์šฉํ•œ Circuit Breaker (๊ธฐ๋ณธํŽธ)

๋ฐ˜์‘ํ˜•

์ง€๋‚œ ํฌ์ŠคํŠธ์— ์ด์–ด์„œ Spring Cloud์—์„œ Circuit Breaker๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์ฒซ ๋ฒˆ์งธ ํŒŒํŠธ๋ฅผ ๋“ค์–ด๊ฐ€๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Hystrix

Hystrix๋Š” Spring Cloud ์Šคํƒ์—์„œ ์ œ๊ณตํ•˜๋Š” Circuit Breaker ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. Netflix์—์„œ ๊ฐœ๋ฐœํ–ˆ์œผ๋ฉฐ ํ˜„์žฌ๋Š” Spring Cloud์˜ ํ‘œ์ค€ Circuit Breaker๋กœ ์ž๋ฆฌ ์žก๊ณ  ์žˆ์ฃ .

๊ธฐ๋ณธ์ ์œผ๋กœ Hystrix๋Š” ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ํ˜น์€ ๋ชจ๋ฐ”์ผ์—์„œ ์–ด๋–ค API ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์„œ๋น„์Šค์˜ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”๋ฐ, ์ด ๋•Œ ์„œ๋น„์Šค์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ฑฐ๋‚˜ ์‘๋‹ต์ด ์—†์„ ๊ฒฝ์šฐ, ์ดํ›„ ์ด์šฉ์ž์—๊ฒŒ ์žฅ์• ๊ฐ€ ์ „ํŒŒ๋˜์ง€ ์•Š๊ณ , ๋ฏธ๋ฆฌ ์ •์˜๋œ ์˜ค๋ฅ˜๋ฅผ ๋ธŒ๋ผ์šฐ์ € ํ˜น์€ ๋ชจ๋ฐ”์ผ์—์„œ ์ „์†กํ•˜๊ฒŒ ๋˜์–ด ์˜ค๋ฅ˜ ์ „ํŒŒ๋ฅผ ๋ง‰์•„์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๊ตฌ์ฒด์ ์œผ๋กœ Hystrix๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘์ด ๋˜๋Š” ๊ฒƒ์ผ๊นŒ์š”? 

๋จผ์ € HystrixCommand, HystrixObservableCommand ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , Command๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ, ๊ธฐ์กด์— ์ด๋ฏธ ์š”์ฒญํ•œ ์ ์ด ์žˆ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ์บ์‹œ์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด, ์„œ๋น„์Šค์˜ ๋™์ž‘ ์—ฌ๋ถ€, ์˜ค๋ฅ˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ฒŒ ๋˜๊ณ , ๊ทธ๊ฒƒ์ด ์ •์ƒ์ž„์„ ํ™•์ธํ–ˆ๋‹ค๋ฉด, ์ด์ œ Thread Pool, Queue, Semaphore๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š”๋ฐ, ์ด ๊ณผ์ •์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ, Circuit Breaker ์ธ์Šคํ„ด์Šค์—์„œ๋„ ์ด๋Ÿฌํ•œ ์šด์˜์ฒด์ œ ์ž์›์ด ์—†๋‹ค๋ฉด, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ด ๋ถ€๋ถ„์ด ์ค‘์š”ํ•œ๋ฐ, Spring Application์„ ๊ฐœ๋ฐœํ•˜๊ณ , ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ์ ‘์†ํ•˜๊ฒŒ ๋˜๋ฉด, ์ •ํ•ด์ง„ Thread ์ž์›์„ ๋‹ค ์“ฐ๊ฒŒ ๋˜๋Š” ๋“œ์˜ ๋ฌธ์ œ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ Socket๊ณผ ๊ฐ™์€ ํ†ต์‹ ์˜ ๊ฒฝ์šฐ๋Š” Linux Kernel์— ์˜ํ–ฅ์„ ๋งŽ์ด ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์งˆ์ ์œผ๋กœ ๋งŽ์ด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฏ€๋กœ Hystrix์—์„œ๋„ ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž์› ํ™•๋ณด๊ฐ€ ํ™•์ธ๋˜์—ˆ๋‹ค๋ฉด, API ์„œ๋น„์Šค์— ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๊ฒŒ ๋˜๊ณ , ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด Fallback ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์˜ค๋ฅ˜๋ฅผ ์ „๋‹ฌํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์ „๋‹ฌํ•˜๊ฒŒ ๋˜๋Š” ์—ญํ• ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

How to use

์ด์ œ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ณผํ…๋ฐ, ์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” Zuul Gateway, Eureka ๋“ฑ์˜ ์„œ๋น„์Šค ์—†์ด ๋‹จ์ˆœํžˆ API ์„œ๋น„์Šค๋งŒ ๊ฐ€์ง€๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋จผ์ € Circuit Breaker ์—ญํ• ์„ ํ•ด์ค„ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ณ  ๋‚œ ํ›„, ์•„๋ž˜์˜ ๋””ํŽœ๋˜์‹œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค์‹œ๋‹ค.

implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix")

๊ฐ ๋””ํŽœ๋˜์‹œ๋ฅผ ๊ฐ„๋‹จํžˆ ์„ค๋ช…๋“œ๋ฆฌ์ž๋ฉด, WebFlux๋Š” Spring์—์„œ REST API Client ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ๋ณธ๋ž˜ RestTemplate์ด๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์ง€๋งŒ, ์ด ํฌ์ŠคํŠธ์—์„œ๋Š” WebFlux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Hystrix๊ฐ€ ๋ฐ”๋กœ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  Circuit Breaker์ž…๋‹ˆ๋‹ค.

@EnableHystrix
@SpringBootApplication
class HystrixexampleApplication

fun main(args: Array<String>) {
    runApplication<HystrixexampleApplication>(*args)
}

Application ํด๋ž˜์Šค์— @EnableHystrix ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

/**
 * Created by Neon K.I.D on 3/27/20
 * Blog : https://blog.neonkid.xyz
 * Github : https://github.com/NEONKID
 */
@Service
class MemberResource {
    private var client = WebClient.builder().baseUrl("http://localhost:8080").build()

    @HystrixCommand(commandKey = "getNotes", fallbackMethod = "defaultMembers")
    fun getMembers()
            = client.get().uri("/v1/member/detail").retrieve().bodyToMono(String::class.java).block();

    fun defaultMembers() = "ERROR"
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„์™€ ๊ฐ™์ด ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด, ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €๋‚˜ ๋ชจ๋ฐ”์ผ์—์„œ ํ˜ธ์ถœํ•  API ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. Hystrix๋Š” Java ์ฝ”๋“œ์—์„œ Component, Service๋ฅผ ์ฐพ๊ณ , ๊ทธ ์•ˆ์— ์žˆ๋Š” HystrixCommand ์–ด๋…ธํ…Œ์ด์…˜์— ๋”ฐ๋ผ ๋™์ž‘ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ API ์„œ๋ฒ„์— ์žˆ๋Š” ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜ค๊ณ ์ž ํ•  ๋•Œ๋Š” Component ๋‚ด์ง€ Service ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.

๋Œ€์ถฉ ๋ˆˆ์น˜๋ฅผ ์ฑ„์…จ๊ฒ ์ง€๋งŒ, ๋งŒ์•ฝ Member API์—์„œ Member๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ, ์‹คํŒจํ–ˆ์„ ๊ฒฝ์šฐ, fallbackMethod๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ getMembers ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒ ์ง€๋งŒ, ๋งŒ์•ฝ ์„œํ‚ท์ด Open๋˜์—ˆ๊ฑฐ๋‚˜ ์š”์ฒญ์— ์‹คํŒจํ–ˆ์„ ๊ฒฝ์šฐ, defaultMembers ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

/**
 * Created by Neon K.I.D on 3/28/20
 * Blog : https://blog.neonkid.xyz
 * Github : https://github.com/NEONKID
 */
@RestController
class MemberController {
    @Autowired
    private lateinit var memberResource: MemberResource

    @GetMapping(value = ["/members"])
    fun getMembers() = memberResource.getMembers()
}

๋งˆ์ง€๋ง‰์œผ๋กœ REST API๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.

 

Test

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ์ง€๋‚œ ํฌ์ŠคํŠธ์—์„œ ๋งŒ๋“ค์—ˆ๋˜ Member API ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ , Circuit Breaker๋ฅผ ์‹คํ–‰ํ•ด ๋ด…์‹œ๋‹ค.

๋‘ ์„œ๋น„์Šค ๋ชจ๋‘ ๊ฐ™์€ ๋ช…๋ น์„ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ API ์„œ๋น„์Šค๋ฅผ ํ•œ ๋ฒˆ ์ข…๋ฃŒํ•œ ํ›„, ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋„๋ก ํ•˜์ฃ .

Member API ์„œ๋น„์Šค๋Š” ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง„ ์ƒํƒœ์ด๊ณ , Circuit Breaker๊ฐ€ ์ด์— ๋”ฐ๋ผ ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ERROR๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋งˆ์น˜๋ฉฐ...

์—ฌ๊ธฐ๊นŒ์ง€ Hystrix์˜ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค. ์•„๋งˆ ์‹ค์Šตํ•˜์‹œ๋Š” ๋™์•ˆ ๋งŽ์€ ์˜๋ฌธ์ ์ด ๋“œ์…จ์„ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ „๊นŒ์ง€๋Š” Zuul Gateway๋ฅผ ์ด์šฉํ•ด ๊ฐ๊ฐ ๋–จ์–ด์ง„ API๋“ค์„ ๋ฌถ์–ด์ฃผ๊ณ  ์ด๋ฅผ ๋ง๋ถ™์—ฌ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ๋œ ์ธ์Šคํ„ด์Šค๋“ค์„ Eureka๊ฐ€ ์ฐพ์•„์ฃผ์—ˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์— Circuit Breaker๊นŒ์ง€ ๋ถ™์œผ๋ฉด? ํ ..

์‚ฌ์‹ค ์ €์˜ Spring Cloud์˜ ํฌ์ŠคํŠธ๋Š” Zuul Gateway๊นŒ์ง€๊ฐ€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋กœ ์ง„ํ–‰๋  ์˜ˆ์ •์ด์—ˆ์Šต๋‹ˆ๋‹ค. Circuit Breaker๋Š” ์˜ต์…˜์ธ ํ˜•ํƒœ๋กœ ์ œ๊ณต๋  ์˜ˆ์ •์ด์—ˆ์Šต๋‹ˆ๋‹ค๋งŒ ๊ทธ ์ด์œ ๋Š” Circuit Breaker๋Š” ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์›ํ•œ๋‹ค๋ฉด Circuit Breaker๋ฅผ ์•ž์— ๋ถ™์—ฌ๋†“๊ณ  ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , Zuul Gateway, Riboon ๋“ฑ ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ์™€ ๋ฌถ์–ด์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์™ธ์—๋„ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ํ†ต๊ณ„๋ฅผ ์ง‘๊ณ„ํ•ด์„œ ์‹œ๊ฐํ™” ํ•ด์ฃผ๋Š” ๋Œ€์‹œ๋ณด๋“œ, Hystrix์˜ ํŠœ๋‹ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฒƒ๋“ค์ด ๋งŽ์ด ์žˆ์–ด์„œ Hystrix๋Š” ์‚ฌ์šฉํ•˜๊ธฐ๋„ ๊ทธ๋งŒํผ ์–ด๋ ต๊ณ , ๊นŠ์€ ๋ถ„์•ผ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ธฐ๋ณธํŽธ์—์„œ๋Š” ์ด๋Ÿฐ ์ฒ˜๋ฆฌ๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๊ณ , ๋” ๋‚˜์•„๊ฐ€์„œ๋Š” ๋‚ด ์„œ๋น„์Šค์— ์–ด๋–ค ์‹์œผ๋กœ ์ ์šฉํ•ด์•ผ ํ•  ์ง€๋ฅผ ๊ณ ๋ฏผํ•˜์…”์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ด๋ฏธ์ง€ ์ถœ์ฒ˜

(https://cloud.spring.io/spring-cloud-netflix/multi/multi__circuit_breaker_hystrix_clients.html)

(https://github.com/Netflix/Hystrix/wiki/How-it-Works)

๋ฐ˜์‘ํ˜•
TAGS.

Tistory Comments