13.9 Zenoh 생태계와의 심화 통합
Zenoh-Flow 파이프라인은 진공 상태에서 고립되어 돌아가는 컨베이어 벨트가 아니다.
그 아래에는 8장부터 12장까지 우리가 뼈 빠지게 다뤘던 Pub/Sub, Queryable, ROS2 Bridge, Storage 등 모든 Zenoh 생태계의 무기들이 거미줄처럼 깔려 있다. 플로우 파이프라인을 이 오리지널 Zenoh 병기들과 결합하여 아키텍처를 전방위로 확장(Expansion) 하는 최후의 런북이다.
1. Zenoh 기본 Pub/Sub 프로토콜과 Zenoh-Flow 파이프라인의 동적 연동
내 휴대폰의 z_pub 명령 한 번으로 공장 바닥에 떨어져 있는 Zenoh-Flow 파이프라인에 데이터를 때려 넣을 수 있는가? 완벽하게 가능하다.
1.0.1 [Runbook] 세계선(Key Expression) 교차 전술
파이프라인의 입력구(Source) 와 출력구(Sink) 를 철저히 오리지널 Zenoh 프로토콜(Pub/Sub) 로 설계하라.
1. Zenoh Subscriber Source
- 노드는 카메라가 아니라 허공을 바라봐야 한다.
- C++ / Rust 소스 코드를 짤 때
zenoh.subscribe("factory/cam_01")로 선언한다. - 이렇게 해두면 파이프라인 밖의 어떤 평범한 Zenoh 클라이언트라도 이
factory/cam_01에Put을 쏘는 순간, 데이터플로우의 거대한 톱니바퀴가 즉각 굴러가기 시작한다.
2. Zenoh Publisher Sink
- 10개의 필터를 뚫고 나온 최종 추론 결과를 DB 가 아닌 허공(Key) 에다 뿌린다.
- 싱크 코드:
zenoh.put("analytics/result", output_data) - 파이프라인 밖에서 파이썬이나 TypeScript 앱이 이 토픽을 Sub 하고 있다면, 복잡한 파이프라인에 직접 개입하지 않고도 결괏값만 공짜로 주워 담을 수 있다(Decoupling).
파이프라인은 밀폐된 터널이 아니라 수십 개의 출입문이 열려 있는 다차원 관문(Gateway) 이다.
2. Zenoh Query를 활용한 파이프라인 내부 상태 실시간 조회
오퍼레이터가 며칠째 내부 State 에 누적 계산해 놓은 주행 거리를 실시간 대시보드에서 보고 싶다.
그런데 파이프라인의 Sink(출구) 에 도달하려면 아직 1시간을 더 연산해야 한다면?
2.0.1 [인스펙션] 오퍼레이터 심장 절개 (RPC) 전술
오퍼레이터(Operator) 는 사실 데이터를 씹어 삼키기만 하는 좀비가 아니다.
필터 내부 코드에서 외부의 Get 질문에 답하는 Queryable(응답기) 도 동시에 장착할 수 있다.
1. 오퍼레이터 안에서의 Queryable 선언
// 오퍼레이터의 init 함수 안
let my_state_tracker = ...; // 내부 지갑
zenoh.declare_queryable("pipeline/op_1/status").callback(|query| {
// 외부에서 질문이 들어오면 상태를 직렬화해서 던져준다!
query.reply("pipeline/op_1/status", my_state_tracker.get_current());
});
2. 관제사의 핀포인트 쿼리
관제사는 파이프라인의 데이터 흐름(Dataflow) 을 방해하지 않는다.
노트북에서 z_get "pipeline/op_1/status" 만 타격하면, 수많은 파이프를 타고 이동 중인 데이터 속에서 딱 1개의 파이프 노드(Operator) 의 혈압(State) 만 마이크로초 컷으로 빼내어 진단할 수 있다. 분산 데이터 정밀 감사(Audit) 의 교과서다.
3. ROS2 네트워크와의 통합: 로보틱스 데이터플로우 브릿지 구성
ROS2 의 액션(Action) 이나 서비스(Service) 가 무거워 뻗기 시작할 때, 병목이 심한 인지(Perception) 노드 구역 하나를 통째로 뜯어내서 Zenoh-Flow 의 연산 군단으로 치환한다.
3.0.1 [Runbook] ROS2 / Zenoh-Flow 흉강 압박 전술
두 시스템을 엮는 접착제는 오직 12장에서 배운 zenoh-bridge-dds 다.
1. 파이프라인의 입구(Source) 는 DDS 를 스니핑한다
- 브릿지가 ROS2 의
/image_raw토픽을 주워서 Zenoh 망에 뿌린다. - Zenoh-Flow 의 Source 노드는 카메라 드라이버를 켤 필요가 없다! 그저 Zenoh 에 떨어지는
/image_raw바이트 덤프를 바로 흡입하여 파이프라인을 가동한다.
2. 순수 플로우 프로세싱 (The Flow)
- 라즈베리 파이에서 터지는 ROS2 연산의 굴레를 박살 낸다.
- Zenoh-Flow 오퍼레이터(YAML 설계) 를 “외부 AWS GPU 서버” 로 강제 할당시킨다. 사진은 로봇에서 찍혔지만 변환 수술은 클라우드에서 빛의 속도로 벌어진다.
3. 파이프라인의 출구(Sink) 는 ROS2 로 재주입한다
- 파이프라인의 끝에서 만들어진 결과물
/cmd_vel을 Zenoh 망에 던진다(Put). - 로봇 내부에 켜져 있던
zenoh-bridge-dds가 이를 낚아채어 진짜 로봇의 바퀴(DDS 망) 로 강제 브로드캐스팅해 버린다. - ROS2 의 거북이는 방금 지나간 0.05초의 판단이 지구 반대편의 컨베이어 벨트를 거쳐 돌아왔다는 사실조차 눈치채지 못한다.
4. Zenoh 스토리지 백엔드(Backend)와의 연동을 통한 파이프라인 결과 영구 저장
자율주행차가 주행을 마치고 시동을 껐다. 컨베이어 벨트(파이프라인) 도 멈췄다. 허공으로 날아간 페타바이트급 데이터는 어디에 남아야 하는가?
4.0.1 [인스펙션] 타임 시리즈(Time-series) 스토리지 다이렉트 덤프
1. 싱크(Sink) 단의 데이터베이스 타격 분리
일반적인 스트리밍 엔진이라면 싱크 코드 안에서 PostgreSQL 드라이버를 열어 쿼리를 날릴 테지만, Zenoh 에서는 그런 블로킹 네트워크 코딩을 절대 권장하지 않는다.
2. 플러그인 스토리지 백엔드 (Zenoh Plugin Storage) 활용
- 싱크(Sink) 의 마지막 로직은 그냥
zenoh.put("archive/ai/result", data)하나로 허공에 뿌리고 노드를 종료시킨다. 가공할 배출 속도를 보장한다. - 그리고 라우터(
zenohd) 백그라운드에 InfluxDB 플러그인 스토리지 모듈을 켜둔다! - 저장 모듈이 네트워크의 끝단에서
archive/ai/**로 떨어지는 모든 가공된 파이프라인 결과 데이터를 묵묵히 낚아채어 TSDB 디스크로 쾅쾅 박아 넣는다.
파이프라인은 계산만 하고 저장소는 줍기만 한다. 계산 계층(Compute Layer) 과 저장 계층(Storage Layer) 의 거룩하고도 숨김 없는 분리(Decoupling). 이것이 Zenoh 생태계가 제안하는 데이터 인프라의 마스터피스다.