NATS详解
一、NATS 配置详解
1.1 命令行参数功能
nats-server \
-a 0.0.0.0 \ # 监听地址,默认“0.0.0.0”
-p 4222 \ # 客户端通信端口,默认 4222
-m 8222 \ # HTTP 监控端口,默认不开启
-js \ # 启用 JetStream 功能
--store_dir ./data # JetStream 存储目录
-c /path/nats.conf \# 指定配置文件
-l /var/log/nats.log \ # 日志文件
-V \ # 输出协议级调试信息
-t # 验证配置文件语法并退出
参数优先级:命令行 > 配置文件 > 默认值(如 -t
为语法校验后退出)
1.2 配置文件详解(以 YAML/CONF 格式书写)
支持注释、include
引用、变量替换 ($VAR
或环境变量),适合正式环境部署。
############################################################
# 基础配置
############################################################
# NATS Server 名称,可用于集群状态监控和日志识别
server_name: "nats-main"
# 客户端连接监听地址与端口(默认 0.0.0.0:4222)
listen: 0.0.0.0:4222
# HTTP 管理监控接口(默认关闭,常用于 Prometheus/健康检查)
http_port: 8222
# 启用调试和追踪(仅开发环境建议开启)
debug: false
trace: false
# 日志文件路径(也可以在命令行通过 -l 指定)
log_file: "./logs/nats.log"
# PID 文件路径
pid_file: "./nats-server.pid"
# 写日志到 stdout(默认 true)
logtime: true
############################################################
# 安全认证配置
############################################################
authorization {
# 用户列表(用户名 + 密码 + 权限)
users = [
{
user: "admin"
password: "admin123"
permissions: {
publish: { allow: ["admin.>"] }
subscribe: { allow: ["admin.>"] }
}
},
{
user: "reader"
password: "reader123"
permissions: {
publish: { deny: [">"] }
subscribe: { allow: ["public.>"] }
}
}
]
# 允许匿名访问(默认 false,设置为 true 表示不需要认证)
# no_auth_user: "guest"
}
# 认证配置-token认证
#authorization {
# Token 认证(所有客户端使用相同的 token 连接)
# token: "your-secret-token-here" # 替换为你的实际 token
#}
############################################################
# JetStream 持久化配置
############################################################
jetstream {
enabled: true # 启用 JetStream 功能
store_dir: "./data/jetstream" # JetStream 存储路径(文件或内存)
domain: "default" # 多租户 JetStream 域名(可选)
max_mem_store: 2Gb # JetStream 使用的最大内存
max_file_store: 10Gb # JetStream 使用的最大文件空间
}
############################################################
# WebSocket 支持(可选)
############################################################
websocket {
enabled: false # 启用 WebSocket 支持
host: "0.0.0.0"
port: 9222 # WebSocket 监听端口
same_origin: true # 是否要求前端连接来源一致
# 支持的协议(一般为 "nats")
# allowed_origins: ["https://example.com"]
}
############################################################
# 集群配置(支持横向扩展)
############################################################
cluster {
name: "nats-cluster"
listen: "0.0.0.0:6222" # 当前节点监听的 cluster 端口
# 当前节点的路由列表(可连接到其它集群节点)
routes: [
"nats://nats-node-2:6222"
"nats://nats-node-3:6222"
]
connect_timeout: 2s
# 如果开启认证,集群间连接也需要账号密码
authorization {
user: "cluster"
password: "clusterpass"
}
}
############################################################
# Gateway 跨数据中心连接(多集群联邦)
############################################################
gateway {
name: "dc1"
listen: "0.0.0.0:7522"
advertise: "nats-dc1:7522" # 本地 gateway 对外地址
gateways: [
{
name: "dc2"
urls: ["nats://nats-dc2:7522"]
}
]
}
############################################################
# LeafNodes(连接边缘节点/前端集群)
############################################################
leafnodes {
listen: "0.0.0.0:7422"
remotes = [
{
url: "nats://leafnode-user:leafpass@leafhost:7422"
}
]
}
############################################################
# 资源限制(防止滥用)
############################################################
# 限制每个客户端的最大连接数/订阅数/消息大小等
limits {
max_connections: 10000 # 最大连接数
max_subscriptions: 100000 # 最大订阅数
max_payload: 1Mb # 最大消息负载
write_deadline: 2s # 写入超时时间
}
############################################################
# TLS 加密配置(生产环境推荐开启)
############################################################
# tls {
# cert_file: "./certs/server-cert.pem"
# key_file: "./certs/server-key.pem"
# ca_file: "./certs/ca.pem"
# verify: true
# timeout: 5
# }
############################################################
# Include 支持(引用其他配置)
############################################################
# include "./more.conf" # 支持引入多个配置文件模块化管理
注意事项
JetStream
配置必须在启用了jetstream.enabled = true
的前提下生效。gateway
、leafnodes
、cluster
三者用途不同,不可混淆。- 所有单位支持:
k
,m
,g
,如512Mb
,1Gb
,或10k
。 - 注释支持
#
,不支持//
。 - WebSocket 是为了让 NATS 更好支持“浏览器 / Web / 移动 / 小程序 / 受限网络环境”下的实时通信需求
1.3 集群配置
LeafNodes
、Gateway
和 Cluster
是 NATS 构建分布式系统的三种关键网络拓扑机制,它们解决的是不同层级的连接、同步和隔离问题。
┌─────────┐ ┌─────────────┐ ┌───────────────┐
│ LeafNode│ 连接到 │ Cluster 主节点 │ ↔ │ Gateway 到其他集群 │
└─────────┘ └─────────────┘ └───────────────┘
👇 👇 👇
边缘设备 同一集群内节点 不同集群之间同步
轻量NATS 服务注册 + 状态一致 跨 DC / 多租户 / 环境联通
-
Cluster —— 基本集群,同一个“集群名”
作用: 把多个 NATS 节点组成一个逻辑上的“集群”,用于:
- 负载均衡(客户端连接到任一节点)
- 状态共享(连接信息 / JetStream stream 分布)
- 高可用(某节点挂了,客户端自动连其他)
用法:
# 每个节点都要配置 cluster { name: "nats-cluster" listen: "0.0.0.0:6222" # 本地集群通信端口 routes: [ "nats://nats-node2:6222", "nats://nats-node3:6222" ] }
所有节点共享相同 cluster name,构成同一个集群。
应用场景:
- 一个系统内部横向扩展多节点
- 客户端通过 VIP 接入 NATS
- JetStream 的 stream 可选复制、分片到各个节点
-
LeafNodes —— “子节点”,边缘设备直连中心
作用:
LeafNode 是一个 小型 NATS 实例,连接到中心节点(Hub):
- 转发本地客户端连接到主节点
- 不共享状态(如 JetStream、连接列表等)
- 不需要集群名、也不参与 cluster 协议
Leaf 配置:
leafnodes { listen: "0.0.0.0:7422" # Leaf节点监听端口 }
Hub 配置(中心服务器):
leafnodes { remotes = [ { url: "nats://leaf-user:pass@leafhost:7422" } ] }
LeafNode 是一种轻量级“接入点”或“代理”,适合边缘设备、内网小节点、IoT 设备接入总部。
应用场景:
- IoT 网关:边缘设备只部署 leaf NATS 实例
- VPC 接入:私网内只跑 leaf,再转发到公网节点
- Dev → Prod 中转:开发环境通过 Leaf 连接生产只读
-
Gateway —— 多个集群之间的桥梁连接
作用: Gateway 是用于连接 不同集群 的桥梁(集群之间同步消息):
- 各自 cluster 内保持一致性
- Gateway 之间同步 subject、订阅
- 支持权限隔离、JetStream 隔离
- 避免跨集群大量 route 消息造成冗余
配置:
gateway { name: "dc1" listen: "0.0.0.0:7522" # 本地 gateway 端口 advertise: "nats-dc1:7522" # 外部看到的地址 # 远程集群 gateways: [ { name: "dc2" urls: ["nats://dc2-nats1:7522"] } ] }
每个集群必须起码有一个节点配置该
gateway
,即可建立多集群同步网络。应用场景:
- 多数据中心(dc1, dc2)同步用户事件流
- SaaS 平台:租户隔离后做 gateway 互通
- 流量治理:A 只允许 pub,B 只 sub
- “多活架构”中连接各活跃集群
1.3 动态 reload 配置功能
修改配置后,可用命令或发送信号动态重加载(不中断连接)
nats-server -signal reload
支持多次 reload,例如新增用户、改变 limits 参数,非常适合线上运维。
1.4 常用子模块介绍
子模块 | 配置内容 | 注释说明 |
---|---|---|
authorization |
用户 / JWT / permissions | 客户端连接认证与访问控制 |
tls |
TLS/SSL 证书路径等 | 通信加密 |
monitoring |
HTTP Stats & profiling | 性能监控端点 |
websocket |
WebSocket 支持 | 用于前端实时通信(如 WebSocket 客户端) |
cluster |
节点互联参数 | 用于大型服务部署 |
websocket |
支持 WebSocket 客户端接入 |
二,编写Nats配置类
2.1 基础配置bean
在 Spring Boot 中使用 NATS 需要配置 Connection
Bean 来建立与 NATS 服务器的连接,在 @Configuration
类中定义 NATS 连接 Bean:
@Configuration
public class NatsConfig {
@Value("${nats.server}")
private String natsServer;
@Value("${nats.name}")
private String serverName;
@Bean
public Connection natsConnection() throws IOException, InterruptedException {
Options options = new Options.Builder()
.server(natsServer) // 服务器地址数组
.connectionTimeout(Duration.ofSeconds(5)) // 连接超时时间
.reconnectWait(Duration.ofSeconds(1)) // 重连等待时间
.maxReconnects(10) // 最大重连次数,-1代表无限重连
.connectionName(serverName) // 连接名称(服务端可见)
.errorListener(new CustomErrorListener()) // 错误监听器
.connectionListener(new CustomConnectionListener())//连接状态监听器
.reconnectBufferSize(1024 * 1024 * 1024)//重连缓冲区大小
.build();
return Nats.connect(options);
}
}
2.2 监听器配置
在 NATS Java 客户端中,有两个核心监听器用于监控连接状态和处理错误:ConnectionListener
和 ErrorListener
2.2.1 ConnectionListener - 连接状态监听器
代码示例
package org.example.natsdemo.Listener;
import io.nats.client.Connection;
import io.nats.client.ConnectionListener;
import lombok.extern.slf4j.Slf4j;
import java.util.Collection;
/**
* 自定义NATS连接监听器
*
* <p>实现ConnectionListener接口,用于监听NATS连接的生命周期事件。
* 注意:根据官方接口定义,只包含connectionEvent一个回调方法。</p>
*
* <p>事件类型说明:</p>
* <ul>
* <li>CONNECTED - 首次成功建立连接</li>
* <li>DISCONNECTED - 连接意外断开</li>
* <li>RECONNECTED - 成功重新连接</li>
* <li>CLOSED - 连接永久关闭</li>
* <li>RESUBSCRIBED - 重新建立所有订阅</li>
* <li>DISCOVERED_SERVERS - 发现新的服务器节点</li>
* <li>LAME_DUCK - 服务器进入优雅关闭模式</li>
* </ul>
*/
@Slf4j
public class CustomConnectionListener implements ConnectionListener {
/**
* 连接事件统一处理回调
*
* <p>所有连接状态变化都通过此方法通知,需根据事件类型进行不同处理</p>
*
* @param conn 当前连接对象
* @param event 发生的事件类型(枚举值)
*/
@Override
public void connectionEvent(Connection conn, Events event) {
// 获取连接标识信息
String connName = conn.getOptions().getConnectionName();
String server = conn.getConnectedUrl();
// 根据事件类型执行不同处理逻辑
switch (event) {
case CONNECTED:
onConnected(connName, server);
break;
case DISCONNECTED:
onDisconnected(connName, server);
break;
case RECONNECTED:
onReconnected(connName, server);
break;
case CLOSED:
onClosed(connName);
break;
case RESUBSCRIBED:
onResubscribed(connName);
break;
case DISCOVERED_SERVERS:
onDiscoveredServers(conn, connName);
break;
case LAME_DUCK:
onLameDuck(connName);
break;
default:
log.warn("[{}] 收到未处理事件: {}", connName, event);
}
// 记录连接事件指标
recordConnectionMetrics(event, connName);
}
//=== 事件处理私有方法 ===//
private void onConnected(String connName, String server) {
log.info("[{}] 成功连接到服务器: {}", connName, server);
// 连接建立后恢复消息处理
}
private void onDisconnected(String connName, String server) {
log.warn("[{}] 连接断开! 最后连接服务器: {}", connName, server);
// 断开时暂停消息处理防止积压
// 记录断开连接的服务器
}
private void onReconnected(String connName, String server) {
log.info("[{}] 成功重连到服务器: {}", connName, server);
// 重连后恢复处理并重发未确认消息
// 更新活动服务器
}
private void onClosed(String connName){
log.info("[{}] 连接已永久关闭", connName);
// 释放连接相关资源
}
private void onResubscribed(String connName) {
log.debug("[{}] 所有订阅已重新建立", connName);
// 确保消息处理状态同步
}
private void onDiscoveredServers(Connection conn, String connName) {
// 获取发现的服务器列表
Collection<String> servers = conn.getServers();
log.info("[{}] 发现 {} 个服务器节点: {}",
connName, servers.size(), String.join(", ", servers));
// 更新服务器集群信息
}
private void onLameDuck(String connName) {
log.warn("[{}] 服务器进入维护模式(Lame Duck Mode)", connName);
// 准备优雅停止消息处理
}
//=== 辅助方法 ===//
private void recordConnectionMetrics(Events event, String connName) {
// 实现指标记录逻辑
}
}
2.2.2 ErrorListener - 错误事件监听器
用于处理连接中的错误和异常:
代码示例
package org.example.natsdemo.Listener;
import io.nats.client.ErrorListener;
import io.nats.client.*;
import lombok.extern.slf4j.Slf4j;
import io.nats.client.support.Status;
/**
* NATS错误事件监听器实现
* 处理NATS客户端运行过程中可能发生的各类错误和异常事件
*/
@Slf4j
public class CustomErrorListener implements ErrorListener {
/**
* 通用错误事件处理
* @param conn 当前NATS连接对象
* @param error 错误描述信息
*/
@Override
public void errorOccurred(Connection conn, String error) {
log.info("[通用错误] 连接 {}: {}", conn.getServerInfo(), error);
// 此处可添加:错误计数器、通知系统等逻辑
}
/**
* 未捕获异常处理
* @param conn 当前NATS连接对象
* @param exp 发生的异常对象
*/
@Override
public void exceptionOccurred(Connection conn, Exception exp) {
log.error("[未捕获异常] 连接 {}: {} - {}",
conn.getServerInfo(), exp.getClass().getSimpleName(), exp.getMessage());
// 此处可添加:异常恢复、重连机制等
}
/**
* 慢消费者检测(消费者处理速度跟不上消息生产速度)
* @param conn 当前NATS连接对象
* @param consumer 相关的消费者对象
*/
@Override
public void slowConsumerDetected(Connection conn, Consumer consumer) {
log.warn("[慢消费者] 连接 {}: 消费者类型 - {}",
conn.getServerInfo(), consumer.getClass().getSimpleName());
// 此处可添加:自动扩容消费者实例、优化处理逻辑等
}
/**
* 消息丢弃事件(通常因队列满或超时导致)
* @param conn 当前NATS连接对象
* @param msg 被丢弃的消息对象
*/
@Override
public void messageDiscarded(Connection conn, Message msg) {
log.warn("[消息丢弃] 连接 {}: 主题 '{}' | 消息大小: {} 字节",
conn.getServerInfo(), msg.getSubject(), msg.getData().length);
// 此处可添加:死信队列处理、丢弃消息统计等
}
/**
* 心跳告警(JetStream心跳包未按时到达)
* @param conn 当前NATS连接对象
* @param sub 相关的JetStream订阅
* @param lastStreamSequence 最后接收的流序列号
* @param lastConsumerSequence 最后接收的消费者序列号
*/
@Override
public void heartbeatAlarm(Connection conn, JetStreamSubscription sub,
long lastStreamSequence, long lastConsumerSequence) {
log.error("[心跳告警] 连接 {}: 订阅主题 '{}' | 流序列号: {} | 消费者序列号: {}",
conn.getServerInfo(), sub.getSubject(), lastStreamSequence, lastConsumerSequence);
// 此处可添加:连接健康检查、订阅重建等
}
/**
* 未处理状态码(服务器返回未处理的状态)
* @param conn 当前NATS连接对象
* @param sub 相关的JetStream订阅
* @param status 服务器返回的状态对象
*/
@Override
public void unhandledStatus(Connection conn, JetStreamSubscription sub, Status status) {
log.warn("[未处理状态] 连接 {}: 状态码 {} - {}",
conn.getServerInfo(), status.getCode(), status.getMessage());
// 此处可添加:特定状态码的自定义处理
}
/**
* Pull模式警告(非致命性问题)
* @param conn 当前NATS连接对象
* @param sub 相关的JetStream订阅
* @param status 警告状态对象
*/
@Override
public void pullStatusWarning(Connection conn, JetStreamSubscription sub, Status status) {
log.warn("[Pull警告] 连接 {}: 状态码 {} - {}",
conn.getServerInfo(), status.getCode(), status.getMessage());
// 此处可添加:警告级别监控告警
}
/**
* Pull模式错误(致命性问题)
* @param conn 当前NATS连接对象
* @param sub 相关的JetStream订阅
* @param status 错误状态对象
*/
@Override
public void pullStatusError(Connection conn, JetStreamSubscription sub, Status status) {
log.error("[Pull错误] 连接 {}: 状态码 {} - {}",
conn.getServerInfo(), status.getCode(), status.getMessage());
// 此处可添加:错误恢复或订阅重置
}
/**
* 流控处理完成(JetStream流量控制机制触发)
* @param conn 当前NATS连接对象
* @param sub 相关的JetStream订阅
* @param subject 触发流控的主题
* @param source 流控来源(HEARTBEAT或FLOW_CONTROL)
*/
@Override
public void flowControlProcessed(Connection conn, JetStreamSubscription sub,
String subject, FlowControlSource source) {
log.info("[流控处理] 连接 {}: 来源={} | 主题={}",
conn.getServerInfo(), source.name(), subject);
// 此处可添加:流量监控指标收集
}
}
-
核心错误处理
方法 触发场景 关键处理 errorOccurred()
协议级错误 权限监控、安全告警 exceptionOccurred()
系统级异常 熔断触发、网络监控 slowConsumerDetected()
消息积压 自动扩容、流控调整 -
JetStream 专用处理
方法 触发场景 关键处理 heartbeatAlarm()
心跳超时 消费者重启、心跳重置 pullStatusWarning()
拉取警告 策略调整 pullStatusError()
拉取错误 消费者重建 flowControlProcessed()
流控生效 参数优化 -
消息生命周期
方法 触发场景 关键处理 messageDiscarded()
消息丢弃 死信队列处理 unhandledStatus()
未知状态 协议监控
2.3 安全认证配置
Token 认证
Options options = new Options.Builder()
.token("your-auth-token")
.build();
用户名/密码认证
Options options = new Options.Builder()
.userInfo("username", "password")
.build();
TLS 加密
Options options = new Options.Builder()
.sslContext(createCustomSslContext()) // 自定义 SSLContext
.build();
2.4 自定义SSLContext
二、NATS 消息模型
2.1 发布/订阅 (Pub-Sub)
-
创建消息发布客户端
@Slf4j @Component public class NatsPublisherClient { @Autowired private Connection natsConnection; public void publishMessage(String subject, String message) { natsConnection.publish(subject, message.getBytes()); log.info("已发布消息到主题[{}]: {}", subject, message); } }
-
创建消息订阅服务
@Slf4j @Service public class NatsSubscriberService { private final String subject = "subject.pubsub"; @Autowired private Connection natsConnection; @PostConstruct public void subscribe() { Dispatcher dispatcher = natsConnection.createDispatcher(msg -> {}); dispatcher.subscribe(subject, (msg) -> { String message = new String(msg.getData()); log.info("接收到来自主题[{}]的消息: {}", subject, message); // 这里可以添加消息处理逻辑 }); log.info("已订阅主题: {}", subject); } }
-
创建测试控制器
@RestController public class TestController { @Autowired NatsPublisherClient natsPublisherClient; /** * NATS消息模型-pub_sub */ @PostMapping("/pubsub") public String pubSub(String msg) { natsPublisherClient.publishMessage("subject.pubsub", msg); return "ok"; } }
2.2 请求/响应 (Request-Reply)
Request-Reply 是 NATS 提供的另一种通信模式,它允许客户端发送请求并等待响应,类似于 HTTP 的请求/响应模型,但基于消息系统实现。
Request-Reply 模型特点
- 同步通信:发送方会等待响应
- 临时主题:NATS 自动创建临时主题用于响应
- 超时机制:可以设置等待响应的超时时间
- 一对一通信:一个请求对应一个响应
-
添加 Reply 服务端
@Slf4j @Service public class NatsReplyService { private String subject = "subject.request"; private final Connection natsConnection; @Autowired public NatsReplyService(Connection natsConnection) { this.natsConnection = natsConnection; } @PostConstruct public void init() { Dispatcher dispatcher = natsConnection.createDispatcher(msg -> { String request = new String(msg.getData()); String replySubject = msg.getReplyTo(); if (replySubject != null) { String response = "处理后的响应: " + request.toUpperCase(); natsConnection.publish(replySubject, response.getBytes()); log.info("已处理请求并返回响应 - 请求内容: {}, 响应内容: {}", request, response); } }); dispatcher.subscribe(subject); log.info("Request-Reply 服务已启动,监听主题: {}", subject); } }
-
添加 Request 客户端
@Slf4j @Component public class NatsRequestClient { @Autowired private Connection natsConnection; public String sendRequest(String subject, String requestData)throws InterruptedException { log.info("发送请求到主题[{}], 请求内容: {}", subject, requestData); // 发送请求并等待响应(设置5秒超时) Message response = natsConnection.request(subject, requestData.getBytes(), Duration.ofSeconds(5)); if (response != null) { String responseData = new String(response.getData()); log.info("接收到响应: {}", responseData); return responseData; } else { log.warn("请求超时,未收到响应"); return "请求超时"; } } }
-
创建测试控制器
@RestController public class TestController { @Autowired NatsRequestClient natsRequestClient; /** * NATS消息模型-Request-Reply */ @PostMapping("/requestReply") public String requestReply(String msg) throws InterruptedException { return natsRequestClient.sendRequest("subject.request", msg); } }
2.3 队列组 (Queue Groups)
队列组是 NATS 提供的一个强大功能,它允许多个订阅者组成一个组,共同消费同一个主题的消息,实现负载均衡和消息的分布式处理。
队列组核心概念
- 负载均衡:消息会自动在组内成员间分配
- 消息独占性:每条消息只会被组内的一个订阅者接收
- 高可用性:组内成员可以动态加入或离开
- 同组竞争:同一组的订阅者竞争消费消息
- 不同组独立:不同组的订阅者各自独立接收全部消息
队列组 vs 普通订阅
特性 | 普通订阅 | 队列组订阅 |
---|---|---|
消息分发 | 所有订阅者都收到相同消息 | 每条消息只发给组内一个订阅者 |
负载均衡 | 无 | 自动负载均衡 |
订阅者关系 | 独立 | 属于同一个逻辑组 |
适用场景 | 广播通知 | 任务分发、工作队列 |
实现步骤
-
创建队列组消费者服务
@Slf4j @Service public class NatsQueueGroupService { private static final String QUEUE_SUBJECT = "subject.queue"; private static final String QUEUE_GROUP = "order-processors"; @Autowired private Connection natsConnection; @PostConstruct public void init() { // 创建第一个队列消费者 createQueueConsumer("消费者-1"); // 创建第二个队列消费者 createQueueConsumer("消费者-2"); } private void createQueueConsumer(String consumerName) { Dispatcher dispatcher = natsConnection.createDispatcher(msg -> { String message = new String(msg.getData()); log.info("[{}] 处理消息: {}", consumerName, message); // 模拟处理耗时 try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } log.info("[{}] 完成处理消息: {}", consumerName, message); }); dispatcher.subscribe(QUEUE_SUBJECT, QUEUE_GROUP); log.info("[{}] 已加入队列组 {}, 监听主题 {}", consumerName, QUEUE_GROUP, QUEUE_SUBJECT); } }
-
消息发布客户端
@Slf4j @Component public class NatsPublisherClient { @Autowired private Connection natsConnection; public void publishToQueue(String subject, String message) { natsConnection.publish(subject, message.getBytes()); log.info("已发布消息到队列主题[{}]: {}", subject, message); } }
-
测试控制器
@RestController public class TestController { @Autowired NatsPublisherClient natsPublisherClient; @PostMapping("/queue") public String sendToQueue(String msg) { natsPublisherClient.publishToQueue("subject.queue", msg); return "ok"; } }
三,NATS核心组件
3.1 Message对象
在 Java 中,Message 对象是 io.nats.client.Message
类,主要包含以下内容:
public class Message {
public String getSubject(); // 获取消息主题
public String getReplyTo(); // 获取回复地址
public byte[] getData(); // 获取原始字节数据
public Headers getHeaders(); // 获取消息头(NATS 2.0+)
public Subscription getSubscription(); // 获取关联的订阅
}
常用用法:
// 创建带头的消息
Headers headers = new Headers();
headers.add("Priority", "high");
headers.add("User", "alice","tom","jack");//消息头可以是数组
// 使用MessageBuilder构建消息
Message msg = NatsMessage.builder()
.subject("orders.new")//必填
.data("order content")//必填
.headers(headers)//选填
.replayTo("replay.Subject")// 指定回复主题,不建议手动指定。
.build();
nc.publish(msg);
// 读取消息头
Dispatcher dispatcher = natsConnection.createDispatcher();
dispatcher.subscribe(subject, (msg) -> {
Headers header = msg.getHeaders();
List<String> header1 = header.get("User");//获取所有匹配的键值
String header2 = header.getFirst("Priority");//获取第一个匹配的键值
String header3 = header.getLast("User");//获取最后一个匹配的键值
List<String> header4 = header.getIgnoreCase("User");//忽略大小写获取所有键值,忽略的是key的大小写
byte[] serialized = header.getSerialized();//获取消息头的原始字节流表示
String message = new String(msg.getData());
log.info("接收到来自主题[{}]的消息: {}", subject, message);
});
3.2 Subscription
Subscription(订阅)是 NATS 客户端中接收消息的核心机制,在 jnats (Java NATS 客户端) 中有多种订阅类型和使用方式。
Subscription 类型
-
同步订阅 (SyncSubscription)
// 创建同步订阅 Subscription sub = nc.subscribe("updates"); // 接收消息(阻塞式) Message msg = sub.nextMessage(Duration.ofSeconds(5)); // 接收消息(无限等待) Message msg = sub.nextMessage(Duration.ZERO); // 或 sub.nextMessage(null)
-
异步订阅 (通过Dispatcher)
// 创建Dispatcher订阅 Dispatcher dispatcher = nc.createDispatcher((msg) -> { System.out.println("收到消息: " + new String(msg.getData())); }); // 添加订阅到Dispatcher dispatcher.subscribe("updates");
-
队列订阅
// 同步队列订阅 Subscription sub = nc.subscribe("tasks", "worker-pool"); // 异步队列订阅 dispatcher.subscribe("tasks", "worker-pool");
Subscription 核心方法
-
消息接收
// 同步接收(带超时) Message msg = sub.nextMessage(Duration.ofSeconds(1)); // 检查是否有待处理消息 long pending = sub.getPendingMessageCount(); if (pending > 0) { Message msg = sub.nextMessage(Duration.ZERO); }
-
订阅管理
// 取消订阅 sub.unsubscribe(); // 带最大消息数的自动取消 Subscription sub = nc.subscribe("updates"); sub.unsubscribe(100); // 收到100条消息后自动取消 // 检查订阅是否有效 if (sub.isActive()) { // 订阅仍然活跃 }
-
流量控制
// 设置待处理消息限制 sub.setPendingLimits(1000, 10 * 1024 * 1024); // 1000条或10MB // 获取当前待处理消息状态 long pendingMessageCount = sub.getPendingMessageCount();//当前待处理的消息数量 long pendingMessageLimit = sub.getPendingMessageLimit();//订阅允许的最大待处理消息数 long pendingByteCount = sub.getPendingByteCount();//当前待处理消息的总字节数 long pendingByteLimit = sub.getPendingByteLimit();//订阅允许的最大待处理字节数
-
订阅监控
// 获取订阅统计信息 long droppedCount = subscribe.getDroppedCount();//已丢弃的消息数 long deliveredCount = subscribe.getDeliveredCount();//已处理的消息数 // 获取关联的主题 String subject = sub.getSubject(); // 获取队列组名称(如果有) String queue = sub.getQueueName();
3.3 MessageHandler
MessageHandler 是 jnats (Java NATS 客户端) 中用于异步处理消息的核心接口,它定义了如何处理接收到的 NATS 消息。
基本概念
MessageHandler 是一个函数式接口,只有一个抽象方法:
@FunctionalInterface
public interface MessageHandler {
void onMessage(Message msg) throws InterruptedException;
}
基本用法
-
使用 Lambda 表达式
// 最简单的形式 MessageHandler handler = (msg) -> { System.out.println("收到消息: " + new String(msg.getData())); }; // 注册到Dispatcher Dispatcher dispatcher = nc.createDispatcher(handler); dispatcher.subscribe("updates");
-
使用方法引用
public class MessageProcessor {
public void process(Message msg) {
System.out.println("处理消息: " + new String(msg.getData()));
}
}
MessageProcessor processor = new MessageProcessor();
Dispatcher dispatcher = nc.createDispatcher(processor::process);
dispatcher.subscribe("orders");
-
使用匿名类
Dispatcher dispatcher = nc.createDispatcher(new MessageHandler() { @Override public void onMessage(Message msg) throws InterruptedException { System.out.println("主题: " + msg.getSubject()); System.out.println("内容: " + new String(msg.getData())); } }); dispatcher.subscribe("logs");
3.3 Dispatcher
Dispatcher 是 jnats (Java NATS 客户端) 中用于异步消息处理的核心组件,它允许高效地处理多个订阅的消息而无需手动管理线程。
Dispatcher 的主要特点:
- 为异步消息处理提供统一的消息分发机制
- 可以管理多个订阅
- 自动处理消息回调的线程管理
- 支持流量控制(节流)
创建和使用 Dispatcher
-
创建和使用 Dispatcher
Connection nc = Nats.connect("nats://localhost:4222"); // 创建 Dispatcher 并定义消息处理器 Dispatcher dispatcher = nc.createDispatcher((msg) -> { System.out.println("收到消息 [" + msg.getSubject() + "] : " + new String(msg.getData())); }); // 添加订阅 dispatcher.subscribe("updates"); dispatcher.subscribe("notifications"); // 也可以取消订阅 dispatcher.unsubscribe("updates");
-
带队列组的订阅
Dispatcher dispatcher = nc.createDispatcher((msg) -> { System.out.println("Worker 处理: " + new String(msg.getData())); }); // 加入队列组实现负载均衡 dispatcher.subscribe("tasks", "worker-pool");
-
使用多个 Dispatcher
// 创建专门处理订单的 Dispatcher Dispatcher orderDispatcher = nc.createDispatcher((msg) -> { // 处理订单逻辑 }); // 创建专门处理日志的 Dispatcher Dispatcher logDispatcher = nc.createDispatcher((msg) -> { // 处理日志逻辑 }); orderDispatcher.subscribe("orders.*"); logDispatcher.subscribe("logs.*");
Dispatcher 高级功能
-
流量控制(节流)
Options options = new Options.Builder() .server("nats://localhost:4222") .connectionListener((conn, type) -> System.out.println("连接状态: " + type)) .build(); Connection nc = Nats.connect(options); // 创建带节流的 Dispatcher (每秒最多处理100条消息) Dispatcher throttledDispatcher = nc.createDispatcher((msg) -> { // 处理消息 System.out.println("处理消息: " + new String(msg.getData())); }); // 设置节流参数 (消息数/时间间隔) throttledDispatcher.setPendingLimits(100, 1000); // 100条/秒 throttledDispatcher.subscribe("high.volume");
-
错误处理
Dispatcher dispatcher = nc.createDispatcher(new MessageHandler() {
@Override
public void onMessage(Message msg) throws InterruptedException {
try {
// 处理消息
processMessage(msg);
} catch (Exception e) {
System.err.println("处理消息失败: " + e.getMessage());
// 可以选择重试或记录错误
}
}
});
dispatcher.subscribe("sensitive.data");
Dispatcher 生命周期管理
- 关闭 Dispatcher
// 关闭特定 Dispatcher 的所有订阅
dispatcher.unsubscribeAll();
// 或者通过关闭连接来关闭所有 Dispatcher
nc.close();
-
状态检测
// 检查 Dispatcher 是否活跃 if (!dispatcher.isActive()) { System.out.println("Dispatcher 已关闭"); } // 获取 Dispatcher 管理的订阅数 int subCount = dispatcher.getSubscriptionCount();