跳到主要内容

队列

队列既作为发布保证消息的目的地,也作为客户端可以绑定消费者并消费消息的端点。队列通常用于点对点(PTP)消息传递环境以及发布/订阅(pub/sub)模型中。

队列比主题端点更加灵活,是大多数应用程序推荐的解决方案。

队列访问类型

队列具有访问类型,这决定了当多个消费者流程绑定到它时消息如何传递。队列可以被分配以下访问类型之一:

  • exclusive - 指定只有单个消费者在任何时候可以接收消息,而其他消费者可以作为待机连接。也就是说,只有一个流程可以处于活动状态。只有第一个绑定的消费者可以接收消息。如果第一个消费者断开连接,第二个消费者接收数据,以此类推。独占队列始终按照它们接收的顺序传递消息。

  • non-exclusive - 指定多个消费者可以绑定到队列,这使得负载均衡和消费者自动扩展成为可能。非独占队列可以是非分区的或分区的。

    • 对于非分区队列(分区计数为零),每个消费者以轮询方式被服务。如果连接失败,未确认的消息将被传递给另一个消费者,并设置重新传递标志。通过这种方式,消息可以无序地被传递给消费者。这种类型的队列有时被称为“竞争消费者”队列。
    • 对于分区队列(分区计数大于零),每个消费者从一到多个分区接收消息。消息根据分区键的哈希映射到分区。分区键由发布应用程序设置。在分区内保持消息顺序,但分区之间不保证。

访问类型可以在消费者访问队列(即消息出站)被禁用时更改持久队列。

我们建议在更改非独占队列从分区到非分区或反之之前禁用入站,并允许消息从队列中排出:

  • 如果队列从分区变为非分区或反之,事件代理将解绑所有已绑定到队列的客户端。这确保事件代理和客户端一致地使用(或不使用)分区队列的语义。请注意,任何在已删除分区中剩余的消息也将被删除。
  • 如果队列从非分区变为分区,变更时在队列中的消息可能会卡住,因为事件代理在队列变为分区后不再从父队列传递消息。在这种情况下,消息可以从父队列中复制出来。

队列浏览支持独占队列和非独占、非分区队列。

有关使用Solace CLI创建队列、配置访问类型和禁用消息出站的信息,请参见配置队列。

有关在PubSub+代理管理器中创建和配置队列的信息,请参见PubSub+云的配置队列或软件事件代理和设备的配置队列。

您还可以在PubSub+事件门户中配置队列,并在启用运行时配置的情况下将更新推送到事件代理。有关更多信息,请参见事件门户中配置事件代理。

队列访问类型总结

队列属性独占访问类型非独占访问类型
非分区分区
------
消息分发单个消费者多个消费者,轮询消息传递。
消息顺序保证不保证
队列浏览支持支持

知名队列

任何具有普遍认可名称的队列,无论是持久的还是非持久的,都是知名队列。知名队列名称由应用程序指定,而不是由API生成。应用程序可以在不与队列创建者通信的情况下向知名队列发送消息。只要队列在事件代理网络中的某处存在,就可以使用知名队列名称向队列发送消息。

知名队列的关键特性之一是其持久性。管理员可以使用队列模板控制知名队列的持久性。可以通过队列模板指定持久性覆盖,将知名持久队列转换为知名非持久队列。要了解如何使用队列模板配置持久性覆盖,请参见配置队列模板。有关队列模板的概述信息,请参见端点模板。

在使用知名非持久队列进行请求/回复消息模式时,存在一个竞态条件,即请求的接收者可能在响应者节点知道如何将响应路由到请求者节点之前就回复。因此,不建议在请求/回复消息模式中使用知名队列。对于请求/回复模式,建议使用客户端的#P2P主题前缀进行直接消息回复,并使用匿名队列的网络主题作为保证消息的回复。

知名队列可以通过管理接口如Solace CLI、PubSub+代理管理器和SEMPv2创建,也可以通过应用程序通过PubSub+消息API创建。有关更多信息,请参见使用PubSub+消息API配置持久端点。

匿名队列

