>백엔드 개발 >Golang >Go 앱의 회로 차단기

Go 앱의 회로 차단기

王林
王林원래의
2024-09-03 14:15:111064검색

오늘날 우리 애플리케이션은 특히 마이크로서비스 환경에서 작업할 때 몇 가지 종속성을 갖는 것이 일반적입니다. 앱에서 오류를 보고하는 경우가 드물지 않으며 종속성 중 하나가 작동 중지된 것을 발견합니다.

복원력을 향상시키는 좋은 방법 중 하나는 제대로 작동하지 않는 앱과의 통신을 차단하는 것입니다. 다른 분야를 살펴보면서 고장이 나면 스위치가 꺼지는 차단기의 개념을 전기공학에서 배웠습니다. 브라질에서는 모든 집에 전기 네트워크가 불안정해지면 자동으로 꺼지는 스위치가 있습니다.

컴퓨터 과학에서 회로 차단기는 중간 상태도 있기 때문에 좀 더 복잡합니다. 아래 그림은 작동 방식에 대해 자세히 설명합니다.

Circuit Breaker in Go apps

요컨대 가능한 상태는 다음과 같습니다.

  • open: 앱 간 통신이 없습니다. 이 상태에 도달하면 타이머가 시작되어 종속성을 다시 설정할 수 있습니다. 타이머가 끝나면 반오픈으로 이동합니다.
  • 닫힘: 앱 간에 통신이 있습니다. 요청이 실패할 때마다 카운터가 업데이트됩니다. 실패 임계값에 도달하면 회로를 개방으로 이동합니다.
  • 반개방: 평소처럼 일할 수 있을 때까지의 치유 상태입니다. 그 동안 성공 기준점에 도달하면 폐쇄 상태로 이동합니다. 요청이 계속 실패하면 다시 공개 상태로 돌아갑니다.

정말 멋지죠? 개념을 더 잘 설명하기 위해 하나 만들어 보는 것은 어떨까요?

먼저 서비스 A를 구축해 보겠습니다. 이 서비스는 모든 요청을 수신하는 역할을 담당합니다. 즉, 메인 앱이 의존하는 서비스가 됩니다. 단순화하기 위해 항상 200으로 응답하는 /success와 항상 500으로 응답하는 /failure라는 두 개의 엔드포인트를 노출합니다.

package main

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

func main() {
    http.HandleFunc("/success", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusOK) })
    http.HandleFunc("/failure", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusInternalServerError) })

    fmt.Println("Server is running at http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

서비스 B는 서비스 A에 전화를 걸고 회로 차단기를 구축합니다. Go 커뮤니티에는 이미 패턴을 구현하는 lib gobreaker가 있습니다. 먼저 차단기 속성을 정의합니다.

var st gobreaker.Settings
st.Name = "Circuit Breaker PoC"
st.Timeout = time.Second * 5
st.MaxRequests = 2
st.ReadyToTrip = func(counts gobreaker.Counts) bool {
    return counts.ConsecutiveFailures >= 1
}

lib를 통해 더 많은 속성을 사용자 정의할 수 있지만 우리는 다음 세 가지에만 집중할 것입니다.

  • 시간 초과: 열린 상태에 있는 시간입니다. 이 예에서는 5초를 선택합니다.
  • MaxRequests: 종료되기 전에 성공한 요청 수입니다. 이 예에서는 두 가지 요청을 결정했습니다.
  • ReadyToTrip: 닫힌 상태에서 열린 상태로 이동하는 조건을 정의합니다. 단순화하면 한 번의 실패로 충분합니다.

이제 차단기를 초기화하고 요청을 보냅니다.

cb := gobreaker.NewCircuitBreaker[int](st)

url := "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

url = "http://localhost:8080/failure"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // open!

time.Sleep(time.Second * 6)
url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // half-open!

url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

gobreaker가 함수 주위의 래퍼처럼 작동하는 것을 볼 수 있습니다. 함수가 오류를 반환하면 실패 카운터가 증가하고 그렇지 않은 경우 성공 카운터가 증가합니다. 해당 함수를 정의해 보겠습니다.

func Get(url string) (int, error) {
    r, _ := http.Get(url)

    if r.StatusCode != http.StatusOK {
        return r.StatusCode, fmt.Errorf("failed to get %s", url)
    }

    return r.StatusCode, nil
}

이것이 회로 차단기가 있는 Go 앱을 만드는 방법입니다! 이 패턴을 사용하면 종속성으로 인한 오류에 대한 내성을 높여 앱의 복원력을 높일 수 있습니다. 또한 이 lib를 사용하면 대부분의 복잡성이 제거되어 일상적인 앱에서 패턴을 더 쉽게 채택할 수 있습니다. 이번 개념 증명의 코드를 보고 싶다면 여기에서 확인하세요.

다른 탄력성 패턴이 여전히 궁금하시다면 Elton Minetto도 이에 대한 훌륭한 블로그 게시물을 게시했습니다!

이 글과 다른 글은 제 개인 블로그에서도 확인하실 수 있습니다. 이 블로그 게시물에 대한 의견을 댓글로 남겨주시고 질문 하나를 남겨주세요. 이전에 회로 차단기를 사용해 본 적이 있나요?

위 내용은 Go 앱의 회로 차단기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.