소프트웨어 시스템은 네트워크를 통해 다른 시스템에서 다른 프로세스에서 실행되는 소프트웨어에 대한 원격 호출을 수행하는 것이 일반적입니다. 메모리 내 호출과 원격 호출 간의 큰 차이점 중 하나는 원격 호출이 실패하거나 일부 제한 시간 제한에 도달 할 때까지 응답없이 중단 될 수 있다는 것입니다. 더 나쁜 것은 응답 하지 않는 공급 업체에 많은 호출자가 있는 경우 다음 여러 시스템에 걸쳐 계단식 오류로 이어지는 중요 한 리소스를 실행할 수 있습니다. 그의 우수한 책 릴리스 그것에서 마이클 니가르드는 이러한 종류의 치명적인 캐스케이드를 방지하기 위해 회로 차단기 패턴을 대중화했습니다.
회로 차단기의 기본 아이디어는 매우 간단합니다. 회로 차단기 개체에서 보호된 함수 호출을 래핑하여 오류를 모니터링합니다. 오류가 특정 임계값에 도달하면 회로 차단기가 트립되고 회로 차단기에 대한 모든 추가 호출은 보호된 호출이 전혀 수행되지 않고 오류로 반환됩니다. 회로 차단기가 여행하는 경우 일반적으로 당신은 또한 모니터 경고의 어떤 종류를 할 수 있습니다.
다음은 시간 초과로부터 보호하는 루비에서이 동작의 간단한 예입니다.
보호 된 호출 인 블록(람다)으로 차단기를 설정했습니다.
cb = CircuitBreaker.new {|arg| @supplier.func arg}
차단기는 블록을 저장하고,다양한 파라미터(임계값,시간 초과 및 모니터링을 위해)를 초기화하고,차단기를 폐쇄 상태로 재설정한다.
클래스 회로 차단기…
attr_accessor :invocation_timeout, :failure_threshold, :monitor def initialize &block @circuit = block @invocation_timeout = 0.01 @failure_threshold = 5 @monitor = acquire_monitor reset end
회로 차단기를 호출하면 회로가 닫혀 있으면 기본 블록이 호출되지만
# client code aCircuitBreaker.call(5)
클래스 회로 차단기가 열려 있으면 오류가 반환됩니다…
def call args case state when :closed begin do_call args rescue Timeout::Error record_failure raise $! end when :open then raise CircuitBreaker::Open else raise "Unreachable Code" end end def do_call args result = Timeout::timeout(@invocation_timeout) do @circuit.call args end reset return result end
시간 초과가 발생하면 실패 카운터를 늘리고 성공적인 호출은 다시 0 으로 재설정합니다.
클래스 회로 차단기…
def record_failure @failure_count += 1 @monitor.alert(:open_circuit) if :open == state end def reset @failure_count = 0 @monitor.alert :reset_circuit end
고장 횟수를 임계값
클래스 회로 차단기와 비교하여 차단기의 상태를 결정합니다…
def state (@failure_count >= @failure_threshold) ? :open : :closed end
이 간단한 회로 차단기는 회로가 열려있을 때 보호 호출을 피하지만 상황이 다시 잘되면 재설정하려면 외부 개입이 필요합니다. 이것은 건물에 있는 전기 차단기를 가진 적당한 접근이다,그러나 소프트웨어 차단기를 위해 우리는 차단기 자체가 근본적인 외침이 다시 작동하는지 검출해 달라고 할 수 있다. 적절한 간격 후에 보호 된 호출을 다시 시도하고 차단기가 성공하면 차단기를 재설정하여이 자체 재설정 동작을 구현할 수 있습니다.
이 종류의 차단기를 만드는 것은 재설정을 시도하고 마지막 오류 시간을 유지하도록 변수를 설정하기위한 임계 값을 추가하는 것을 의미합니다.
클래스 재설정 회로 차단기…
def initialize &block @circuit = block @invocation_timeout = 0.01 @failure_threshold = 5 @monitor = BreakerMonitor.new @reset_timeout = 0.1 reset end def reset @failure_count = 0 @last_failure_time = nil @monitor.alert :reset_circuit end
이제 세 번째 상태가 있습니다-반 개방-회로가 문제가 해결되었는지 확인하기 위해 실제 통화를 할 준비가되었음을 의미합니다.
클래스 재설정 회로 차단기…
def state case when (@failure_count >= @failure_threshold) && (Time.now - @last_failure_time) > @reset_timeout :half_open when (@failure_count >= @failure_threshold) :open else :closed end end
반 개방 상태에서 전화를 걸도록 요청하면 평가판 호출이 발생합니다.
클래스 재설정 회로 차단기…
def call args case state when :closed, :half_open begin do_call args rescue Timeout::Error record_failure raise $! end when :open raise CircuitBreaker::Open else raise "Unreachable" end end def record_failure @failure_count += 1 @last_failure_time = Time.now @monitor.alert(:open_circuit) if :open == state end
이 예는 간단한 설명 하나,실제로 회로 차단기는 좋은 좀 더 많은 기능과 매개 변수화를 제공합니다. 종종 네트워크 연결 실패와 같이 보호 된 호출이 발생할 수있는 다양한 오류로부터 보호 할 수 있습니다. 모든 오류가 회로를 트립 해야하는 것은 아니며,일부는 정상적인 오류를 반영해야하며 일반 논리의 일부로 처리되어야합니다.
트래픽이 많은 경우 초기 시간 제한을 기다리는 많은 호출에 문제가 발생할 수 있습니다. 원격 호출이 느린 경우가 많으므로 나중에 또는 약속을 사용하여 각 호출을 다른 스레드에 배치하여 결과가 돌아올 때 처리하는 것이 좋습니다. 스레드 풀에서 이러한 스레드를 그리면 스레드 풀이 모두 소모될 때 회로가 중단되도록 정렬할 수 있습니다.
이 예제에서는 차단기를 트립하는 간단한 방법을 보여 줍니다. 좀 더 정교한 접근 방식은 오류의 빈도를 볼 수 있습니다,당신이 일단 트립,말,50%실패율. 또한 다른 오류에 대해 임계값이 다를 수 있습니다(예:제한 시간은 10 이고 연결 실패는 3 입니다).
내가 보여준 예는 동기 호출 용 회로 차단기이지만 회로 차단기는 비동기 통신에도 유용합니다. 여기서 일반적인 방법은 공급 업체가 서버 과부하를 방지하는 데 유용한 기술 인 속도로 소비하는 모든 요청을 큐에 넣는 것입니다. 이 경우 대기열이 채워지면 회로가 끊어집니다.
자체적으로 회로 차단기는 실패 할 가능성이있는 작업에 묶여있는 리소스를 줄이는 데 도움이됩니다. 당신은 클라이언트에 대한 시간 초과에 대기 방지 및 고장 회로는 어려움을 겪고 서버에 부하를 가하고 방지 할 수 있습니다. 나는 회로 차단기에 대한 일반적인 경우 원격 호출에 대해 여기에 이야기,하지만 그들은 당신이 다른 부분에 장애로부터 시스템의 일부를 보호 할 어떤 상황에서 사용할 수 있습니다.
차단기는 감시를 위한 귀중한 장소입니다. 차단기 상태의 모든 변경 사항을 기록해야하며 차단기는 심층 모니터링을 위해 해당 상태의 세부 정보를 표시해야합니다. 차단기 동작은 종종 환경의 더 깊은 문제에 대한 경고의 좋은 원천입니다. 운영 직원은 차단기를 여행하거나 재설정 할 수 있어야합니다.
자체 차단기는 가치가 있지만 이를 사용하는 클라이언트는 차단기 오류에 대응해야 합니다. 모든 원격 호출과 마찬가지로 실패시 수행 할 작업을 고려해야합니다. 그것은 당신이 수행하고있는 작업에 실패합니까,아니면 당신이 할 수있는 해결 방법이 있습니까? 신용 카드 인증은 나중에 처리하기 위해 대기열에 배치 될 수 있으며,일부 데이터를 가져 오지 않으면 표시하기에 충분한 오래된 데이터를 표시하여 완화 할 수 있습니다.
추가 읽기
넷플릭스 테크 블로그에는 많은 서비스를 제공하는 시스템의 신뢰성 향상에 대한 유용한 정보가 많이 포함되어 있습니다. 종속성 명령은 회로 차단기 및 스레드 풀 제한 사용에 대해 설명합니다.
넷플릭스는 오픈 소스 히스테릭스,분산 시스템에 대한 대기 시간 및 내결함성을 처리하기위한 정교한 도구가 있습니다. 그것은 스레드 풀 제한 회로 차단기 패턴의 구현을 포함
루비 회로 차단기 패턴의 다른 오픈 소스 구현이 있습니다,자바,성배 플러그인,씨#,측면,스칼라
감사
파벨 슈팍은 예제 코드
에서 버그를 발견하고 보고했습니다.