4.9 클러스터링(Clustering) 및 고가용성(High Availability)

4.9 클러스터링(Clustering) 및 고가용성(High Availability)

단 하나의 Zenoh(제노) 라우터에 기업의 모든 센서와 액추에이터 데이터를 의존하는 것은 자살 행위나 다름없다. 라우터가 구동 중인 서버의 전원이 나가거나, 네트워크 스위치가 고장 나거나, 혹은 예기치 못한 OOM(Out of Memory)으로 프로세스가 죽는 순간 전체 시스템은 마비(Downtime)된다.

현대의 무중단(Zero-downtime) 인프라 아키텍처에서 고가용성(High Availability, HA)은 필수 불가결한 요소다. Zenoh는 탈중앙화된 P2P 철학을 기반으로 설계되었기 때문에, 약간의 토폴로지 튜닝과 클라이언트 설정만 더해주면 값비싼 L4 스위치(Load Balancer) 없이도 뛰어난 클러스터링 효과를 거둘 수 있다.

이 장에서는 어떠한 단일 장애점(SPOF, Single Point of Failure)도 허용하지 않는 견고한 Zenoh 네트워크를 구성하는 전략을 다룬다.

  • SPOF 회피 다중 라우터 (4.9.1): 네트워크의 척추인 라우터를 여러 대 병렬로 띄우고 그물망(Mesh)으로 엮어내어 1대가 죽어도 끄떡없는 백본망 설계법을 배운다.
  • 스플릿 브레인(Split-brain) 방어 (4.9.2): 네트워크 단선으로 인해 라우터 클러스터가 두 동강 났을 때 발생하는 뇌사 상태를 이해하고, Zenoh의 최적 경로 라우팅이 이를 어떻게 우회하는지 살펴본다.
  • 재접속 및 백오프(Backoff) 전략 (4.9.3): 클라이언트가 기존 라우터와의 연결을 잃었을 때 다른 생존 라우터로 신속하게 갈아타는 멀티 호밍(Multi-homing) 설정과 지수적 재접속 지연(Exponential Backoff) 기법을 알아본다.
  • 로드 밸런싱 및 분산 (4.9.4): 몰려드는 퍼블리셔(Publisher)의 데이터 트래픽을 여러 라우터가 똑똑하게 나누어 처리함으로써 병목 현상을 해소하는 트래픽 분산 메커니즘을 파헤친다.

1. 다중 라우터(Multi-router) 배포를 통한 단일 장애점(SPOF) 제거

엔터프라이즈 레벨의 생산 라인이나 글로벌 서비스에서 가장 경계해야 할 단어가 바로 단일 장애점(Single Point of Failure, SPOF)이다. Zenoh(제노) 라우터를 데이터 센터에 한 대만 달랑 띄워두고 수만 대의 센서 클라이언트를 연동하는 이른바 단순 스타(Star) 토폴로지(4.6.2절 참고)는, 라우터 하나가 죽으면 전체 통신망이 즉사하는 최악의 아키텍처다.

시스템 아키텍트는 필연적으로 라우터 노드를 2대, 혹은 그 이상으로 복제(Replication)하여 배치하는 클러스터링(Clustering)을 고민해야 한다.

1.1 다중 라우터 메쉬(Mesh) 구성

가장 기본적이고 강력한 SPOF 회피 구성은 최소 2대 이상의 라우터를 서로 가로질러 연결하는 **완전 연결망(Clique 또는 Mesh)**을 만드는 것이다.

  • 동작 원리: 클라우드 인스턴스 A와 B에 각각 Router-1Router-2를 띄운다. 그리고 각 라우터의 설정 파일(zenoh.json5)에 상대방을 정적 연결(connect) 파라미터로 명시해 두면, 두 라우터는 하나의 커다란 척추(Backbone)처럼 맞물려 동작하기 시작한다.
  • 장애 무효화: 에지 노드(Publisher)는 Router-1에 데이터를 밀어 넣고, 관제 모니터링 서버(Subscriber)는 Router-2에 붙어있더라도 Zenoh의 코어 라우팅 엔진이 둘 사이의 최적의 길을 찾아내어 데이터를 전달한다. 만약 클라이언트가 양쪽 라우터 정보를 모두 알고 있다면(4.9.3절 참고), Router-1의 하드웨어가 타버려도 클라이언트는 즉시 Router-2로 선을 갈아타며 통신 단절(Downtime)을 제로(0)에 가깝게 방어해 낸다.

