现在的许多应用是包括跨越不同网络的组件,LAN或者Internet。因此许多应用做了消息机制。另一些开发人员使用消息队列产品,但是大多数时候他们自己写,使用TCP或者UDP。这些协议并不难用,但是从A发送几个字节到B和一个可靠的消息机制有很大的区别。
让我们看看我们将面临什么问题,当我们开始使用TCP时的一些经典问题。任何可重复使用的消息层都需要解决部分和全部。
- 我们如何处理I/O?难道我们在程序块中或者后台处理I/O?这是一个关键的设计决定。阻塞的I/O模式不能很好的扩展。但是异步I/O可能很难。
- 我们怎么处理动态组件,例如组件总是临时的?我们正式将组件分割为”clients”和”servers”,命令servers不消失?以便如果我们想连接两个servers?
- 我们怎么在线上表达一个消息?我们怎么将数据变成frame便于读写,在缓冲区溢出时保持安全,确保消息小而有效?
- 我们怎么处理不能立即交付的消息?特别是如果我们正在等待一个在线返回的组件?我们丢弃消息,把它们放入数据库,或者放入内存队列中?
- 我们在哪里存储消息队列?如果组件的读取速度很慢引起队列集聚,会发生什么?我们的策略是什么?
- 我们怎么处理丢失的消息?我们等待新的数据,请求重新发送,或者我们创建一种可靠的层确保数据不丢失?
- 如果我们需要使用不同的网络传输。使用多播取代TCP单播?或者IPv6?我们需要重新这个应用或者做一些抽象的传输层?
- 我们怎么为其他语言写API?难道我们重新实现一个wire-level protocol或者我们重新包装一个库?如果是前者我们怎么保证协议栈的高效与稳定?如果是后者我们怎么保证互操作性?
- 我们如何表示数据以便它可以在不同的体系结构之间被读取?我们是否强制执行数据类型的特定编码?消息系统的工作量超过上层结构还要多远?
- 我们如何处理网络错误?难度我们等待并重试,或者悄无声息的忽略它们,还是直接终止?
来看看一个典型的开源工程像Hadoop Zookeeper并且读C API代码src/c/src/zookeeper.c。我在2013年1月读这些代码时,它有4200行神秘的代码,并且那是一个未公开的client/server网络通信协议。我们明白这是有效的,因为他使用了poll替代了select。但是Zookeeper真的应该使用了一个通用的消息层和一个公开的wire level protocol。这其实是很大的浪费,该团队一遍一遍的制造这种特殊的轮子。
但是怎么设计一个可重要的消息层?为什么有那么多的项目需要这种技术,人们仍然还在艰难的使用TCP socket在他们的代码,并一遍一遍解决解决这一长串问题?
这些事实证明了构建可重复使用的消息传递系统是非常困难的,这也是为什么一些FOSS项目尝试过,也是为什么商业通信产品是复杂的,昂贵,不灵活,脆弱的。2006年iMatix设计了AMQP,开始为FOSS开发者提供一个可重复使用的消息系统。AMQP比许多类似设计更好,但是仍然相对复杂,价格昂贵,脆弱。并且需要几个星期来学习使用,再用几个月稳定架构确保不奔溃。
多数消息工程,如AMQP,在可复用的路上尝试解决一长串问题列表 并发明一些新的概念,”broker”做寻址,路由,队列。这导致client/server