NATS JetStream — Messaging siêu nhẹ cho Microservices Event-Driven

Posted on: 4/27/2026 9:11:04 AM

Trong thế giới microservices, việc các service giao tiếp với nhau một cách đáng tin cậy và hiệu quả là bài toán cốt lõi. NATS — hệ thống messaging mã nguồn mở viết bằng Go — đã âm thầm trở thành lựa chọn hàng đầu cho các kiến trúc event-driven nhờ hiệu năng cực cao, footprint siêu nhẹ và mô hình triển khai linh hoạt. Với JetStream — lớp persistence tích hợp sẵn — NATS không còn chỉ là pub/sub đơn thuần mà đã trở thành một nền tảng streaming hoàn chỉnh, cạnh tranh trực tiếp với Kafka và RabbitMQ.

15M+ Messages/giây — throughput đỉnh NATS Core
<100μs Latency trung bình end-to-end
~20MB RAM footprint cho NATS Server
1 binary Zero dependency — không cần JVM, Erlang, Zookeeper

NATS là gì và tại sao nó quan trọng?

NATS (Neural Autonomic Transport System) được tạo bởi Derek Collier — người từng xây dựng hệ thống messaging tại TIBCO. Triết lý thiết kế của NATS hoàn toàn khác biệt so với Kafka hay RabbitMQ:

  • Simplicity first: Một binary duy nhất, cấu hình tối thiểu, protocol text-based dễ debug.
  • Always on, always available: Self-healing cluster, tự reconnect, không cần human intervention.
  • Multi-pattern: Pub/Sub, Request/Reply, Queue Groups, Key-Value Store, Object Store — tất cả trong một.
  • Location transparency: Client không cần biết service nào đang chạy ở đâu — NATS tự route.
graph TB
    subgraph "NATS Unified Platform"
        A[NATS Core] --> B[Pub/Sub]
        A --> C[Request/Reply]
        A --> D[Queue Groups]
        E[JetStream] --> F[Streaming]
        E --> G[Key-Value Store]
        E --> H[Object Store]
        E --> I[Exactly-Once Delivery]
    end

    J[Microservice A] --> A
    K[Microservice B] --> A
    L[Microservice C] --> E
    M[Edge Device] --> A

    style A fill:#e94560,stroke:#fff,color:#fff
    style E fill:#2c3e50,stroke:#fff,color:#fff
    style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style F fill:#f8f9fa,stroke:#2c3e50,color:#2c3e50
    style G fill:#f8f9fa,stroke:#2c3e50,color:#2c3e50
    style H fill:#f8f9fa,stroke:#2c3e50,color:#2c3e50
    style I fill:#f8f9fa,stroke:#2c3e50,color:#2c3e50
    style J fill:#4CAF50,stroke:#fff,color:#fff
    style K fill:#4CAF50,stroke:#fff,color:#fff
    style L fill:#4CAF50,stroke:#fff,color:#fff
    style M fill:#4CAF50,stroke:#fff,color:#fff

NATS — nền tảng messaging thống nhất cho mọi pattern giao tiếp

NATS Core: Nền tảng giao tiếp siêu nhẹ

NATS Core cung cấp messaging at-most-once với hiệu năng cực kỳ ấn tượng. Đây là lớp giao tiếp lý tưởng cho các use case không yêu cầu persistence — như health check, service discovery, hay real-time notifications.

Pub/Sub — Fire and Forget

Mô hình đơn giản nhất: publisher gửi message lên subject, tất cả subscriber đang listen sẽ nhận được.

// Publisher
await nats.PublishAsync("orders.created", orderData);

// Subscriber
await foreach (var msg in nats.SubscribeAsync<Order>("orders.created"))
{
    await ProcessOrder(msg.Data);
}

Request/Reply — Synchronous over Async

NATS biến async messaging thành request/reply pattern, cho phép microservices giao tiếp đồng bộ mà không cần biết nhau trực tiếp.

// Service A — request
var reply = await nats.RequestAsync<OrderRequest, OrderResponse>(
    "orders.validate", new OrderRequest { Id = 42 });

