消息会话
使用 Azure 服务总线会话,可以连贯有序的方式处理一系列无限多的相关消息。 可以在“先进先出 (FIFO)”和“请求-响应”模式下使用会话。 本文展示了如何在使用服务总线时使用会话来实现这些模式。
注意
服务总线的基本层不支持会话。 标准层和高级层支持会话。 有关这些层之间的差异,请参阅服务总线定价。
先进先出 (FIFO) 模式
若要在服务总线队列或订阅的处理消息中实现 FIFO 保证,请使用会话。 服务总线没有规定消息之间的关系性质,也没有定义用于确定消息序列开始或结束位置的特定模型。
任何发送方都可以在将消息提交到主题或队列时创建会话,方法是将“session ID”属性设置为会话专属的某个由应用程序定义的标识符。 在 AMQP 1.0 协议一级,此值映射到 group-id 属性。
在会话感知队列或订阅中,如果有至少一个消息带有会话 ID,会话就诞生了。 一旦会话诞生,就没有规定会话何时过期或消失的已定义时间或 API。 理论上讲,从服务总线的角度看,今天可以接收会话的消息,一年后可以接收下一个消息,如果会话 ID 一致,则会话相同。
然而,通常情况下,应用程序都很清楚一组相关消息的开始和结束位置。 服务总线未设置任何具体规则。 例如,应用程序可以将第一个、中间一个和最后一个消息的“Label”属性分别设置为“start”、“content”和“end” 。 content 消息相对位置的计算方式为,当前消息的 SequenceNumber 与 start 消息的 SequenceNumber 的增量值。
重要
当对队列或订阅启用会话时,客户端应用程序可以不再发送/接收常规消息。 所有消息都必须作为会话的一部分进行发送(通过设置会话 ID)并通过接受会话进行接收。 客户端仍可能速览启用了会话的队列或订阅。 请参阅消息浏览。
会话 API 存在于队列和订阅客户端上。 可以使用一个命令性模型,控制会话和消息的接收时间;还可以使用一个基于处理程序的模型,此模型简化了接收循环的管理操作。
有关示例,请使用后续步骤部分中的链接。
会话功能
会话支持对交错消息流进行并发解多路复用,同时保留和保证有序传递。
会话接收方由接受会话的客户端创建。 当客户端接受或持有会话时,客户端对队列或订阅中具有该会话的“session ID”的所有消息持有一个排他锁。 它会对以后到达的具有“session ID”的所有消息持有排他锁。
当你在接收方上调用关闭方法或当锁过期时,将释放该锁。 接收方上还提供了一些方法来续订锁。 相反,你可以使用自动锁定续订功能,你可以在其中指定要使锁定得到续订的持续时间。 应将会话锁定视为对文件施加的排他锁。也就是说,应用程序应在不再需要它时和/或不需要再处理其他任何消息时关闭会话。
当多个并发接收程序从队列中拉取消息时,属于特定会话的消息会被分派到当前让相应会话一直处于锁定状态的特定接收程序。 通过此操作,一个队列或订阅中的交错消息流可以明确解多路复用到各个接收程序,这些接收程序也可以驻留在不同的客户端计算机上,因为锁定管理是在服务总线内的服务端执行。
上图显示三个并发会话接收程序。 某个 SessionId
= 4 的会话不具有活动的、所属的客户端,这意味着此特定会话不传递任何消息。 会话在很多方面都起着一个子队列的作用。
会话接收程序保留的会话锁定是速览锁定安排模式使用的消息锁的保护伞。 只有一个接收程序可以在会话上使用锁。 接收方可能具有许多正在传输的消息,但将按顺序接收消息。 如果放弃消息,则会在下一次执行接收操作时再次处理相同的消息。
消息会话状态
在高度可缩放、高度可用的云系统中处理工作流时,与特定会话相关的工作流处理程序不仅必须能够从意外故障中恢复,还必须能够在不同的进程或计算机中从工作开始位置恢复部分完成的工作。
借助会话状态工具,可以在中转站内为消息会话添加应用程序定义的注释。这样一来,当会话被新处理程序获取时,相对于此会话的已记录处理状态就会立即可用。
从服务总线的角度来看,消息会话状态是一个不透明的二进制对象,可以保留一个消息大小的数据(对于服务总线标准版,大小为 256KB;对于服务总线高级版,大小为 100 MB)。 相对于会话的处理状态可以保留在会话状态中,会话状态也可以指向保留此类信息的某存储位置或数据库记录。
可在会话接收方上找到用于管理会话状态的 SetState
和 GetState
方法。 之前没有设置会话状态的会话将对 GetState
返回空引用。 将 NULL 传递给接收方的 SetState
方法,可以清除先前设置的会话状态。
只要不清除会话状态,会话状态将保留(返回 null),即使会话中的所有消息都已使用,也是如此。
队列或订阅中保留的会话状态计入相应实体的存储配额。 因此,当应用程序完成会话时,建议应用程序清理保留的状态,以杜绝外部管理成本。
传送计数的影响
在会话上下文中,每条消息的传递计数的定义与在没有会话的情况下的定义略有不同。 下表汇总了递增传送计数的时间。
方案 | 消息的传递计数是否递增 |
---|---|
接受会话,但会话锁已过期(由于超时) | 是 |
会话被接受,会话中的消息未完成(即使它们已被锁定),然后关闭会话 | 否 |
会话被接受,消息完成,然后显式关闭会话 | 不适用(这是标准流。此处的消息将从会话中删除) |
“请求-响应”模式
“请求-回复”模式是一种成熟的集成模式,它使发送方应用程序能够发送请求,并为接收程序提供了一种正确地将响应发送回发送方应用程序的方法。 此模式通常需要一个生存期较短的队列或主题,以便应用程序向其发送响应。 在此方案中,会话提供了一个具有可比较语义的简单替代解决方案。
多个应用程序可以将其请求发送到单个请求队列,并将特定标头参数设置为唯一标识发送程序应用程序。 接收程序应用程序可以处理传入队列的请求并在启用了会话的队列上发送答复,将会话 ID 设置为发送程序已在请求消息上发送的唯一标识符。 然后,发送请求的应用程序可以在特定会话 ID 上接收消息,并正确地处理答复。
注意
发送初始请求的应用程序应了解会话 ID,并用它来接受会话,由此锁定需要响应的会话。 一个不错的做法是使用可独一无二地将应用程序实例标识为会话 ID 的 GUID。队列的会话接收方上不应存在会话处理程序或指定的超时,以确保响应可由特定接收方锁定和处理。
排序与会话
序列号本身可以保证消息的排队顺序和提取程序顺序,但不能保证需要会话的处理顺序。
假设队列中有三条消息和两名使用者。
- 使用者 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。
消息过期
对于已启用会话的队列或主题订阅,消息会在会话级别锁定。 如果任何消息的生存时间 (TTL) 过期,则根据实体上的消息过期设置中启用的死信功能,将会删除与该会话相关的所有消息或将其处理为死信。 换句话说,如果会话中的单个消息已超过 TTL,则会话中的所有消息都是过期的。 仅当存在活动侦听器时,消息才会过期。 有关详细信息,请参阅消息过期。
后续步骤
可以使用 Azure 门户、PowerShell、CLI、资源管理器模板、.NET、Java、Python 和 JavaScript 在创建队列时启用消息会话。 有关详细信息,请参阅启用消息会话。
尝试采用所选语言的示例,了解 Azure 服务总线功能。
- .NET
- Java
- Python
- JavaScript