Service Broker 的优点

Service Broker 的功能为数据库应用程序的帮助很大。这些功能和好处包括:

  • 数据库集成提高了应用程序的性能并简化了管理。

  • 适用于简化的应用程序开发的消息排序和协调。

  • 应用程序松耦合提供了工作负荷灵活性。

  • 相关消息锁定使一个应用程序的多个实例可以对同一队列中的消息不必显式同步处理。

  • 自动激活使应用程序可以随消息量进行调整。

数据库集成

Service Broker 的集成设计对应用程序性能和管理有所帮助。

与 SQL Server 集成可以进行事务性的消息传递,从而避免了外部分布式事务协调器的额外开销和复杂性。在一个数据库事务内,应用程序接收一个或多个消息,处理消息并发送答复消息。如果事务失败,所有工作都回滚,并且收到的消息会返回到队列中,以便可以尝试再次处理它。仅当应用程序提交事务之后,操作才会生效。应用程序保持一致性状态。

当数据、消息和应用程序逻辑都在数据库中时,管理变得更简单,因为应用程序的管理(灾难恢复、安全性、备份等)随之成为数据库日常管理的一部分,而且管理员不必管理三个或四个单独的组件。

在传统的消息传递系统中,消息存储区和数据库可以不一致。例如,当一个组件从备份中还原时,另一个组件也必须同时从备份中还原,否则消息存储区中的信息与数据库中的信息不匹配。由于 Service Broker 将消息和数据保存在同一个数据库中,因此消除了不一致问题。

公共的开发环境也是数据库集成的一个好处。应用程序的消息传递部分和数据部分可以在 Service Broker 应用程序中使用相同的 SQL Server 语言和工具,这使开发人员在基于消息的编程中可以充分利用对数据库编程技术的熟悉。实现 Service Broker 服务的存储过程可以用 Transact-SQL 或一种公共语言运行时 (CLR) 语言来编写。数据库外的程序使用 Transact-SQL 和类似的数据库编程接口,如 ADO.NET。

此外,数据库集成使自动资源管理成为可能。Service Broker 在 SQL Server 实例的上下文中运行,因此它监视准备从该实例中所有数据库传送的所有消息。这样使每个数据库在维护自己队列的同时,帮助 Service Broker 管理整个 SQL Server 实例中的资源使用情况。

排序和协调消息

在传统的消息传递系统中,应用程序负责排序和协调到达顺序可能不对的消息。例如,应用程序 A 发送消息 1、2 和 3。应用程序 B 接收并确认消息 1 和 3,但是在接收消息 2 时出现错误。应用程序 A 重新发送消息 2,但是,现在该消息是在消息 1 和 3 后面收到的。过去,开发人员或者必须编写应用程序,使消息顺序不出问题,或者在消息 2 到达之前暂时缓存消息 3,以便应用程序可以以正确的顺序处理这些消息。这两个解决方案都既不明了也不简单。

传统系统还存在另一个问题,即重复传递。在上面的示例中,如果应用程序 B 收到消息 2,但是返回给应用程序 A 的确认消息丢失,应用程序 A 将重新发送消息 2,这导致应用程序 B 收到消息 2 两次。应用程序代码必须能够识别出重复消息并放弃它,或者重新处理该重复消息,而不产生任何负面效果。同样,这两个方法也很难实现。

消息协调在传统上也是难以处理的问题。例如,某个应用程序可能向一个服务提交成百上千个请求。该服务并行处理这些请求,并且它每处理完一个请求就立即返回一个响应。由于处理每个请求所花费的时间长短是不同的,因此应用程序收到响应的顺序与它发送传出消息的顺序不同。但是,为了正确处理响应,应用程序必须将每个响应与正确的传出消息相关联。在传统的消息传递系统中,每个应用程序都管理此关联,这使得应用程序的开发成本和复杂程度加大了。

Service Broker 通过自动处理消息顺序、唯一传递和会话标识解决这些问题。在两个 Service Broker 端点间建立会话后,一个应用程序只对每个消息接收一次,并且以该消息的发送顺序接收它。您不需要对应用程序额外编写代码,即可按照顺序处理这些消息,且仅处理一次。最后,Service Broker 自动将标识符包含在每个消息中。应用程序可以始终掌握特定消息属于哪个会话。

松耦合与工作负荷灵活性