与知名队列不同,匿名队列名称由API生成,而不是由应用程序指定,因此队列名称不是众所周知的。要向匿名队列发送消息,必须将目的地发送给对等方,因为它不是事先已知的。通常,这是在请求/回复消息模式的reply-to字段中完成的。PubSub+内置了一个机制,以防止在创建匿名队列后发送到它们时出现竞态条件。这使得匿名队列特别适合请求/回复消息模式。

匿名队列始终是非持久的,这意味着队列和队列上的数据在客户端从队列解绑或客户端断开连接并在六十秒内未能重新建立会话时会被移除。

死信队列

默认情况下,当保证消息的数量重试次数超过原始目的地端点的Max Redelivery值时,或者消息的TTL值已超过且端点配置为尊重消息TTL过期时间时,保证消息会从持久端点的消息缓冲中被移除并丢弃。

然而,由发布客户端标记为DMQ合格的消息可以被发送到分配给端点的DMQ,而不是被丢弃。

任何与消息被缓冲到的端点在同一消息VPN上的持久队列都可以被分配为该端点的DMQ。虽然持久端点被分配了默认的DMQ(#DEAD_MSG_QUEUE),但每个持久端点都可以被分配特定的DMQ。因此,每个消息VPN可以有多个DMQ。

如果端点分配的DMQ不存在,即使它们是DMQ合格的,保证消息也将被丢弃。此外,尽管它是默认的DMQ,管理用户必须手动创建#DEAD_MSG_QUEUE

当消息通过主题到队列映射传递到端点,并且随后被移动到多个端点使用默认的DMQ时,服务端应用程序无法知道消息来自哪个端点。在这种情况下,为每个端点配置单独的DMQ可能更受偏好。

分区队列可以有或是一个DMQ。

有关使用Solace CLI配置DMQ的信息,请参见配置死信队列。

有关在PubSub+代理管理器中配置DMQ的更多信息,请参见PubSub+云的配置死信队列或软件事件代理和设备的配置死信队列。

DMQ功能交互

使用高可用性

PubSub+事件代理在高可用性(HA)组中应将其时钟与网络时间协议(NTP)服务器同步(设备也可以使用PTP),以确保在冗余配置中按预期工作保证消息过期。如果备份事件代理与主事件代理的时钟时间不一致,那么在消息发布和设置过期时间之间发生故障转移时,消息将不会在预期时间过期。NTP服务器参数可以通过CLI通过ntp-server CONFIG命令配置。

使用复制

如果您使用复制,并且为端点启用了ACK传播(启用是默认值),超出TTL的复制消息将被丢弃而不是移动到DMQ。如果您禁用ACK传播,那么TTL计时器将在两个站点独立运行,导致每个站点缓冲的消息之间存在差异。Solace建议不要禁用ACK传播。

最后值队列

如果队列被分配最大缓冲大小为0,则队列仅缓冲它收到的最后消息,无论消息优先级值如何。对于分区队列,每个分区保存最后缓冲到该分区的消息。在这种配置中,队列充当所谓的最后值队列。

像其他队列一样,如果队列收到确认(ACK)消息已被消费,则消息将从队列中移除。要保留队列中最后缓冲的消息,客户端可以浏览队列而不是消费消息。有关更多信息,请参见队列浏览。

您可以通过以下方式将队列设置为最后值队列:

  • 使用Solace CLI将队列的max-spool-usage值设置为0。有关更多信息,请参见配置队列。

  • 在代理管理器中将队列的消息队列配额设置为0。有关更多信息,请参见PubSub+云的配置队列或软件事件代理和设备的配置队列。

主题订阅的应用

发布保证消息的客户端可以对最后值队列应用主题订阅,以便它吸引客户端发布所有消息。这允许客户端使用最后值队列准确确定它成功发布的最后保证消息。

例如,如果在消息发布后应用程序失败,客户端应用程序如果没有从事件代理接收到消息的确认,它不知道发布的消息是否完全丢失,或者消息是否已接收但只是确认丢失。如果使用最后值队列,当客户端重新连接并重新绑定到最后值队列时,它可以确定最后成功发布的消息,并可以从它停止的地方继续发布,而不会创建重复消息或丢失消息。

当有多个发布者针对给定主题时,发布者应在发布主题中被识别,订阅应用程序可以通过通配符订阅。

例如,为每个发布客户端分配形式为uniquePubId/>的最后值队列主题订阅(第一个发布者为Pub1/>,第二个发布者为Pub2/>,依此类推)。然后客户端可以发布形式为uniquePubId/some/hierarchical/topic/的消息。例如,Pub1可能发布到Pub1/price/equities/apple,而Pub2可能发布到Pub2/price/equities/apple,依此类推。这允许客户端特别订阅它们自己的最后值队列,但其他客户端,如果也想接收这些主题的消息,可以使用形式为*/some/hierarchical/topic的主题订阅。例如,*/price/equities/apple

消息选择器

最后值队列不支持消息选择器。

队列浏览

使用Solace企业API的客户端应用程序可以在会话中创建队列浏览器,按最旧到最新的顺序查看队列上缓冲的消息,而不消费它们。也就是说,浏览消息会返回消息的全部内容,包括所有消息头和有效载荷,但那些被浏览的消息不会被从消息缓冲中移除。您应该意识到,当您浏览具有活动消费者的队列时,浏览器可能不会接收到所有发布到队列的消息,因为消费者可以在消息传递给浏览器之前接收并确认消息。

下图显示了浏览器流程如何从队列返回消息,而不消费它们,以便已建立流程的客户端仍然可以消费它们。在这个示例中,还使用了选择器字符串,以便客户端应用程序只浏览与该选择器匹配的消息。(有关选择器的更多信息,请参阅选择器。)

队列浏览

img

分区队列不支持队列浏览。

分区队列

分区队列由一个父非独占队列和每个分区的子队列组成。例如,具有四个分区的分区队列由一个单一的非独占父队列和四个额外的子队列组成。

父队列保存分区队列的配置状态,包括订阅集和分区的组合消息配额。父队列不保留消息,也不消耗任何配额。分区(子队列)对发布和消费应用程序完全不可见。分区既不直接可访问,也不直接可配置。

分区队列对象有一个分区计数属性,指定它拥有的分区数量。分区编号从0到N-1,其中N是分区数量。

有关使用Solace CLI配置分区队列的信息,请参见配置分区队列。

有关在PubSub+代理管理器中配置分区队列的更多信息,请参见PubSub+云的配置分区队列或软件事件代理和设备的配置分区队列。

向分区队列发布和从分区队列消费

事件代理根据消息中携带的键(分区键)将消息分配到分区队列的分区中。发布应用程序在创建消息时设置此键。事件代理创建分区键的哈希,并使用以下计算选择特定消息集的目标分区:

partition = partition-key-hash MOD partition-count

这种分区键与其目标分区之间的关系被称为键到分区映射。所有具有相同键的消息都由同一分区处理。如果没有设置分区键,事件代理会生成一个随机哈希值,这会导致消息被缓冲到随机分区。

消费应用程序绑定到分区队列并像处理任何其他队列一样消费消息。事件代理将一个或多个分区映射到每个消费者流程。这称为分区到流程映射。

在分区内保持消息顺序,但分区之间不保持。

有关代理如何处理分区队列中的消息的详细信息,请参见分区队列中的消息分发。

添加和删除分区

分区扩展指的是添加或删除分区。您可以通过更改队列的分区计数来添加或删除分区。

为了避免消息丢失,我们建议您在进行这些管理更改之前确保消息从队列中排出。有关添加和删除分区的详细信息和具体说明,请参见分区扩展。

分区扩展会影响服务。确保您按照分区扩展中提供的确切程序添加或删除分区。

更改消费者数量

当分区队列的消费者(即绑定流程)数量发生变化时,会触发分区再平衡过程。再平衡涉及重新分配分区到流程映射,以便流程在所有分区中均匀分布,每个分区分配给单个流程(但请注意,流程可以分配给多个分区)。有关更多信息,请参见分区再平衡。

作为再平衡的一部分,事件代理通常会将分区转移到不同的客户端流程。这个过程称为分区交接,它对消费应用程序的设计有影响。有关这个过程的详细讨论以及您的应用程序如何应对分区到流程映射的变化,请参见分区交接。

分区队列功能交互

直接消息传递模式

直接消息可以设置分区键,除非该直接消息被提升到分区队列中,否则这对代理没有意义。否则,分区键只是从入站到出站通过代理携带。

高可用性(冗余)

事件代理的分区到流程映射在HA故障转移中得以保持。从客户端应用程序的角度来看,分区队列和非分区队列在冗余行为之间没有区别。

灾难恢复(复制)

支持将消息复制到分区队列,但有以下警告:

  • 如果没有遵循适当的分区扩展程序,复制到DR-standby的消息可能会因配置更改而在不同的分区结束。这是因为DR-active站点上的配置更改与DR-standby站点的配置更改是脱机协调的。例如,DR-active站点上的分区计数更改通过config-sync发送到DR-standby站点,但执行该更改与数据消息的时间是不协调的。在两边完成分区扩展后,可以预期消息最终会进入相同的分区。

  • 如果没有遵循适当的分区扩展程序,从DR-active到DR-standby的ACK传播可能会失败,因为确认的消息在错误的辅助队列中。通常这样的消息在后续消息确认时会被确认(由于我们使用范围ACK),但无论如何它们不会在适当的时间被确认。

  • 如果从DR-active站点发生故障转移到DR-standby站点,之前分区和消费者流程之间的关系不会被维护。

REST交付点

REST交付点不能绑定到分区队列。

活动流程指示

分区队列支持活动流程指示。尽管客户端绑定到父队列(非独占队列),但内部流程实际上被分配给一个或多个子分区。当流程被分配其第一个分区时,它被认为是过渡到“活动”状态。未被分配分区的流程(例如,如果有比分区更多的流程)被认为是“非活动”的。

队列浏览

分区队列不支持队列浏览。事件代理会拒绝来自浏览流程绑定到分区队列的请求。

选择器

分区队列不支持选择器。如果请求包括选择器,事件代理会拒绝绑定到分区队列的请求。

事务

本地事务支持发布和订阅,但有一个警告,即如果选定的分区在消息被接收和事务被提交之间的配置更改被删除,则本地发布事务的提交会失败。在这种情况下,事务可以简单地重试。

不支持XA事务,无论是发布还是订阅:

客户端信号行为

客户端应用程序不能创建分区队列。分区队列必须通过管理方式预配置。

客户端应用程序可以管理分区队列的订阅。

重放

分区队列不支持消息重放。

从分区队列中删除消息

要从子队列中删除缓冲的消息,您必须在delete-messages命令中指定子队列的名称。如果您在父队列上运行delete-messages命令(即,未指定分区),事件代理会删除在变为分区之前直接缓冲到父队列的任何消息。

将一条消息复制到端点

如果队列从非分区变为分区,消息可能会滞留在父队列中。在这种情况下,消息可以从父队列中复制出去。

消息可以被复制到或从分区中复制。

AMQP

AMQP发布者可以在其消息上设置group-id属性,事件代理直接将此属性映射到分区键属性。这种机制支持分区队列的发布侧行为。

MQTT

MQTT 3.1发布者无法为消息设置分区键。它们的消息可以被传递到分区队列,但被分配一个随机分区。

MQTT 5.0发布者可以在其消息上设置JMSXGroupID作为用户属性,事件代理直接将此属性映射到分区键属性。这种机制支持分区队列的发布侧行为。

MQTT订阅者无法绑定到任意队列,因此无法从分区队列中提取消息。

HTTP

任何HTTP发布者都可以通过使用Solace-User-Property-JMSXGroupID的HTTP头部选项提供分区键。事件代理将此字段翻译为等效的SMF头部,并触发发布侧分区队列行为。

分布式跟踪

分区队列的跟踪与非分区队列相同。

死信队列处理

分区队列可以为其配置DMQ。所有分区的消息从一个分区队列过期到单个配置的DMQ。

DMQ本身可能是一个分区队列。任何到期的消息将根据消息的分区键的哈希放入分区DMQ,或者如果没有哈希,则放入分区0。