본문으로 건너뛰기
김신건의 로그

[Distributed] NATS: 가벼움, JetStream, subject 라우팅

· 수정 · 📖 약 2분 · 685자/단어 #nats #message-broker #lightweight #edge #distributed
NATS, NATS.io, JetStream, core NATS, request-reply, subject hierarchy, NATS KV

정의

NATS = 극도로 가벼운 메시징 시스템. core NATS = at-most-once Pub/Sub + request-reply. JetStream = 영속 / at-least-once / exactly-once 까지.

특징:

  • 1 바이너리 (Go), 메모리 ~10MB.
  • 마이크로초 latency.
  • 수백만 msg/s/노드.
  • edge / IoT / 마이크로서비스 친화.

두 모드: Core vs JetStream

-Core NATSJetStream
영속없음 (in-memory)있음
신뢰성at-most-onceat-least-once / exactly-once
Latency매우 낮음낮음
사용telemetry, signalevent log, queue

Subject 계층

orders.created
orders.paid
orders.shipped.us
orders.shipped.eu
inventory.low.warehouse-a
와일드카드의미
*단어 1개
>나머지 모두
subscribe orders.*    → orders.created, orders.paid (1단 차이만)
subscribe orders.>    → orders.created, orders.paid, orders.shipped.us, ...

Request-Reply (Core NATS 의 강점)

sequenceDiagram
    autonumber
    participant R as Requester
    participant N as NATS
    participant S as Service

    S->>N: SUB shop.getItem
    R->>N: PUB shop.getItem (reply=INBOX.abc)
    N->>S: deliver
    S->>S: 처리
    S->>N: PUB INBOX.abc 결과
    N->>R: deliver
  • RPCPub/Sub 위에 자연스럽게.
  • load balancing = 같은 subject 의 queue group 으로.
// Queue group: 여러 service 가 같은 subject 구독, 한 명에게 전달
nats.subscribe('shop.getItem', { queue: 'shop' }, (msg) => { ... });

JetStream 개요

JetStream 은 NATS 에 내장된 영속 스트리밍 레이어:

flowchart LR
    P[Producer] -->|"PUB orders.>"| JS[("JetStream Stream")]
    JS --> Consumer1[Push consumer]
    JS --> Consumer2[Pull consumer]
    JS --> Consumer3[Durable consumer]
Consumer 타입의미
Pushbroker 가 능동 push
Pullconsumer 가 poll
Ephemeral임시 (재접속 시 처음부터)
Durable진행 상태 영속

JetStream Stream 설정

# nats CLI 또는 API 로 Stream 생성
stream:
  name: ORDERS
  subjects:
    - orders.>
  storage: file          # file (영속) / memory (빠름)
  retention: limits      # limits / workqueue / interest
  max_age: 24h           # 메시지 보존 기간
  replicas: 3            # 노드 수 (HA 필수)
  max_bytes: 10GB
  discard: old           # 한계 초과 시 오래된 것 삭제

JetStream 메시지 흐름 (Ack)

sequenceDiagram
    autonumber
    participant P as Producer
    participant JS as JetStream
    participant C as Consumer

    P->>JS: PUB orders.created
    JS-->>P: PubAck (seq=42)
    JS->>C: deliver msg (seq=42)
    C->>C: 처리
    C->>JS: Ack
    Note over JS: 해당 seq 완료 마킹
    alt Ack 없이 timeout
        JS->>C: redeliver (at-least-once)
    end

Consumer Ack 정책

AckPolicy동작
explicit각 메시지 개별 Ack. 가장 안전
allN번 Ack = 1~N 모두 확인 (배치 처리 효율)
noneAck 불필요. fire-and-forget
// Durable Consumer: 재연결 후 마지막 위치부터
const consumer = await js.consumers.get('ORDERS', 'order-processor');
for await (const msg of await consumer.consume()) {
  await processOrder(msg.json());
  msg.ack();   // explicit ack
}

NATS KV / Object Store

JetStream 위 추가 추상:

// KV
const kv = await jsm.views.kv('config');
await kv.put('feature.x', 'enabled');
const val = await kv.get('feature.x');

// Object Store
const os = await jsm.views.os('images');
await os.put('logo.png', readableStream);

Redis 같은 KV, S3 같은 object store 가 NATS 안에 통합. 작은 인프라 친화.

