[Go] gobreaker

sony์—์„œ ๋งŒ๋“  ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค ๊ตฌํ˜„์ฒด๋‹ค. ์ž๊ธฐ๋“ค์ด ์“ฐ๋ ค๊ณ  ๋งŒ๋“ ๊ฑฐ๊ฐ™๋‹ค.
์ •์„์ ์ธ ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค ํŒจํ„ด์„ ๋”ฐ๋ฅธ๋‹ค.
https://blog.naver.com/sssang97/222890127728




์„ค์น˜

์„ค์น˜๋Š” ๊ฐ„๋‹จํ•˜๋‹ค. ๋””ํŽœ๋˜์‹œ๋„ ๋ณ„๊ฑฐ์—†๋‹ค.

go get github.com/sony/gobreaker




๊ธฐ๋ณธ๊ตฌ์„ฑ

์ „์—ญ๋ณ€์ˆ˜๋‚˜ ์ „์—ญ์— ๊ฐ€๊นŒ์šด ๋ผ์ดํ”„ํƒ€์ž„์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋กœ ์„œํ‚ท๋ธŒ๋ ˆ์ด๊ฑฐ ๋ณ€์ˆ˜๋ฅผ ๋‘”๋‹ค.

๊ทธ๋ฆฌ๊ณ  Setting ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์„ค์ •๊ฐ’๋“ค์„ ๋„ฃ๊ณ  ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค.

์„ธํŒ…์—๋Š” ์ด๋Ÿฐ ๊ฐ’๋“ค์ด ์žˆ๋‹ค.

  1. Name์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์„ฑ ์ด๋ฆ„์ด๊ณ .
  2. MaxRequets๋Š” half-open ์ƒํƒœ์ผ๋•Œ ํ•œ๋ฒˆ์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ์š”์ฒญ ์ˆ˜๋‹ค.
  3. Interval์€ close ์ƒํƒœ์—์„œ ๋‚ด๋ถ€ ์นด์šดํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ๊ธฐ๋‹ค. 0์ด๋ฉด ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  4. Timeout์€ ๋ง ๊ทธ๋Œ€๋กœ ํƒ€์ž„์•„์›ƒ ์„ค์ •์ด๋‹ค. ํ•ด๋‹น ์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด half-open ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. 0์ด๋ฉด 60์ดˆ๋‹ค.
  5. ReadyToTrip์€ close ์ƒํƒœ๋กœ ์ง„์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด์ด๋‹ค. ์ € ๋ฐ˜ํ™˜๊ฐ’์ด true๊ฐ€ ๋˜๋ฉด close๊ฐ€ ๋œ๋‹ค.
  6. OnStateChange๋Š” ๊ทธ๋ƒฅ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋ ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค.
  7. IsSuccessful๋Š” ์„ฑ๊ณต ์กฐ๊ฑด์„ ์ง€์ •ํ•œ๋‹ค. error๊ฐ€ ๋ฐ˜ํ™˜๋ ๋•Œ ํŠน์ • ์˜ค๋ฅ˜๋งŒ ์„ฑ๊ณต์œผ๋กœ ๊ฐ„์ฃผํ•ด์•ผ ํ•˜๊ฑฐ๋“  ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์•„๋ž˜๋Š” ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค ๊ธฐ๋ฐ˜์œผ๋กœ Get ์š”์ฒญ์„ ๋‚ ๋ฆฌ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ ์˜ˆ๋‹ค.

๋ณ„๊ฑด ์—†๋‹ค. Execute๋กœ ๊ฐ์‹ธ์„œ ์‹คํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.
์ € ๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ๊ฒŒ ReadyToTrip์œผ๋กœ ๊ฒ€์‚ฌํ•ด์„œ close ์ƒํƒœ๋กœ ์ง„์ž…ํ•˜๊ณ , ๊ทธ๋Ÿฐ ์‹์œผ๋กœ ์ œ์–ด๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.


๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋ƒฅ ์“ฐ๋ฉด ๋œ๋‹ค.


์•„๋ž˜๋Š” ์ „์ฒด ์˜ˆ์ œ ์ฝ”๋“œ๋‹ค.

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/sony/gobreaker"
)

var circuitBreaker *gobreaker.CircuitBreaker

func init() {
	var setting gobreaker.Settings
	setting.Name = "HTTP GET ํ…Œ์ŠคํŠธ"
	setting.ReadyToTrip = func(counts gobreaker.Counts) bool {
		// 3๋ฒˆ ์ด์ƒ ํ˜ธ์ถœ๋˜๊ณ , 60% ์ด์ƒ ์‹คํŒจํ•˜๋ฉด circuit breaker๊ฐ€ ์—ด๋ฆฐ๋‹ค.
		failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
		return counts.Requests >= 3 && failureRatio >= 0.6
	}

	circuitBreaker = gobreaker.NewCircuitBreaker(setting)
}

// Get wraps http.Get in CircuitBreaker.
func Get(url string) ([]byte, error) {
	// ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•œ๋‹ค.
	body, err := circuitBreaker.Execute(func() (interface{}, error) {
		resp, err := http.Get(url)
		if err != nil {
			return nil, err
		}

		defer resp.Body.Close()
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}

		return body, nil
	})
	if err != nil {
		return nil, err
	}

	return body.([]byte), nil
}

func main() {
	body, err := Get("http://www.google.com/robots.txt")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(body))
}


์ฐธ์กฐ
https://github.com/sony/gobreaker