13.8 장애 대응(Fault Tolerance) 및 고가용성 보장 체계

13.8 장애 대응(Fault Tolerance) 및 고가용성 보장 체계

로봇의 카메라는 뽑히고, 공장의 와이파이는 끊어지며, 클라우드의 딥러닝 서버는 메모리 누수로 죽는다. 이것이 필드(Field) 다.

이 거대한 분산 파이프라인(Dataflow) 의 중간 허리가 부러졌을 때, 전체 시스템이 어떻게 죽지 않고 버티며 궤멸적 데이터 유실을 막아내는지, 그 피비린내 나는 생존 런북을 해부한다.

1. 런타임 및 데몬 레벨의 헬스 체크 및 장애 감지(Failure Detection)

서버(데몬) 가 통째로 전원이 나갔는지, 아니면 그저 파이프라인 필터 함수(Node) 가 무한 루프에 빠져 대답을 안 하는 건지 어떻게 구분할 것인가?

1.0.1 [인스펙션] 심장 박동(Heartbeat) 의 감시망

1. 데몬 대 데몬 헬스체크

  • zf-daemon 끼리는 Zenoh 코어 라우터를 통해 초당 수십 번씩 “나 아직 살아있다” 는 Liveliness 패킷을 보낸다.
  • 만약 AWS의 데몬이 3초 이상 이 Liveliness 를 쏘지 않으면, 컨트롤러 런타임은 즉각 해당 데몬을 UNREACHABLE (도달 불가) 로 마킹하고 전체 클러스터 경보를 울린다.

2. 데몬 대 노드(스레드) 헬스체크

  • 데몬 내부에서는 스케줄러(Tokio) 가 각 노드의 상태를 감시한다.
  • 만약 특정 C++ 오퍼레이터 안에서 10초 넘게 process() 함수가 반환(Return) 되지 않고 있으면, 데몬은 이것을 “연산 지연” 혹은 “병목/데드락” 으로 간주하고 경고 로그를 띄운다.
  • 즉, 아키텍처 상 데몬과 플러그인 노드는 서로 완벽히 모니터링 체계가 분리되어 있다.

2. 노드 크래시(Crash) 발생 시의 자동 복구(Auto Recovery) 메커니즘

어떤 파이썬 초보 개발자가 배열 인덱스를 잘못 써서 IndexError 를 발생시켰다. 데몬 속의 파이썬 노드는 처참하게 크래시가 났다! 어떻게 살려낼 것인가?

2.0.1 [Runbook] 데몬의 관성적 되살리기(Resurrection) 전술

1. 프로세스 격리 모드의 한계
만약 Node 가 데몬과 완벽히 같은 주소 공간(.so 라이브러리) 을 공유하고 있다면, C 언어의 메모리 예외(Segfault) 는 데몬 전체를 죽여버린다. 이 경우에는 런타임 자체가 날아갔으므로, 리눅스 자체의 systemd (Restrat=always) 데몬 부활 기능에 온전히 의존할 수밖에 없다.

2. 논리적 노드 재시작 런북
컨테이너나 별도 데몬에 할당된 원격 노드가 크래시 되면, 그쪽의 데몬만 죽고 전체 파이프 배관은 살아있다.
이때 원격 데몬이 systemd 로 인해 다시 부팅되어 세상에 나오면?

  • Zenoh-Flow 컨트롤러는 이 데몬이 다시 살아났음을 디스커버리 망(Discovery) 에서 감지한다.
  • 그러고는 곧바로 예전에 갖고 있던 해당 노드의 “YAML 마스터 도면”“런타임 환결 변수(Configuration)” 를 다시 그 데몬의 기억 상실증 걸린 뇌에 강제 주입(Injection) 하여 파이프라인의 명맥을 재건한다.
  • 아키텍트는 가만히 앉아 기다리면 된다.

3. 상태 저장 오퍼레이터(Stateful Operator)를 위한 체크포인팅(Checkpointing)

