약간씩 눈에 익는 용어들이 생긴다. 일단 끝을 내보기로 한다.
제3법칙 관련
Backpressure(Reactive Streams)는 데이터 스트림에서 수신측에 감당 못할 속도로 데이터가 들어올 때, 송신측에 "천천히 보내!"라고 신호를 보내는 메커니즘이다.
Circuit Breaker는 시스템에 과부하가 걸리면 회로를 차단해 더 큰 피해를 막는 코딩 패턴이다.
논리적 징검다리
용어의 주소를 찾아가는 길에는 논리적 징검다리가 필요하다.
[Backpressure]에 관하여: "속도 조절의 논리"
데이터를 보내는 쪽(송신)과 받는 쪽(수신)의 속도 차이를 해결하는 과정입니다.
step1. 리스트와 반복문(기초): 모든 데이터를 메모리에 다 올려두고 for 문을 돌립니다. 데이터가 작을 땐 문제없지만, 데이터가 무한히 많아지면 메모리가 터져버립니다(논리회로의 오버플로우와 비슷).
step2. 제너레이터와 yield(중급): 데이터를 한꺼번에 만들지 않고, 받는 쪽에서 "다음 데이터 줘!"라고 요청할 때만 하나씩 생성합니다. 이것이 'Pull' 방식의 시작입니다.
step3. 비동기 큐(Queue)와 버퍼(연결고리): 송신측과 수신측 사이에 임시 저장소(버퍼)를 둡니다. 하지만 버퍼도 가득찰 수 있죠. 이때 수신측이 "잠깐, 나 지금 꽉 찼어!"라고 신호를 보내야 합니다.
도착지(Backpressure). 논리회로의 Handshaking과 같습니다. 수신측이 처리 가능한 상태일 때만 Ready 신호를 보내 송신측의 속도를 억제하는 메커니즘입니다.
--> 반복문을 공부할 때, "이 데이터 흐름을 어떻게 제어해야 수신측 회로가 타지 않을까(Backpressure)?라고 상상해보자.
import time
#[기초] 제너레이터(데이터를 하나씩 생성)
def data_sender():
for i in range(1, 11):
print(f"송신측: 데이터 {i}번 전송준비")
yield i
#수신측 (처리 속도가 아주 느림)
def slow_receiver(data):
print(f"수신측: 데이터 {data}번 받는 중...")
time.sleep(1) # 1초 동안 처리 (부하 발생)
print(f"수신측: 데이터 {data}번 처리 완료! 다음 꺼 주세요.")
#[핵심] 수신측이 "준비됐다"고 할 때만 송신측이 데이터를 보냄
sender = data_sender()
for item in sender:
#수신측이 감당할 수 있는 속도로만 루프가 돌아감(Backpressure)
slow_receiver(item)
[Circuit Breaker]에 관하여: "안전 차단의 논리"
문제가 생긴 곳을 격리하여 시스템 전체의 마비를 막는 과정
step1. 예외처리 try-except(기초): 오류가 발생햇을 때 프로그램이 멈추지 않고 다음 코드를 실행하게 합니다(가장 기본적인 방어막)
step2. 조건문을 활용한 상태 관리(중급): 특정 함수가 계속 실패한다면, if문을 사용해 당분간 그 함수를 호출하지 않도록 플래그(Flag)를 세웁니다.
step3. 상태머신(State Machine) 이해(연결고리): 논리 회로에서 배우는 FSM(Finite State Machine) 개념을 적용합니다. 상태를 정상(Closed), 차단(Open), 확인 중(Half-Open)으로 나눕니다.
도착지(Circuit Breaker). 전기회로의 퓨즈와 같음. 과전류(계속된 에럭)가 감지되면 회로를 물리적으로 끊어버리듯, 소프트웨어적으로 해당 경로를 차단해 서버 자원을 보호.
--> 파이썬 교재에서 try-except를 공부할 때, "이게 나중에 시스템 전체를 지키는 Circuit Breaker의 부품이 되겠구나!"라고 생각하자.
#[기초] 예외 처리와 상태 변수 활용
error_count = 0
is_circuit open = False #회로 차단기 상태(False = 정상)
def call server():
#서버 연결 시도 중 에러가 발생했다고 가정
raise Exception("연결 실패")
for i in range(1,6):
print(f"\n[{i}번째 시도]")
if is_circuit_open:
print("X 회로가 차단되었습니다. 요청을 즉시 중단합니다.")
continue
try:
call_server()
except Exception as e:
error_count += 1
print(f"! 에러 발생! (누적: {error_count})")
if error_count >= 3:
is_circuit_open = True #회로를 물리적으로 차단하는 것과 같음
print("위험 감지: 회로 차단기(Circuit Breaker)가 작동합니다.")
용어들이 익숙해지는데 의의를 두자.