企业集成模式-第五章

五、消息构造

5.1 引言

在第 3 章“消息传递系统”中,我们已经讨论了消息。两个应用想要交换一些数据时,可以把数据包装在消息中来实现数据交换。尽管消息通道不能直接传送原始数据,但是它能传送包装在消息中的数据。创建和发送消息带来了另外几个问题。

  • 消息的目的
  • 返回响应
  • 海量数据
  • 慢消息

5.2 命令消息

本地调用要比远程调用更可靠。如果调用者能把过程调用作为消息传送给接收者,接收者就能在本地执行调用。因此,现在的问题是如何把过程调用转换成消息。
image
命令并没有特定的消息类型。命令消息只是一个常规的消息,其中恰好包含了一个命令而已。

5.3 文档消息

文档消息看上去很像事件消息,它们之间的主要区别在于时间限制和内容两方面。文档消息的关键在于其内容是一个文档。

5.4 事件消息

事件消息与文档消息的区别主要在时间限制和内容两方面。事件的内容一般并不是很重要。许多事件的消息体甚至都是空的,只要出现了事件就能让观察者作出反应。事件的时间限制非常重要:一旦有所修改,主体应该立即发出事件,观察者应该趁事件有效时尽快处理事件。可靠传输对事件传送的意义不大,因为事件发生的频率很快,而且需要尽快地传送。消息到期有助于保证事件得到快速处理,或者根本不处理。

推模型:消息是文档/事件消息的组合。

拉模型:

  1. 更新是一种事件消息,它向观察者通知发生了一个事件
  2. 状态请求是一种命令消息,感兴趣的观察者使用这个消息从主体那里请求详细的信息
  3. 状态应答(state reply)是一种文档消息,主体使用这个消息向观察者发送详细的信息

拉模型的优点是更新消息很小,只有感兴趣的观察者才需要请求详细的信息,而且每个感兴趣的观察者只需请求它特别关注的信息。其缺点是需要增加额外的通道,且由于消息不只一个会带来通信量的增加。

5.5 请求/应答

image
有两种应答方法。

  1. 同步阻塞
  2. 异步回调

仅仅有能相互发送请求和应答的两个应用并没有太大意义,真正有意思的是请求和应答消息分别表示什么。

  1. 消息传递RPC:请求是一个命令消息,它描述了应答者应该调用的函数。应答是一个文档消息,它包含了函数的返回值或异常信息
  2. 消息传递查询:请求是一个命令消息,其中包含查询。应答是查询的结果,可能是一个消息序列。
  3. 通知/确认:请求是一个事件消息,可以提供通知。应答是一个文档消息,对通知作出确认。确认本身也可以是另一个请求,如查询事件的详情。

请求就像一个方法调用。类似地,应答也有3种可能:

  1. 空:只是通知调用者方法已经结束,使调用者的工作可以继续
  2. 结果值:方法的返回值,这是一个对象
  3. 异常:这是一个异常对象,表示方法在成功完成之前异常中止,并给出异常的原因

5.6 返回地址

请求消息中包含返回地址

5.7 关联标识符

接收到应答的请求者怎样知道这个应答对应哪一个请求?

调用者可以采用两种方法避免这种混乱的情况。可以在发出新的请求前等待上一次请求的应答,在任何时刻只有一个未完成的请求存在。但是,这种做法会极大地降低处理的吞吐量。

消息可以有某种键,这是一个唯一标识符,类似于关系数据库中某行记录的主键。可以用这种唯一标识符把这个消息与其他消息区分开,将使用此消息的客户等等区分开。

关联标识符包括六个部分:

  1. 请求者:此应用发送请求并等待应答,从而完成业务任务
  2. 应答者:这是另一个应用,将接收请求,处理请求,并发送应答。它从请求消息种获得请求ID。
  3. 请求:
  4. 应答
  5. 请求ID:请求消息中的一个令牌,唯一地标识请求消息
  6. 关联ID:应答消息中的令牌,其值域请求消息中的请求ID相同

5.8 消息序列

一些消息传递实现对消息的最大容量有一个绝对的限制

只要需要把一大块数据分解为消息大小的数据块,就可以将数据作为消息序列来发送,并用序列标识字段标记每个消息。

  1. 序列标识符:把本消息簇与其他消息簇区分开来
  2. 位置标识符:唯一地标识序列中的各个消息,并对各个消息完成顺序排序
  3. 大小或结束指示符:指定消息簇中消息的数量,或者标记簇中的最后一个消息(它的位置标识符指定了簇的大学)

要让序列中的每个消息指示出序列的总大小——也就是说,给出序列中消息的总数量。另一种方法是让每个消息都指出它是否是序列中的最后一个消息。

对于最后一个消息之前的各个消息,发送者要将这些消息的序列结束”标志设置为假 (false)。发送者准备发送序列中的最后一个消息时,要把消息的序列结束标志设置为真(true)。

如果接收者只接收到序列中的一部分消息,而不是全部消息,它应该把已经接收到的消息重新转发给非法消息通道。只有在接收到全部消息之后,它才会真正消费这些消息。

消息序列可能与竞争消费者(Competing Consumer)或消息分派器(Message Dispatcher)不兼容。如果不同的消费者/执行者接收到同一个序列中的不同消息,那么所有接收者都无法将消息重组成原始的数据,除非它们彼此交换所收到的消息内容。因此,消息序列应当通过只有一个消费者的消息通道传输。

使用消息序列就类似于使用分解器把大的消息分解为一系列消息,再使用聚合器把这些消息重新组装成一个消息。

5.9 消息到期

消息传递最终总能保证把消息传送给接收者。但是它无法保证传送所需的时间。通常,消息的内容只是在一定的时间期限内有效。

image
消息到期是一个时间戳(日期和时间),指定了消息生存的时间或何时到期。可以采用相对或绝对方式做此设置。绝对设置要指定消息到期的日期和时间。相对设置则指定消息到期前会存活多长时间,发送消息时,消息传递系统要使用这个时间把将相对时间转换为绝对时间。消息传递系统要负责为处于不同时区的接收者(与发送者不在同一个时区)调整时间戳,负责针对夏令时以及引起时钟不一致的其他问题做出调整。

消息到期属性有一个相关的属性:发送时间,这个属性指定消息是何时发送的。消息的绝对到期时间戳必须比它的发送时间戳晚(否则消息立即就到期了)。为了避免这个问题,发送者一般只给出相对到期时间,由消息传递系统把相对期限与发送时间戳相加(到期时间=发送时间+生存时间),从而计算出到期时间戳。

当消息到期时,消息传递系统可以简单地把它丢掉,或者是把它转移到死信队列中。

5.10 格式指示符

如何设计消息的数据格式,使之能适应未来可能的变化?

实际上,应用必须能同时支持新老两种数据格式。为此,应用必须要在消息中指明它采用的是新格式还是老格式。

更好的解决办法是采用老格式使用的通道来传递新格式的消息。为此,接收者必须采用某种方法把使用相同通道的不同格式消息区分开。每个消息必须指定所使用的格式,而且需要一种简单的方法来指示其格式。

实现格式指示符的三种主要方法:

  1. 版本号:唯一标识格式的数字或字符串
  2. 外键:指定文档的唯一ID
  3. 格式文档:描述数据格式的模式
posted @ 2023-11-12 21:31  LHX2018  阅读(8)  评论(0编辑  收藏  举报