NATS Cluster 구성

# nats.conf (3-node cluster)
cluster {
  name: my-cluster
  listen: 0.0.0.0:6222
  routes: [
    nats-route://nats-0:6222
    nats-route://nats-1:6222
    nats-route://nats-2:6222
  ]
}
jetstream {
  store_dir: /data/jetstream
  max_memory_store: 4GB
  max_file_store: 100GB
}
  • 3 노드 이상 권장 (Raft 합의)
  • JetStream replica = 노드 수 이하 로 설정 (보통 3)

Edge / IoT 패턴

flowchart TB
    subgraph Edge["Edge devices (수천 ~ 수백만)"]
        E1[Sensor 1]
        E2[Sensor 2]
        EN[Sensor N]
    end
    Edge --> NEdge["NATS edge cluster"]
    NEdge --> Leaf["Leaf node"]
    Leaf --> NCloud["NATS central cluster"]
    NCloud --> Apps["Apps / Analytics"]
  • Leaf node = edge → central 의 경량 게이트웨이.
  • bandwidth 최적: 같은 메시지 한 번만 전송.
  • 오프라인 buffer + 재연결 시 sync.

NATS vs Kafka vs RabbitMQ

항목NATSKafkaRabbitMQ
바이너리 크기10 MB수백 MB수십 MB
운영 복잡도낮음높음중간
처리량매우 높음매우 높음중간
Latency최저중간낮음
영속옵션 (JS)항상옵션
Replication빌트인 (JS)빌트인mirror queue
학습 곡선낮음높음중간
Request-Reply네이티브 지원어색가능
Edge/IoT최적부적합가능

Kafka 와 NATS 의 핵심 차이:

-NATS JetStreamKafka
설계 목적빠른 메시징 + 선택적 영속대용량 영속 로그
장기 retention가능하지만 Kafka 만큼 최적화 안 됨최적 (수개월)
Offset 관리consumer 별 server-sideconsumer 가 broker 에 commit
Subject 라우팅와일드카드 (*, >)없음 (topic = exact match)

적합 / 부적합

flowchart TD
    Good[적합]
    Good --> G1[마이크로서비스 사이 메시징]
    Good --> G2["Edge / IoT"]
    Good --> G3[Real-time telemetry]
    Good --> G4["작은 영속 큐 (JS)"]
    Bad[부적합]
    Bad --> B1["복잡한 라우팅 (Topic exchange 같은)"]
    Bad --> B2[수개월 retention 의 거대 로그]

흔한 함정

WARNING

  1. Core NATS 의 손실 가능성 무시 = subscriber 없으면 조용히 사라짐. JS 로 가야.
  2. JS replica 1 = 노드 다운 시 손실. RF 3 권장.
  3. Wildcard 과도 사용 = >모든 메시지 받음 → 클라이언트 부하.
  4. Subject 표준화 없음 = 작은 팀에서는 OK, 큰 팀에서는 충돌 / 중복. 네임스페이스 가이드 필요.
  5. JetStream max_age 미설정 = 디스크 무한 증가. retention 정책 명시 필수.

관련 위키

이 글의 용어 (4개)
[Distributed] Kafka: 분산 로그, partition, consumer groupdistributed-systems
정의 Apache Kafka = 분산 commit log. 고처리량 (수백만 msg/s), 영속, 수평 확장. event-driven 아키텍처 의 de facto. 핵심 개념: …
[Distributed] RabbitMQ: exchange, queue, routing keydistributed-systems
정의 RabbitMQ = AMQP 0.9.1 기반 traditional message broker. exchange → queue 라우팅, workload distribution…
[Network] gRPC: HTTP/2 + Protobuf, 4가지 streaming 패턴network
정의 gRPC 는 HTTP/2 위에서 Protobuf 직렬화 로 동작하는 고성능 RPC 프레임워크. Google 내부 Stubby 의 오픈소스 후계. 핵심 4가지: 1. Prot…
[Redis] Pub/Sub vs Streams: 휘발 신호 vs 영속 로그database-internals
정의 - Pub/Sub ( / ): 지금 듣고 있는 구독자 에게만 메시지가 전달되는 휘발성 신호. 영속 없음, ACK 없음. fan-out. - Streams ( / / / ):…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기