消息序列化和时间戳

序列化和时间戳是所有服务总线实体上始终启用的两项功能,通过收到或检索到的消息的 Sequence​NumberEnqueuedTimeUtc 属性体现。

如果消息的绝对顺序至关重要,和/或使用者需要消息的可信唯一标识符,中转站会向消息分发相对于队列或主题的无间隔递增序列号。 对于已分区实体,序列号是相对于分区进行分发。

序列号

SequenceNumber 值是在代理接受并存储消息时分配给消息的唯一 64 位整数,可用作消息的内部标识符。 对于已分区实体,最前面的 16 位数反映的是分区标识符。 当 64 位或 48 位(不包括分区标识符的 16 位)范围耗尽时,序列号将滚动到零。

序列号可作为唯一标识符受到信任,因为它是由中央主管中立机构(而不是客户端)分配。 它还表示真正的到达顺序,比作为顺序条件的时间戳更为精确,因为时间戳在消息传递速度极快时的解析度可能不够高,并且可能会在代理所有权跨节点转让时受到时钟偏差的影响(虽然影响很小)。

绝对到达顺序非常重要。例如,在供货量有限的业务方案中,在供应期内货物供应遵循“先到先得”的原则;音乐会门票销售就是一个例子。

时间戳

时间戳功能将充当一个中立且值得信赖的机构,可准确捕获消息的到达时间 (UTC),并通过 EnqueuedTimeUtc 属性进行体现。 此值非常适用于依赖截止时间、但处理进度远远落后于队列积压工作 (backlog) 的业务方案,如需要确定工作项是否在特定日期的午夜前提交。

注意

序列号本身可以保证消息的排队顺序和提取程序顺序,但不能保证需要会话的处理顺序。

假设队列中有 5 条消息,有 2 个使用者。 使用者 1 选取消息 1。 使用者 2 选取消息 2。 使用者 2 完成对消息 2 的处理并选取消息 3,而使用者 1 尚未完成对消息 1 的处理。 使用者 2 完成对消息 3 的处理,但使用者 1 仍未完成对消息 1 的处理。 最后,使用者 1 完成对消息 1 的处理。 因此,消息按以下顺序进行处理:消息 2、消息 3 和消息 1。 如果需要按顺序处理消息 1、2 和 3,则需要使用会话。

因此,如果只需按顺序检索消息,则无需使用会话。 如果需要按顺序处理消息,请使用会话。 属于同一组的消息应设置相同的会话 ID,可以是一组中的消息1、4 和 8,也可以是另一组中的消息 2、3 和 6。

有关详细信息,请参阅服务总线消息会话

计划的消息

可以将消息提交到队列或主题以供延迟处理;例如,将作业安排为在特定时间可供系统处理。 此功能实现了可靠的分布式时间计划程序。

在定义的排队时间前,计划的消息不会在队列中具体化。 在此之前,可以取消计划的消息。 取消操作会将消息删除。

可以通过两种方式使用我们的任何客户端来计划消息:

  • 使用常规发送 API,但在发送之前设置消息上的 Scheduled​Enqueue​Time​Utc 属性。
  • 使用计划消息 API,同时传递常规消息和计划时间。 API 将返回计划消息的 SequenceNumber,以便稍后用于根据需要取消计划消息。

也可以使用消息浏览,发现计划的消息及其序列号。

只有当消息处于计划状态时,计划消息的 SequenceNumber 才有效。 当消息转换为活动状态时,消息就会被追加到队列中,就像瞬时排入队列一样,包括分配新的 SequenceNumber

因为此功能与各个消息绑定在一起,并且消息只能排入队列一次,所以服务总线不支持定期安排消息。

注意

  • 消息入队时间并不意味着将同时发送消息。 它将加入队列,但实际发送时间取决于队列的工作负载及其状态。
  • 出于性能考虑,定时消息的激活和取消是独立的操作,无需互相锁定。 如果在消息激活过程中取消消息,则不会撤回激活过程,消息仍会被激活。 此外,这可能会导致计划消息出现负计数。 为了最大程度地减少这种争用情况,建议避免在紧密连续的时间内安排激活和取消操作。

将计划消息与工作流结合使用

长期运行的业务工作流通常具有显式时间组件,例如双重身份验证具有 5 分钟超时,确认电子邮件地址的用户具有 1 小时超时,银行和保险等领域中有数天、数周或数月时间组件。

这些工作流通常在处理一些消息时启动,处理消息会存储一些状态,然后计划消息以在稍后时间继续执行进程。 通过 NServiceBusMassTransit 等框架,可以更轻松地将所有这些元素集成在一起。

若要了解有关服务总线消息传送的详细信息,请参阅以下主题: