云原生消息系统

33 阅读8分钟

什么是云原生消息系统?

云原生消息系统是一种为云计算环境优化的消息传递解决方案,支持微服务架构和容器化部署,提供高可扩展性、弹性和可靠性。

微服务架构的负担

微服务架构虽然带来了模块化、可伸缩性和高容错性等优点,但也引入了一系列挑战和额外的复杂度。以下是微服务架构的一些需要处理的机制:

  1. 服务注册和服务发现

    • 服务实例需要能够相互发现和通信。这需要一个服务注册中心来记录服务的位置信息,以便其他服务能够找到并调用它们。
  2. 负载均衡

    • 在高并发请求下,单个服务可能无法处理巨大的负载,需要将请求分散到多个处理节点上,以提高系统的吞吐量。
  3. 熔断

    • 当一个服务失败时,它会迅速传播到其他服务,导致整个系统的性能下降,需要设置一个熔断机制让服务调用可以快速失败,避免服务出现级联错误。
  4. 降级

    • 当服务不可用或响应时间过长时,需要提供一个备选方案来处理请求,以保证系统的可用性。
  5. 重试

    • 在分布式系统中,服务可能会因为各种原因(如网络闪断、垃圾回收、线程死锁、资源不足等)出现不可用的情况,需要处理服务调用的重试机制,以提高系统的容错率。
  6. 配置管理

    • 需要管理分布式系统中各个服务的配置,确保配置的一致性和动态更新。
  7. 分布式事务

    • 一个完整的业务操作可能需要跨多个服务、访问多个数据库来完成。为了保证这些操作要么全部成功,要么全部失败,以保持数据的一致性,需要集成分布式事务机制。
  8. 链路追踪

    • 一个业务请求可能涉及多个服务,需要一个能追踪请求在各个服务间的流动的分析机制,以帮助开发者快速定位错误位置和性能瓶颈。

什么是NATS?

NATS是一个开源的、轻量级、高性能的分布式云原生消息传递系统,它基于发布/订阅模式,适用于构建分布式和微服务应用程序。NATS提供了一种简单、可靠、高效的方式来传递信息,具有良好的可扩展性和容错性。

NATS的核心特性

  1. 高性能:NATS能够达到每秒数百万个消息的处理能力,具有低延迟和高吞吐量。
  2. 轻量级:NATS服务器程序很小,只有3M,易于部署和维护。
  3. 可扩展性:NATS支持集群模式,可以跨多个服务器进行扩展,提高性能和容错能力。
  4. 发布/订阅模式:NATS的核心是一个发布/订阅消息传递系统,允许消息生产者发布消息到特定的主题,而消息消费者可以订阅感兴趣的主题来接收消息。
  5. 请求/响应模式:NATS支持请求/响应模式,允许客户端发送请求消息并等待服务器的响应。
  6. 集群模式:NATS支持集群模式,允许跨多个服务器进行扩展。
  7. 持久化:NATS Streaming提供了消息持久化的功能,确保即使在服务器重启后,消息也不会丢失。
  8. 安全性:NATS支持多种安全机制,包括TLS加密、用户认证和授权等。

NATS 消息传递系统通过其设计和特性,可以有效地解决微服务架构中的一些关键问题:

  1. 服务发现

    • 在NATS中,服务通过发布消息到主题或订阅主题来交换信息,而不是直接调用彼此的接口。
  2. 负载均衡

    • NATS支持发布/订阅模式,允许多个订阅者使用相同的队列名称订阅同一个主题。NATS 会将消息分发给这些订阅者中的一个,实现负载均衡。
  3. 熔断

    • NATS可以通过合理的设计来实现熔断机制。例如,可以设置消息重试次数和超时时间,当达到一定条件时,停止向问题服务发送消息,从而避免级联故障。
  4. 降级

    • NATS可以通过设置备选的消息处理器来实现降级策略。如果主服务不可用,NATS可以将消息路由到备用服务,确保系统继续提供服务。
  5. 重试

    • NATS可以配置重试机制,支持请求/响应模式,如果消费者未能处理消息,消息可以被重新发送。
  6. 配置管理

    • NATS服务器和客户端的配置可以通过配置文件或环境变量来管理。对于动态配置更新,可以结合配置管理工具(如Spring Cloud Config)和NATS实现配置的动态下发。
  7. 分布式事务

    • NATS JetStream提供了消息流的持久化和高级消息传递语义,包括至少一次(at-least-once)和有条件的精确一次(exactly-once)交付语义。这使得 JetStream 能够支持事务型消息的处理,可以通过与其他工具(如数据库事务管理器、分布式事务协调器等)结合使用来实现跨服务的事务管理。
  8. 链路追踪

    • NATS监控系统可以简单地以另一个NATS客户端的形式实现,订阅特定的监控主题,接收服务器状态更新,NATS也可以和链路追踪工具(如OpenTelemetry、Jaeger等)集成,通过在消息传递过程中添加追踪信息,实现请求在各个服务间的流动追踪。

使用NATS

NATS是与语言无关的,它支持多种编程语言的客户端库,方便开发者集成。以下是 NATS 支持的一些语言:

  1. Go:NATS是用 Go 语言实现的,其官方 Go 客户端库的支持非常成熟 。
  2. Java:官方提供了 NATS 的 Java 客户端 。
  3. Python:官方有 Python 的支持库,性能较好 。
  4. C/C++ :NATS 提供 C 和 C++ 的原生支持库 。
  5. Node.js:官方支持,适合 Node.js 环境使用 。
  6. RustRubyC#PHPElixir 等: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中扮演了多重角色,以下是它们的主要作用:

  1. 去重(De-duplication)

    • 客户端可以在发布消息时设置Nats-Msg-Id header,服务器会使用这个ID在配置的重复窗口内应用去重逻辑,确保消息不会被重复处理。
  2. 自动清除消息(Auto-purging of messages)

    • 通过设置Nats-Rollup header,可以清除流中或主题级别上的所有先前消息。
  3. 元数据传递(Metadata from republished messages)

    • 当消息被重新发布时,NATS会设置一系列headers,如Nats-StreamNats-SubjectNats-Sequence等,以保留原始消息的元数据。
  4. 乐观并发控制(Optimistic concurrency control)

    • 通过Nats-Expected-Last-Msg-IdNats-Expected-Last-SequenceNats-Expected-Last-Subject-Sequence headers,可以实现流级别或主题级别的乐观并发控制。
  5. 消息来源(Sources)

    • 当消息从其他流中被源起时,Nats-Stream-Source header会指定原始流的名称、主题和序列号,以及消息的主题过滤器和目的地转换。
  6. 内部流控制(Internal flow-control messages for a mirror)

    • 在NATS的镜像功能中,headers用于内部流控制消息。
  7. 消息大小(Message size)

    • 当消费者配置为仅接收headers时,Nats-Msg-Size header指示消息体的大小(以字节为单位)。
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成为了现代云原生应用开发中不可或缺的消息传递解决方案,帮助开发者构建更加健壮、可维护和可扩展的系统。