// Service B — reply handler
await foreach (var msg in nats.SubscribeAsync<OrderRequest>("orders.validate"))
{
    var result = await ValidateOrder(msg.Data);
    await msg.ReplyAsync(result);
}

Queue Groups — Load Balancing tự động

Khi nhiều instance của cùng một service subscribe vào cùng subject với queue group, NATS tự động phân phối message theo round-robin — không cần load balancer riêng.

// 3 instances cùng subscribe — NATS tự load balance
await foreach (var msg in nats.SubscribeAsync<Order>(
    "orders.process", queueGroup: "order-processors"))
{
    await ProcessOrder(msg.Data);
}

Queue Groups vs Kafka Consumer Groups

Không giống Kafka yêu cầu partition để parallelism, NATS Queue Groups hoạt động trên bất kỳ subject nào mà không cần cấu hình trước. Thêm/bớt consumer instance hoàn toàn tự động — zero configuration.

JetStream: Persistence và Streaming

JetStream là lớp persistence được tích hợp trực tiếp vào NATS Server (bật bằng một dòng config). Nó biến NATS từ messaging system thuần túy thành một streaming platform đầy đủ tính năng.

graph LR
    A[Producer] -->|Publish| B[Stream]
    B -->|"Retention: Limits/Interest/WorkQueue"| C[Storage Layer]
    C -->|File/Memory| D[(Raft Consensus)]
    B --> E[Consumer 1
Durable, Pull] B --> F[Consumer 2
Push, Ephemeral] B --> G[Consumer 3
Ordered] style A fill:#4CAF50,stroke:#fff,color:#fff style B fill:#e94560,stroke:#fff,color:#fff style C fill:#2c3e50,stroke:#fff,color:#fff style D fill:#2c3e50,stroke:#fff,color:#fff style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style F fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style G fill:#f8f9fa,stroke:#e94560,color:#2c3e50

Kiến trúc JetStream — Stream, Storage và Consumer

Streams — Nơi lưu trữ messages

Stream là đơn vị lưu trữ trong JetStream, có thể capture messages từ nhiều subjects. Ba chế độ retention:

Retention Policy Mô tả Use Case
Limits Giữ message theo size/count/age — cũ nhất bị xóa trước Event log, audit trail
Interest Xóa message khi tất cả consumer đã ack Task queue với nhiều worker groups
WorkQueue Xóa message ngay khi bất kỳ consumer nào ack Job processing, exclusive consumer

Exactly-Once Delivery

JetStream hỗ trợ exactly-once thông qua sự kết hợp của message deduplication (phía producer) và double ack (phía consumer):

// Producer: deduplication bằng Nats-Msg-Id header
var headers = new NatsHeaders { { "Nats-Msg-Id", $"order-{orderId}" } };
var ack = await js.PublishAsync("orders.created", orderData,
    opts: new NatsJSPubOpts { MsgId = $"order-{orderId}" });

// Consumer: double ack đảm bảo exactly-once processing
await foreach (var msg in consumer.ConsumeAsync<Order>())
{
    await ProcessOrderIdempotently(msg.Data);
    await msg.AckAsync();  // Server xác nhận đã xử lý
}

Exactly-Once không miễn phí

Deduplication window mặc định là 2 phút. Producer phải gán Nats-Msg-Id duy nhất cho mỗi message. Consumer vẫn cần idempotent processing — JetStream đảm bảo delivery, không đảm bảo business logic.

Key-Value Store: State Management tích hợp

JetStream cung cấp một Key-Value Store immediately-consistent, built-in — không cần Redis hay etcd riêng cho configuration, feature flags, hay service registry.

// Tạo KV bucket
var kv = await js.CreateKeyValueStoreAsync(new NatsKVConfig("config")
{
    History = 5,  // Giữ 5 versions gần nhất
    MaxBytes = 1024 * 1024
});

// Put/Get
await kv.PutAsync("feature.dark-mode", "enabled");
var entry = await kv.GetEntryAsync<string>("feature.dark-mode");

// Watch changes — real-time notification
await foreach (var update in kv.WatchAsync<string>("feature.>"))
{
    Console.WriteLine($"Config changed: {update.Key} = {update.Value}");
}

