原文链接:Routing Mechanisms For AMQP Protocol
作者:Paolo Patierno,红帽高级软件工程师
译者:赵屹华 审校:刘翔宇
责编:周建丁(zhoujd@csdn.net)
未经许可,请勿转载!
在上一篇文章里,我们安装了Qpid Dispatch Router,并且快速地浏览了安装包提供的路由管理和监控工具。
本文将介绍几个路由器的使用例子,从简单的配置和网络拓扑到复杂的结构,包括AMQP发送端、接收端和代理者。代理部分并不是必须的,因为AMQP协议是一种“对等”协议,它可以直接连接两个客户端,不需要代理提供的“存储再转发”机制。关于这方面的介绍,可以阅读本系列的第一篇文章。
在本文中,我将使用默认配置的路由器来演示发送端和接收端是如何与它连接的,以及如何通过路由器来交换消息。
路由机制
首先,值得一提的一点是路由器支持两种不同的路由机制。
消息路由
当路由器从链路上收到一条消息,它使用发送端发到路由器时所指定的目的地址;如果这一地址没有被指定,则目的地址从消息的“to”属性中获取。基于这个信息,路由器查找路由表从而决定消息传递的路径。它可能是直接相连的接收端,也可能是网络中的另一个路由器来作为下一块跳板。当然,消息也可以被送达地址相同的多个不同的接收端。这里的关键点是针对每一条接受到的消息都做一次路由决策,而且路由器内部节点之间和外部客户端往往还有很多通信。
从上图中可以看出,链路是建立在发送端和路由器以及接收端和路由器之间的。在基于消息的路由机制下,路由器和发送端以及接收端的消息交换是两条截然不同的链路。
这也意味着路由器(内部的接收端)与发送端、路由器(内部的发送端)与接收端有着不同的流量控制策略。当然,如果接收端获得的分值很低(比如10),但是路由器(内部接收端)给了发送端很大的分值(默认是250),这个差值需要被考虑到。如果接收端由于某些原因(收到10条消息后)关闭了连接,而发送端发送的消息已经超过10条(根据“accepted”标志),因为路由器无法向已经关闭的接收端继续发送消息,它会回复一个“released”标志。
另一个有趣的地方在于消息的“处置”。路由器总是在网络中传播递送和处置。当接收一条“预处置”消息时,它的属性被传播到了目的地址。“未处置”消息也是如此:在这种情况下,路由器需要跟踪传入的递送,并将未处置消息发往目的地址;当它从最终的接收端收到已处置标志时,它将以同样的方式回复原始发送端。
消息路由的最后一点有趣之处在于其路由模式,定义了消息在网络中的游走路径:
最近路线:即使有许多接收端的地址相同,消息还是按照最短路径送往目的地址。这也意味着只有一个接收端能够收到消息。
平衡路线:当有多个接收端的地址相同时,发往该地址的消息将分布在各个接收端上。意思是说各个接收端以类似“竞争消费者”的形式每次接收不同的消息。
多路传送:这有点类似“发布/订阅”模式,即附着在同一个地址的所有接收端都能收到同样的消息。
当某个地址上的所有接收者都与同一个路由器相连,我们可以近似认为“最近路线”和“平衡路线”的效果是一样的,因为所有的路径长度都相等,接收端与路由器的距离等级都相同。事实上并不完全这样,因为在“最近路线”模式下路由器对各个接收端使用严格的循环分布,而在“平衡路线”模式下它考虑了各个接收端未处置递送的个数,选择其中“更快”的一个(即处置消息更快)。
举个例子,假设有一个发送端S、两个接收端R1和R2和一个路由器网络,R1与S连接在同一个路由器上,R2连在了另一个路由器(连到前一个)。我们认为R1到S的距离是1级,R2到S的距离是2级。
在下面的场景中,按照“最近路线”模式S发送的所有消息都将被传递到R1。
按照“平衡路线”模式,消息分布在两个接收端上,且与路径长度无关。
最后,在“多路传送”模式下所有的消息被发送到所有的接收端。
链路路由
当路由器收到一条附加请求时,它被传播于整个网络,以至于找到目的地节点,建立起一条真正的链路。当发送端开始给路由器发送消息,在消息层面上不需要任何决策过程,直接通过建立起的链路送达目的地址。你可以认为它是一种虚拟连接或是一条连同发送端和接收端的隧道。
如你在上述图片中所见,链路直接建在两个端点之间,所有的活动都是通过它来进行。
从流量控制的角度来看,它直接由发送端和接收端控制;发送端给予的任何分值直接到达接收端,无需路由器的中间干扰。穿越路由器的链路就像一条“隧道”,两个端点就像是直接相连的。
对于“未处置”消息的标志也是一样的,发送端直接收到来自接收端的标志。
不同路由模式的概念在这里没有意义,因为在这种情况下有一条连接发送端和接收端的直接路径,因此路由器对单条消息不做任何决策,只需要沿着链路传递每一帧数据。
我们开始吧……超级简单!
现在,我们用一个默认配置的路由器做一个简单的例子,只有一个发送端和一个接收端与其相连,挂载在/my_address的地址上。
我使用了simple_recv和simple_send的C++客户端例子,它们在Quid Proton安装文件夹里都能找到。
首先,我们定义接收端的地址和接收消息的条数,比如10条消息,启动接收端。
我们使用qdstat管理工具可以发现my_address被定义为“输出”(从路由器到接收端)的端点,还没有发送过消息。
之后,我们开启发送端来发送一些自动生成的消息,比如5条消息。
如你所见,所有的消息被处置且得到确认。在接收端一侧的情况如何呢?
发送端发送的所有消息都已经接收,但应用并未关闭,因为它在等待另外5条消息(当然,这只是应用本身的行为,与路由机制无关)。
使用qdstat管理工具,我们可以看到在my_address的输出端点有5条已发送消息。我们无法查看的是同一个地址下的“输入”端点(从发送端到路由器),因为消息发送之后,发送端关闭了与路由器的连接,这个端点也随之被删除。相信我,发送端在发送消息时这个端点确确实实是存在的!
你应该发现了我们直接将发送端和接收端相连,不需要代理者在中间存储和转发消息。在上述场景中,当消息被处置并且给发送端确认之后,就意味着消息真正的被接收端所接收了。
总结
在本文中,我介绍了Qpid Dispatch Router提供的消息路由的不同机制。我们可以针对不同的场景选择最佳的方式,使得我们的分布式应用能更有效地传递消息。我们演示了一个简单的例子,它不需要代理者参与,而是直接将发送端和接收端与路由器相连。在下一篇文章里,我将不再使用默认的配置文件,探索连接路由器与客户端和代理者的不同方式,增加系统的复杂性。