10시간 동안 누적해서 배터리 통계를 내고 있던 노드가 죽었다 살아나면, 과거 10시간의 합산 데이터가 몽땅 증발(RAM 휘발) 해 버린다.

3.0.1 [Runbook] 내부 지갑 (State) 영속성 결속 전술

비참하지만 Zenoh-Flow 런타임 자체가 아파치 플링크(Apache Flink) 처럼 거대한 분산 스냅샷(Distributed Snapshot / Checkpoint) 기능까지 통째로 완벽하게 챙겨주진 않는다. 이는 극악의 오버헤드를 막기 위한 철학적 결단이다.
그렇다면 아키텍트는 어떻게 상태를 사수해야 하는가?

1. 플러그인 로컬 SQLite 연동

  • 오퍼레이터의 계산(process) 함수가 돌 때, 누적 변수를 매 초마다 단순히 RAM 에만 두지 말고, 당신의 노드 코드 안에서 직접 로컬 SQLite 혹은 RocksDB 에 직렬화(Serialize) 해서 써라.
  • 노드가 크래시 나서 방금 다시 깨어났다면? 노드의 init 자각몽 함수에서 자기 폴더의 로컬 DB 파일을 읽어서 변수 값을 10시간 전의 최신판으로 자기 스스로 복원시켜야 한다.

2. Zenoh Storage 로의 위탁망 사용
상태 값을 로컬 디스크가 아닌 옆구리의 통신 채널로 던진다.
오퍼레이터가 연산을 끝낼 때마다 계산 상태를 파이프라인 링크가 아닌 zenoh.put("state/robot_1/battery", ...) 으로 바깥망 스토리지를 향해 발로 차버린다. 다시 살아나면 zenoh.get 으로 불러온다.

프레임워크가 무거워지는 것을 막기 위해, 데이터플로우 철학과 별개로 “스토리지의 복원은 개발자의 재량” 으로 오롯이 던져 둔 것이 Zenoh-Flow 의 차가운 런북이다.

4. 네트워크 단절 및 파티션(Network Partition) 발생 시의 데이터 유실 방지 설계

로봇이 터널로 진입해서 LTE 통신망이 5분 동안 단절되었다(Network Partition). 클라우드로 올라가야 할 카메라 파이프라인 데이터는 공중에서 증발하는가?

4.0.1 [인스펙션] 오프라인 버퍼링(Buffering) 및 유량 통제 전술

클라우드로 향하던 컨베이어 벨트가 와이파이 단절로 인해 멈췄다면, 로봇쪽 에지(Edge) 데몬 내부에서는 다음과 같은 지옥도가 펼쳐진다.

1. 송신측 데몬 큐(Queue) 폭발 대기

  • 네트워크가 끊기는 즉시 링크 큐의 버퍼율이 무서운 속도로 차오르기 시작한다.
  • 13.7.3 장에서 보았던 백프레셔(Backpressure) 가 작동한다. 데몬은 이 “나갈 구멍 없는 데이터” 때문에 시스템이 터지기 전에, 원본 카메라 노드(Source) 에 “네트워크 단절! 당분간 그림 그리지 마!” 라는 신호를 역류시킨다.

2. 아키텍트의 극복 플랜 (스토어 앤 포워드)
자율주행의 블랙박스는 네트워크가 끊겨도 찍혀야 한다. 백프레셔로 카메라를 멈추게 해선 안 된다.

  • 파이프라인에서 카메라 노드 -> 클라우드 필터 사이에 로컬 저장용 Sink 노드(디스크 기록기) 파이프를 강제로 하나 더 분기(Split) 해두어야 한다!
  • 네트워크 단절 시 클라우드행 파이프는 백프레셔가 걸려서 정지되더라도, 갈라져 있던 로컬 디스크행 파이프는 계속 살아있기 때문에 카메라 영상이 100% 보존된다.
    Zenoh 특유의 선언적 라우팅이 분산 파이프라인 아키텍처에서 얼마나 우아하게 오프라인 내구도(Durability) 를 올릴 수 있는지 보여주는 궁극의 모범답안이다.