Đặc biệt, KV Store hỗ trợ history — bạn có thể xem các giá trị trước đó của một key, tính năng mà Redis không có natively.

Kiến trúc Cluster và Edge Deployment

NATS có mô hình topology linh hoạt nhất trong số các messaging systems hiện tại:

graph TB
    subgraph "Region US — Supercluster"
        US1[NATS Node 1] --- US2[NATS Node 2]
        US2 --- US3[NATS Node 3]
        US3 --- US1
    end

    subgraph "Region EU — Supercluster"
        EU1[NATS Node 1] --- EU2[NATS Node 2]
        EU2 --- EU3[NATS Node 3]
        EU3 --- EU1
    end

    subgraph "Edge — Leaf Nodes"
        L1[Factory Floor
Leaf Node] L2[IoT Gateway
Leaf Node] L3[Dev Machine
Leaf Node] end US1 ---|Gateway| EU1 US2 --> L1 EU2 --> L2 US3 --> L3 style US1 fill:#e94560,stroke:#fff,color:#fff style US2 fill:#e94560,stroke:#fff,color:#fff style US3 fill:#e94560,stroke:#fff,color:#fff style EU1 fill:#2c3e50,stroke:#fff,color:#fff style EU2 fill:#2c3e50,stroke:#fff,color:#fff style EU3 fill:#2c3e50,stroke:#fff,color:#fff style L1 fill:#4CAF50,stroke:#fff,color:#fff style L2 fill:#4CAF50,stroke:#fff,color:#fff style L3 fill:#4CAF50,stroke:#fff,color:#fff

NATS Superclusters + Leaf Nodes — messaging từ cloud đến edge

Superclusters

Nhiều NATS clusters kết nối qua Gateway tạo thành supercluster. Messages tự động route giữa các cluster/region mà client không cần biết topology. Thêm region mới? Chỉ cần kết nối gateway — zero downtime, zero client changes.

Leaf Nodes — Edge Computing với NATS

Leaf Nodes là NATS server instances nhẹ kết nối vào cluster/supercluster chính. Điểm đặc biệt:

  • Disconnected operation: Khi mất kết nối internet, leaf node vẫn hoạt động độc lập với local JetStream.
  • Automatic sync: Khi kết nối phục hồi, messages tự động đồng bộ lên hub.
  • Security boundary: Leaf node có thể giới hạn subjects được phép, tạo multi-tenancy tự nhiên.

Use case thực tế

Một nhà máy sản xuất triển khai leaf node tại mỗi dây chuyền, thu thập dữ liệu sensor real-time. Khi mạng WAN gián đoạn, dây chuyền vẫn chạy bình thường — dữ liệu buffer locally và sync lên cloud khi kết nối phục hồi. Pattern này cực kỳ phù hợp cho IoT và edge computing.

So sánh NATS vs Kafka vs RabbitMQ

Tiêu chí NATS JetStream Apache Kafka RabbitMQ
Throughput (persistent) 200K-400K msg/s 500K-1M+ msg/s 50K-100K msg/s
Latency Sub-ms (core), 1-5ms (JetStream) 10-50ms (batching) 5-20ms
Operational complexity Rất thấp — 1 binary Cao — KRaft/ZK, schema registry Trung bình — Erlang runtime
Multi-pattern Pub/Sub, Req/Reply, Queue, KV, Object Store Pub/Sub, Streams Pub/Sub, Queue, RPC
Edge deployment Leaf Nodes native Không hỗ trợ native Federation/Shovel
Memory footprint ~20MB ~1GB+ ~150MB
Best for Microservices, IoT, Edge, Request/Reply Event streaming, Data pipeline, Log aggregation Enterprise messaging, Task queues

Tích hợp NATS với .NET và Aspire

NATS .NET client v2 hỗ trợ .NET 6+ với async-first API. Đặc biệt, .NET Aspire đã có integration chính thức cho NATS:

// Program.cs — Aspire AppHost
var nats = builder.AddNats("nats")
    .WithJetStream();

var orderService = builder.AddProject<Projects.OrderService>()
    .WithReference(nats);