Service Broker 提供起始应用程序和目标应用程序间的松耦合功能。应用程序可以向队列发送一个消息,然后继续应用程序处理,而依靠 Service Broker 确保该消息到达其目标。这种松耦合带来了计划上的灵活性。发起方可以发出多个消息,而多个目标服务可以并行处理这些消息。每个目标服务按照其自己的速度处理这些消息,具体情况取决于当前的工作负荷。

排队也可使系统更平均地分配处理任务,从而减少服务器所需的峰值容量。这样可以提高数据库应用程序的总体吞吐量和性能。例如,许多数据库应用程序在一天中的某些特定时段事务量激增,这使资源消耗加大并使响应时间延长。使用 Service Broker,这些应用程序无需对提交的业务事务执行该事务的所有处理。而是使用 Service Broker 将有关该事务的信息发送给执行后台处理的应用程序。这些执行后台处理的应用程序可靠地处理这些事务一段时间,同时主入口应用程序继续接收新的业务事务。

如果目标不是立即可用的,消息保留在发送数据库的传输队列中。Service Broker 会重试发送该消息直至该消息成功发送为止,或者直至会话的生存期过期,这使得即使两个服务中的一个在会话期间的某个点不可用,会话也可以在两个服务之间可靠地继续。传输队列中的消息是数据库的一部分;即使实例发生故障转移或重新启动,Service Broker 也可以传递消息。

相关消息锁定

在传统的消息传递应用程序中,最难实现的任务之一是使多个程序并行读取同一队列。在传统的消息传递系统中,当多个程序或多个线程读取同一队列时,可能会以错误的顺序处理消息。Service Broker 通过会话组锁定防止出现这种情况。

试想传统的订单处理应用程序。队列收到两个消息,消息 A 包含有关创建订单标题的指令,消息 B 包含有关创建订单行各项的指令。如果这两个消息分别由不同的应用程序实例移出队列,并且同时处理,则订单行项事务有可能尝试先提交,并因订单尚未存在而失败。这一失败进而导致事务回滚和消息重新入队,然后消息被再次处理,从而浪费了资源。程序员解决此问题的传统做法是:将消息 A 和消息 B 中的信息组合成一个消息。虽然这种方法对两个消息来说简单明了,但是对于涉及需要协调几十个或几百个消息的系统来说,这一方法就无能为力了。

Service Broker 通过关联会话组中的相关会话来解决这个问题。Service Broker 自动锁定同一会话组中的所有消息,使这些消息只能由一个应用程序实例来接收和处理。同时,应用程序的其他实例可以继续将其他会话组中的消息移出队列并处理它们。这样使得多个并行应用程序实例可以可靠而有效地工作,而不需要在应用程序中编写复杂的锁定代码。

自动激活

Service Broker 最有用的功能之一是激活功能。激活功能使应用程序可以动态地调整自身,以匹配队列中到达的消息量。Service Broker 提供了一些功能,这些功能使在数据库中运行的程序和在数据库外运行的程序都可以利用激活。但是,Service Broker 不要求应用程序必须使用激活。

Service Broker 监视队列中的活动,以确定某个应用程序是否在接收所有含有可用消息的会话的消息。当有工作需要由新的队列读取器来执行时,Service Broker 激活功能会启动一个新的队列读取器。Service Broker 监视队列中的活动来确定何时有工作需要由队列读取器来执行。当队列读取器的数量与传入的通信流量相匹配时,队列会定期进入一种状态,即队列或者为空,或者该队列中的所有消息都属于正由另一队列读取器处理的会话。如果队列在一段时间内没有达到此状态,则 Service Broker 会激活应用程序的另一个实例。

对于在数据库中运行的程序和在数据库外运行的程序,应用程序使用不同的激活方法。对于在数据库中运行的程序,Service Broker 启动队列所指定的存储过程的另一个副本。对于在数据库外运行的程序,Service Broker 生成一个激活事件。程序监视此事件以确定何时需要另一个队列读取器。

Service Broker 不停止通过激活功能启动的程序。激活的应用程序都被编写为如果在特定的时间段内没有消息到达以供接收,则在这段时间过后将自动关闭。以这种方法设计的应用程序使应用程序实例的数量可以随服务的通信流量更改而动态地增大或减小。此外,如果系统关闭或重新启动,则系统重新启动时,应用程序会自动启动以读取队列中的消息。

传统的消息传递系统没有此行为,结果在某个给定的时间专用于特定队列的资源经常不是太多就是太少。