什么是云原生消息系统?
云原生消息系统是一种为云计算环境优化的消息传递解决方案,支持微服务架构和容器化部署,提供高可扩展性、弹性和可靠性。
微服务架构的负担
微服务架构虽然带来了模块化、可伸缩性和高容错性等优点,但也引入了一系列挑战和额外的复杂度。以下是微服务架构的一些需要处理的机制:
-
服务注册和服务发现
- 服务实例需要能够相互发现和通信。这需要一个服务注册中心来记录服务的位置信息,以便其他服务能够找到并调用它们。
-
负载均衡
- 在高并发请求下,单个服务可能无法处理巨大的负载,需要将请求分散到多个处理节点上,以提高系统的吞吐量。
-
熔断
- 当一个服务失败时,它会迅速传播到其他服务,导致整个系统的性能下降,需要设置一个熔断机制让服务调用可以快速失败,避免服务出现级联错误。
-
降级
- 当服务不可用或响应时间过长时,需要提供一个备选方案来处理请求,以保证系统的可用性。
-
重试
- 在分布式系统中,服务可能会因为各种原因(如网络闪断、垃圾回收、线程死锁、资源不足等)出现不可用的情况,需要处理服务调用的重试机制,以提高系统的容错率。
-
配置管理
- 需要管理分布式系统中各个服务的配置,确保配置的一致性和动态更新。
-
分布式事务
- 一个完整的业务操作可能需要跨多个服务、访问多个数据库来完成。为了保证这些操作要么全部成功,要么全部失败,以保持数据的一致性,需要集成分布式事务机制。
-
链路追踪
- 一个业务请求可能涉及多个服务,需要一个能追踪请求在各个服务间的流动的分析机制,以帮助开发者快速定位错误位置和性能瓶颈。
什么是NATS?
NATS
是一个开源的、轻量级、高性能的分布式云原生消息传递系统,它基于发布/订阅模式,适用于构建分布式和微服务应用程序。NATS提供了一种简单、可靠、高效的方式来传递信息,具有良好的可扩展性和容错性。
NATS的核心特性
- 高性能:NATS能够达到每秒数百万个消息的处理能力,具有低延迟和高吞吐量。
- 轻量级:NATS服务器程序很小,只有3M,易于部署和维护。
- 可扩展性:NATS支持集群模式,可以跨多个服务器进行扩展,提高性能和容错能力。
- 发布/订阅模式:NATS的核心是一个发布/订阅消息传递系统,允许消息生产者发布消息到特定的主题,而消息消费者可以订阅感兴趣的主题来接收消息。
- 请求/响应模式:NATS支持请求/响应模式,允许客户端发送请求消息并等待服务器的响应。
- 集群模式:NATS支持集群模式,允许跨多个服务器进行扩展。
- 持久化:NATS Streaming提供了消息持久化的功能,确保即使在服务器重启后,消息也不会丢失。
- 安全性:NATS支持多种安全机制,包括TLS加密、用户认证和授权等。
NATS 消息传递系统通过其设计和特性,可以有效地解决微服务架构中的一些关键问题:
-
服务发现:
- 在NATS中,服务通过发布消息到主题或订阅主题来交换信息,而不是直接调用彼此的接口。
-
负载均衡:
- NATS支持发布/订阅模式,允许多个订阅者使用相同的队列名称订阅同一个主题。NATS 会将消息分发给这些订阅者中的一个,实现负载均衡。
-
熔断:
- NATS可以通过合理的设计来实现熔断机制。例如,可以设置消息重试次数和超时时间,当达到一定条件时,停止向问题服务发送消息,从而避免级联故障。
-
降级:
- NATS可以通过设置备选的消息处理器来实现降级策略。如果主服务不可用,NATS可以将消息路由到备用服务,确保系统继续提供服务。
-
重试:
- NATS可以配置重试机制,支持请求/响应模式,如果消费者未能处理消息,消息可以被重新发送。
-
配置管理:
- NATS服务器和客户端的配置可以通过配置文件或环境变量来管理。对于动态配置更新,可以结合配置管理工具(如Spring Cloud Config)和NATS实现配置的动态下发。
-
分布式事务:
- NATS JetStream提供了消息流的持久化和高级消息传递语义,包括至少一次(at-least-once)和有条件的精确一次(exactly-once)交付语义。这使得 JetStream 能够支持事务型消息的处理,可以通过与其他工具(如数据库事务管理器、分布式事务协调器等)结合使用来实现跨服务的事务管理。
-
链路追踪:
- NATS监控系统可以简单地以另一个NATS客户端的形式实现,订阅特定的监控主题,接收服务器状态更新,NATS也可以和链路追踪工具(如OpenTelemetry、Jaeger等)集成,通过在消息传递过程中添加追踪信息,实现请求在各个服务间的流动追踪。
使用NATS
NATS
是与语言无关的,它支持多种编程语言的客户端库,方便开发者集成。以下是 NATS 支持的一些语言:
- Go:NATS是用 Go 语言实现的,其官方 Go 客户端库的支持非常成熟 。
- Java:官方提供了 NATS 的 Java 客户端 。
- Python:官方有 Python 的支持库,性能较好 。
- C/C++ :NATS 提供 C 和 C++ 的原生支持库 。
- Node.js:官方支持,适合 Node.js 环境使用 。
- Rust、Ruby、C# 、PHP、Elixir 等:NATS 也支持这些语言,提供了官方或社区维护的客户端库 。
在TypeScript中使用NATS
import { NatsConnection, StringCodec, connect } from 'nats';
async function main() {
try {
// 连接到运行在localhost的NATS服务器
const nc: NatsConnection = await connect({ servers: ['nats://localhost:4222'] });
console.log('Connected to NATS server');
// 创建一个字符串消息编解码器
const sc = StringCodec();
// 订阅主题
const sub = nc.subscribe("test");
(async () => {
for await (const m of sub) {
console.log(`[${sub.getProcessed()}]: ${sc.decode(m.data)}`);
}
console.log("subscription closed");
})();
// 发布消息到主题
nc.publish('test', Buffer.from('Hello'));
nc.publish('test', Buffer.from('World'));
// 等待所有消息被排空后关闭连接
await nc.drain();
} catch (error) {
console.error('Error connecting to NATS:', error);
}
}
main();
NestJS
框架支持使用NATS
作为微服务的消息传输器
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.NATS,
options: {
servers: ['nats://localhost:4222'],
},
});
@MessagePattern('notifications')
getNotifications(@Payload() data: number[], @Ctx() context: NatsContext) {
console.log(`Subject: ${context.getSubject()}`);
}
Headers
NATS
中的headers功能类似于HTTP headers,它们以键值对的形式提供额外的元数据。Headers在NATS
中扮演了多重角色,以下是它们的主要作用:
-
去重(De-duplication) :
- 客户端可以在发布消息时设置
Nats-Msg-Id
header,服务器会使用这个ID在配置的重复窗口内应用去重逻辑,确保消息不会被重复处理。
- 客户端可以在发布消息时设置
-
自动清除消息(Auto-purging of messages) :
- 通过设置
Nats-Rollup
header,可以清除流中或主题级别上的所有先前消息。
- 通过设置
-
元数据传递(Metadata from republished messages) :
- 当消息被重新发布时,NATS会设置一系列headers,如
Nats-Stream
、Nats-Subject
、Nats-Sequence
等,以保留原始消息的元数据。
- 当消息被重新发布时,NATS会设置一系列headers,如
-
乐观并发控制(Optimistic concurrency control) :
- 通过
Nats-Expected-Last-Msg-Id
、Nats-Expected-Last-Sequence
和Nats-Expected-Last-Subject-Sequence
headers,可以实现流级别或主题级别的乐观并发控制。
- 通过
-
消息来源(Sources) :
- 当消息从其他流中被源起时,
Nats-Stream-Source
header会指定原始流的名称、主题和序列号,以及消息的主题过滤器和目的地转换。
- 当消息从其他流中被源起时,
-
内部流控制(Internal flow-control messages for a mirror) :
- 在NATS的镜像功能中,headers用于内部流控制消息。
-
消息大小(Message size) :
- 当消费者配置为仅接收headers时,
Nats-Msg-Size
header指示消息体的大小(以字节为单位)。
- 当消费者配置为仅接收headers时,
import * as nats from 'nats';
const headers = nats.headers();
headers.set('x-version', '1.0.0');
const record = new NatsRecordBuilder(':cat:').setHeaders(headers).build();
this.client.send('replace-emoji', record).subscribe(...);
@MessagePattern('replace-emoji')
replaceEmoji(@Payload() data: string, @Ctx() context: NatsContext): string {
const headers = context.getHeaders();
return headers['x-version'] === '1.0.0' ? '🐱' : '🐈';
}
总结
NATS
作为一个高性能、轻量级、可扩展的云原生消息系统,为微服务架构提供了强大的消息传递能力。它通过支持服务发现、负载均衡、熔断、降级、重试等机制,有效地解决了微服务架构中的通信和可靠性挑战。NATS
的跨语言支持和headers功能进一步增强了其在构建分布式系统中的灵活性和效率。因此,NATS
成为了现代云原生应用开发中不可或缺的消息传递解决方案,帮助开发者构建更加健壮、可维护和可扩展的系统。