// OrderService — DI registration
builder.AddNatsClient("nats");

// Sử dụng trong service
public class OrderProcessor(INatsConnection nats)
{
    public async Task ProcessAsync(CancellationToken ct)
    {
        var js = nats.CreateJetStreamContext();

        var consumer = await js.GetConsumerAsync("ORDERS", "processor", ct);

        await foreach (var msg in consumer.ConsumeAsync<OrderEvent>(cancellationToken: ct))
        {
            try
            {
                await HandleOrder(msg.Data);
                await msg.AckAsync(cancellationToken: ct);
            }
            catch (Exception ex)
            {
                await msg.NakAsync(cancellationToken: ct); // Redeliver
            }
        }
    }
}

Pattern thực tế: Saga với NATS JetStream

Distributed transaction giữa nhiều microservices sử dụng Choreography Saga pattern với NATS:

sequenceDiagram
    participant OS as Order Service
    participant N as NATS JetStream
    participant PS as Payment Service
    participant IS as Inventory Service
    participant NS as Notification Service

    OS->>N: orders.created
    N->>PS: orders.created (Consumer Group)
    PS->>N: payments.completed
    N->>IS: payments.completed
    IS->>N: inventory.reserved
    N->>NS: inventory.reserved
    NS->>N: notification.sent

    Note over PS,N: Nếu payment fail
    PS->>N: payments.failed
    N->>OS: payments.failed (Compensate)
    OS->>N: orders.cancelled

    style N fill:#e94560,stroke:#fff,color:#fff

Choreography Saga pattern với NATS JetStream làm event backbone

// Cấu hình Stream cho Saga
var streamConfig = new StreamConfig("SAGA", subjects: new[]
{
    "orders.>", "payments.>", "inventory.>", "notifications.>"
})
{
    Retention = StreamConfigRetention.Interest,  // Xóa khi tất cả consumer đã ack
    MaxAge = TimeSpan.FromHours(24),
    Replicas = 3  // High availability
};

await js.CreateStreamAsync(streamConfig);

Monitoring và Observability

NATS Server expose metrics qua HTTP endpoint /varz, /connz, /subsz, dễ dàng tích hợp với Prometheus/Grafana. Ngoài ra, nats-top cung cấp real-time monitoring tương tự top cho Unix:

# Monitoring endpoints
curl http://localhost:8222/varz   # Server stats
curl http://localhost:8222/jsz    # JetStream stats
curl http://localhost:8222/connz  # Connection info

# Real-time monitoring
nats-top -s msgs_per_sec

Khi nào nên chọn NATS?

Chọn NATS JetStream khi

1. Cần hệ thống messaging đa năng (pub/sub + request/reply + streaming + KV) mà không muốn vận hành nhiều hệ thống riêng lẻ.
2. Latency dưới millisecond là yêu cầu bắt buộc.
3. Có edge/IoT deployment cần hoạt động offline (Leaf Nodes).
4. Team nhỏ, muốn operational simplicity — NATS chạy ổn định với gần như zero maintenance.
5. Microservices cần request/reply pattern (Kafka và RabbitMQ không native support tốt).

Cân nhắc Kafka thay thế khi

1. Throughput trên 500K msg/s với persistence là yêu cầu cứng.
2. Cần stream processing phức tạp (Kafka Streams, ksqlDB).
3. Log aggregation / data pipeline quy mô lớn với retention dài hạn (terabytes).
4. Ecosystem maturity: Schema Registry, Kafka Connect, hàng trăm connectors sẵn có.

Kết luận

NATS JetStream đã chứng minh rằng messaging system không nhất thiết phải phức tạp để mạnh mẽ. Với footprint chỉ ~20MB RAM, latency sub-millisecond, và khả năng triển khai từ cloud đến edge trong cùng một platform, NATS là lựa chọn đáng xem xét nghiêm túc cho bất kỳ kiến trúc microservices nào — đặc biệt khi team coi trọng operational simplicity. Phiên bản NATS Server 2.12 (tháng 4/2026) tiếp tục cải thiện atomic batch publishing và JetStream performance, khẳng định vị thế của NATS trong cuộc đua messaging platform.

Tham khảo