Raft

Nats设计与实现

NATS设计与实现 #

NATS 就是一个消息中间件,提供了 Pub/Sub 核心数据流,并基于此构建了 Request/Reply API 和 JetStream 用来提供可靠的分布式存储能力,和更高的 QoS(至少一次 + ACK)。

1. 核心概念 #

序号 名词(ENG) 名词(zh-CN) 解释
1 Publish 发布 发布动作,往 subject 中投递一条消息
2 Subscribe 订阅 订阅动作,表示想要接受发布相应 subject 的消息
3 Subject 主题 唯一标识,用于标识一种或者一类事件的概念。订阅时,可以使用 nats 约定的通匹配符来接收一类 subjects,如 orders.> 。
4 Core Nats NATS 核心 CORE NATS 提供了以下能力:

- PUB / SUB https://docs.nats.io/nats-concepts/core-nats/pubsub

- Request / Reply https://docs.nats.io/nats-concepts/core-nats/reqreply

- Queue Groups https://docs.nats.io/nats-concepts/core-nats/queue


提供 最多一次 的消息传递保证
5 Request / Reply 请求 / 回复 NATS 基于 PUB / SUB 实现的对 request 异步回复的功能,依赖于消息中的 reply 字段。reply 是内置实现,随机生成一个 “inbox” subject。



订阅者中间也是存在 Queue Group 概念的。

注意:发起 request 如果没有reply,那么服务端会返回 No Responders 消息。
6 Queue groups 队列组 订阅者使用同一个队列名称,它们就会成为一个队列组。每次队列组接收到消息时,只有队列组中_随机选择_的一个订阅者会消费一条消息,内置的负载均衡。
7 Message 消息 or 事件 一条消息包含了以下内容:

- Subject.

- A payload in the form of a byte array.

- Any number of header fields.

- An optional ‘reply’ address field.
8 Subject wildcards

https://docs.nats.io/nats-concepts/subjects#wildcards
主题通配符 订阅者可以使用这些通配符_通过单个订阅收听多个主题。_

注意:但发布者将始终使用完全指定的主题,而不使用通配符。
9 JetStream

https://docs.nats.io/nats-concepts/jetstream
无 / 流 NATS 中一个功能特性,它是一个内置的分布式存储,在 CORE nats 的基础上扩展了更多的功能和更高的 QoS。功能上:

- Stream:将 NATS 消息存储在流中,提供多种保留策略、限制、丢弃策略和主题映射功能。

- Consumer: 让客户端应用订阅或拉取流中的消息,支持多种重放策略、确认机制和流控功能

- Persistence: 将流的数据复制到多个 NATS 服务器,提供容错能力和加密存储功能

- KV Store: 可以将消息与键关联,提供存储、检索、删除和监听键值变化的功能。

- Object Store: JetStream 可以存储任意大小的对象(如文件),提供分块、校验和、元数据等功能。


其中最核心(开发常用)的概念就是:stream 和 consumer。
10 Stream

https://docs.nats.io/nats-concepts/jetstream/streams
流即是消息存储,它定义了消息的存储方式以及保留的限制。

更具体的内容参见 #5.1 Stream 配置解析
11 Consumer 消费者 消费者作为客户端的接口,使用存储在流中的消息,跟踪客户端传递和确认的消息。Nats 同时支持 pullpush 两种消费模式;consumer 还提供了 durable 配置,用于持久化 consumer 消费信息(除非设置了 InactiveThreshold)

更具体的内容参见 #5.2 Consumer 配置解析
12 Replay / Redelivery
13 Raft Group



https://docs.nats.io/running-a-nats-service/configuration/clustering/jetstream_clustering
RAFT 组 对于特定内容达成一致的分组,nats 中有 meta, stream, consumer 几种组。

Meta: 全部节点都是组成员。负责:JetStream API + 集群管理。



Stream: (根据 replicas 配置选择组内的服务器成员)。负责:stream 数据



Consumer: (根据 stream group的成员来确定消费者组内的成员)。负责:消费者状态

14 KV Store 键值存储
15 Object Store 对象存储

2. 软件架构(集群模式) #

Nats 自身是提供了多种运行方式:

...

设计一个分布式定时任务系统

需求和背景分析 #

一提到定时任务的使用场景,我们肯定能想到很多场景,比如:

  • 每天晚上12点执行一次清理数据的任务
  • 每天凌晨1点给符合条件的用户发送推广邮件
  • 每个月10号结算工资
  • 每隔5分钟检查一次服务器的状态
  • 每天根据用户的配置,给用户发送站内消息提醒

从常见的场景中,我们可以提炼出一些定时任务的特点:

序号 特点 说明
1 定时 执行时间有规则
2 可靠 可以延迟执行,但不能不执行;可以不执行,但是不能多执行
3 并发(可能) 某些场景下,可以运行多个 cron 进程来提高执行效率
4 可执行 这个有点废话了,但是这个关系到 cronjob 的设计,因此在这里还是提出来

但是作为一个系统来说,我们需要更多的功能来提升用户体验,保证平台的可靠和稳定。我们设想下以下的场景:

  • 定时任务已经触发了,但是有没有执行,执行结果是什么?
  • 如果一个定时任务长时间运行,那么它正常吗?
  • 一个定时任务还在运行,但是下一个触发时机又到来了,该怎么办?
  • 如果服务器资源已经处于高位,那么要被触发的任务还触发吗?

最后,基本的访问控制,权限分配和API设计,这些都是系统功能的一部分,但不作为本文的重点考虑对象。

一些概念 #

到这里我们可以提取一些概念,来帮助我们设计一个系统:

序号 名词 解释
1 CronJob 定时任务实例,描述定时任务资源的一个实体
2 Job 执行中的定时任务
3 Scheduler 调度器,负责触发 CronJob 执行和监控 Job 的执行状态;或许还会存储一些 CronJob 的状态
4 JobRuntime job 运行时,准备 Job 运行时需要的资源; 可以参考 k8s CRI

这里 JobRuntime 是抽象化的概念,因为 Job 可以是k8s上的POD,也可以是物理机的进程,还可以是一个进程中的coroutine。

...

访问量 访客数