1.2 브로커리스(Broker-less) 아키텍처의 강점 활용

기존의 MQTT 미들웨어였다면 브로커(Broker)를 다중화하기 위해 Keepalived를 설정하고, 스토리지를 클러스터링하며, Primary-Secondary의 리더 선출(Leader Election) 합의 알고리즘 때문에 허리가 휘었을 것이다.

하지만 Zenoh 라우터는 데이터를 쥐고 있는 마스터(Master)나 상태를 동기화해야 하는 리더(Leader) 노드라는 개념 자체가 애초에 존재하지 않는다. 흘러가는 찰나의 데이터만 중계하는 Stateless한 릴레이(Relay)에 불과하므로, 그저 여러 대를 띄우고 서로 연결선만 그어주면 그 자체로 액티브-액티브(Active-Active) 고가용성 클러스터가 완성된다.

이러한 설계적 우아함은 인프라 운영자의 스트레스를 비약적으로 낮춰준다.

2. 네트워크 파티션(Network Partition) 및 스플릿 브레인(Split-brain) 현상 이해

데이터 센터와 로컬 공장을 잇는 전용선(Leased Line)을 굴착기가 끊어먹는 사고가 발생했다. 클라우드에 떠 있는 라우터 그룹 A와 로컬망의 라우터 그룹 B 사이의 연결망이 완전히 단절된 것이다.

분산 시스템에서는 이를 **네트워크 파티션(Network Partition)**이라 부르며, 이로 인해 하나의 시스템이 두 개의 별도 망으로 쪼개져 각각 독립적으로 동작하는 좀비 상태를 **스플릿 브레인(Split-brain)**이라 칭한다. Zenoh(제노) 네트워크는 이 끔찍한 파국(Catastrophe)을 어떻게 견뎌낼까?

2.1 Zenoh의 분산 아키텍처와 로컬 생존력(Local Survivability)

기존 중앙 집중형 미들웨어(예: 마스터 브로커 기반 아키텍처)에서는 클라우드의 중앙 서버와 연결이 끊기면 공장 내부망(그룹 B)의 모든 센서와 액추에이터는 서로 소통할 방법조차 잃고 올스톱(All-stop)된다.

하지만 Zenoh에서는 데이터의 출처이자 소비지인 에지 시스템들이 탈중앙화된 P2P 피어(Peer)나 로컬 라우터 망을 자체적으로 구성하고 있다. 중앙망과 끊기더라도:

  • 로컬 그룹 B에 속한 로봇과 제어 PC 간의 통신은 아무런 영향 없이 초저지연으로 정상 동작(Sub-mesh operation)을 이어간다.
  • 이를 클라우드 단절 환경(Air-gapped)에서의 생존력 확보라고 부른다.

2.2 분산 데이터의 불일치(Inconsistency)와 갈등 해소 방안

물론 스플릿 브레인 상황에서 완벽한 평화만 있는 것은 아니다. 그룹 A(클라우드)의 데이터베이스 스토리지와 그룹 B(로컬)의 센서 데이터가 양분되어, 단절 기간 동안 클라우드는 과거 시점에 멈춰있고 로컬망은 최신 데이터를 생산하는 데이터의 치명적인 불일치 상태에 놓인다.

통신선 복구 엔지니어가 끊어진 케이블을 다시 이어서 그룹 A와 그룹 B의 라우터가 재접속(Re-connect)하는 순간, Zenoh의 최단 경로 알고리즘은 즉시 업데이트된 라우팅 테이블(Link State)을 교환하여 통신 경로를 회복시킨다.

  • 이때 흘러가지 못하고 쌓여있던 쿼리(Query) 요청이나, 디스크(Storage Plugin)에 보관된 최신 값들은 분산 쿼리와 병합(Consolidation) 매커니즘을 통해 충돌 없이 안전하게 싱크(Sync)된다.
  • 결론적으로 Zenoh는 스플릿 브레인 사고 시 네트워크를 찢어진 상태로 놔두어 최소한의 로컬 오퍼레이션은 우아하게 존속(Graceful Degradation)시키고, 복구와 동시에 유연하게 봉합해 내는 회복 탄력성(Resilience)을 기본 철학으로 탑재하고 있다.

3. 노드 연결 끊김 시 자동 재접속(Auto-reconnect) 및 백오프(Backoff) 전략

클라이언트(Client)나 피어(Peer) 노드가 아무리 무선 연결 상태가 좋은 환경에 배치되었다 하더라도, 통신 미들웨어는 ’네트워크는 항상 끊어질 수 있다’는 맹제 하에 코드를 짜는 것이 클라우드 네이티브의 기본 소양이다.

특히, 라우터가 재부팅되거나 찰나의 와이파이(Wi-Fi) 그림자를 지날 때, 하드코딩된 단일 연결(Single connection)만 믿고 있는 애플리케이션은 즉시 크래시(Crash)가 나거나 메인 스레드가 패닉(Panic) 상태에 빠진다. **Zenoh(제노)**는 개발자가 예외 처리를 수십 줄씩 짜 넣지 않아도 알아서 통신선을 복구해 내는 무적의 라이브러리 엔진을 품고 있다.

3.1 멀티 호밍(Multi-homing)과 동적 엔드포인트 리스트

고가용성을 위해 4.9.1절에서처럼 2대 이상의 라우터를 클러스터링해 두었다면, 클라이언트 역시 2대 모두에 접속을 시도할 수 있도록 연결점(Endpoint)을 콤마(,)로 구분하여 나열해야 한다.

이렇게 여러 개의 대체 접속 경로를 쥐어주는 것을 **멀티 호밍(Multi-homing)**이라 부른다.

// 클라이언트의 zenoh.json5 설정 예시
{
  "mode": "client",
  "connect": {
    // Router-1이 죽어 있으면 자동으로 Router-2를 찾아간다.
    "endpoints": [
      "tcp/192.168.1.10:7447", 
      "tcp/192.168.1.11:7447"
    ]
  }
}

클라이언트는 기동 시점에 리스트 중 가장 응답 속도가 빠른 라우터에 먼저 붙게 되며, 통신 중 해당 라우터가 응답이 없으면 즉각적으로 다음 후보자에게 connect 소켓을 던져 세션 이주(Session Migration)를 성공시킨다.

3.2 지수적 백오프(Exponential Backoff)를 통한 과부하 방지

클라이언트가 라우터와 연결이 끊겼다고 해서 당황하여 1밀리초(ms) 단위로 접속 수락(SYN) 패킷을 난사하면 어떻게 될까? 동시에 접속이 끊긴 수만 대의 로봇이 똑같이 행동한다면 그 자체로 라우터 클러스터에 디도스(DDoS) 공격을 가하는 셈이 된다. 이를 **서징 트래픽(Surging Traffic)**이라 부른다.

Zenoh 클라이언트는 연결이 거부당할 때마다 다음 재접속 시도까지의 대기 시간을 지수 함수적으로 늘려 나가는 지수적 백오프(Exponential Backoff) 알고리즘을 코어 런타임에 기본 탑재하고 있다.
처음에는 100ms 뒤에, 실패하면 200ms, 그다음엔 400ms, 800ms… 하는 식으로 네트워크 스톰을 방지하며 라우터 클러스터가 완전히 숨을 고르고 복구될 시간을 벌어준다. 개발자는 스레드 슬립(Sleep) 로직을 한 줄도 짤 필요 없이, 그저 Zenoh 세션 객체가 알아서 복구될 때까지 묵묵히 퍼블리시(Publish) 함수만 던지면 된다.

4. 라우터 간 로드 밸런싱(Load Balancing) 및 트래픽 분산 메커니즘

1초에 수천 개의 영상 프레임을 쏘아 올리는 드론 편대, 초당 수 메가바이트의 라이다(LiDAR) 포인트 클라우드를 내뿜는 자율주행차량 등 거대한 데이터 파이프가 단일 Zenoh(제노) 라우터로 쏠리게 되면, 제아무리 극강의 성능을 자랑하는 Zenoh라 할지라도 포트 대역폭의 물리적 한계나 CPU 병목을 피할 수 없다.

앞선 절들에서 SPOF 회피를 위해 라우터를 여러 대(Mesh) 깔았다 하더라도, 모든 로봇이 첫 번째 라우터(Router-1) 하나만 물고 늘어진다면 이는 절반의 고가용성에 불과하다. 트래픽을 지능적으로 분산시키는 로드 밸런싱(Load Balancing) 아키텍처가 결합되어야 비로소 엔터프라이즈급 인프라라 부를 수 있다.

4.1 퍼블리셔(Publisher) 엔드포인트 무작위 셔플링

Zenoh는 전통적인 L4 로드 밸런서 장비(Nginx, HAProxy) 없이도 엣지 네트워크의 부하를 스스로 분산시킬 수 있다. 핵심은 앞서 설정한 클라이언트들의 connect 지점(Endpoints 리스트)에 있다.

로봇(클라이언트)을 수백 대 찍어낼 때 접속 지점을 [Router-A, Router-B, Router-C] 묶음으로 스크립트에 똑같이 넣어주기만 하면, Zenoh 클라이언트 네트워크 스택은 기동될 때마다 이 Endpoint 리스트를 무작위로 섞어서(Shuffle) 접속을 시도한다.

결과적으로 100대의 로봇 중 33대는 A로, 33대는 B로 균등하게 흩어져 붙게 되며, 어떠한 하드웨어 스위치의 도움 없이도 통계적 분산(Statistical Dispersion)을 달성해 낸다.

4.2 브로커 분산 방식과의 철학적 차이점 심층 분석

만약 Kafka나 RabbitMQ 같은 중앙형 브로커 메커니즘에서 이런 장난을 쳤다면 파국을 피할 수 없었을 것이다. 로봇 1이 브로커 A로 들어갔고 명령을 내릴 운영자가 브로커 B에 접속했다면, 브로커 간 무거운 클러스터 맵핑과 리더 동기화 상태 트리(Zookeeper 등)를 스캔하느라 트래픽이 지연되기 일쑤다.

반면, 4.9.1절에서 언급했듯 **Zenoh 라우터는 Stateless한 경로 교환기(Dispatcher)**에 불과하다. Router-1, 2, 3이 완전 연결망(Mesh) 상태로 물려 척추(Backbone)를 형성하고 있다면, 퍼블리셔가 어느 팔다리(Edge)로 데이터를 쑤셔 넣든, 서브스크라이버가 어느 포트에 귀를 대고 있든 간에 Zenoh 코어 알고리즘은 링크 상태(Link State) 정보에 기반하여 가장 지연이 적고 최적화된 토폴로지 홉(Hop)을 계산해 낸다.

한 곳으로 트래픽이 몰리면 우회 경로를 즉각 계산하여 동적으로 스패닝 트리를 조정하므로, 트래픽 폭주로 인한 부분적인 네트워크 병목마저도 강물이 돌멩이를 피해서 흐르듯 지능적으로 우회(Routing around congestion)하는 경이로운 트래픽 분산 메커니즘을 완성하게 된다.