如何确保通过网络服务器的拉/查询传输邮件

如何确保通过网络服务器的拉/查询传输邮件

问题描述:

这建立在How to send messages between Companies上。如果我决定公司S(upplier)应该以某种简单的基于HTTP的方式轮询公司(B)的订单,那么最好的实现方式是什么。如何确保通过网络服务器的拉/查询传输邮件

  • 我假设公司B有一个Web服务器正在运行,并且该Web服务器的后端数据库是持久的。我们应该尽可能少地假设S上的存储过程,并且他们是否能够保持状态(例如,已经传输的GUID列表)
  • B和S之间的因特网连接是不可靠的。
  • 我们必须达到eventual consistency这意味着在一个时间点B和S之间的所有订单都应该被转移。

实施此类系统的最佳实践是什么?

这种问题的一种方法是使用某种排队产品,作为我立即考虑MQ的IBM人员。然而,因为我自己并不是真正的MQ人,所以我可能会对您采用的基于服务的方法感到满意。

想到两种可能的方法。一种是使用WS Reliable Messaging,它将可靠性问题推入Web服务基础架构。另一种方法是在简单但不可靠的服务之上提供自己的可靠协议。

我对WS Reliable Messaging实现系统没有认真的实践经验,我确信它可以工作,但它确实需要对参与者进行某种程度的控制 - 因为它是一个相对较新的标准我们不能保证任何给定的IT商店都将实施交付,并且供应商之间的互操作性可能是一个问题。我对每一端的SW堆栈的控制越多,我就越倾向于使用WS Reliable Messaging。 [我也应该提到WS Atomic Transaction,它也可以用来构建可靠的服务,同样的操作间问题也适用。]

那么你自己怎么样?这里的关键是要使所有服务都是幂等的。由于我们没有跨越两个系统的交易保证,因此我们必须假定任何给定的服务呼叫都可能会因未知结果而失败。

我打算假设B想要确认S已经下了订单,因此我们需要在订单转移时更新B和S的信息。所以

Give me the next order(s) 

I have stored {orders ...} 

我们如何定义 “下一步”:

B必须提供诸如这些。如果我们正在处理的卷可以让我们有一个单一的“线程”转移,最简单的情况很好地工作。然后,B一次一个地发送已发送的订单,并且订单具有单调递增的ID。我们可以简化为:

I have stored order <65,004> please give me the next 

请注意,这是一个幂等的请求:它可以安全地重复多次。另外请注意,S必须预期两次获得相同订单的可能性,并检查重复项。

+0

在e分布式系统中,单调递增的ID有些困难,但是我们可以额外添加:“我现在已经存储了消息,可以删除它”请求。 – max 2010-10-27 09:37:11

+0

++为网络服务 – 2010-11-09 16:43:17

+0

您能否给我一个“Web服务”的例子,WS- *堆栈似乎给我一个不兼容的复杂混乱,但这可能只是我缺乏经验。我在哪里可以找到Github上的WS- *的Ruby/Python/PHP/Perl库? – max 2010-11-11 19:00:29

您可能正在寻找的是两阶段提交。它是在互联网很好的描述,这里例如:

http://en.wikipedia.org/wiki/Two-phase_commit_protocol

它的要点:

的提交过程如下:

* Phase 1 
     o Each participating resource manager coordinates local 
     operations and forces all log records out: 
     o If successful, respond "OK" 
     o If unsuccessful, either allow a time-out or respond "OOPS" 
* Phase 2 
     o If all participants respond "OK": 
      * Coordinator instructs participating resource managers to "COMMIT" 
      * Participants complete operation writing the log record 
       for the commit 
     o Otherwise: 
      * Coordinator instructs participating resource managers to "ROLLBACK" 
      * Participants complete their respective local undos 

应该对任何类型的数据工作。

+0

我认为让“另一端”实现(和测试)两个阶段的原子提交将是相当困难的。 – max 2010-11-03 22:26:30

好吧,首先你不能保证任何东西在一个不可靠的链接。 Two Generals' Problem证明了这对于确定性和非确定性协议。你所能做的就是将不可靠性降低到可接受的程度。

最简单的方法是,在你的情况下,一旦服务器收到一个轮询请求,它会发送x数量的回复,全部使用相同的GUID。例如。

S: B, anything new? 
S: B, anything new? 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 
B: Yes, S, I need some shoes (order #124). 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 
B: Yes, S, I need some shoes (order #124). 
S: B, anything new? 
B: Yes, S, I need some shoes (order #124). 
S: B, anything new? 
B: Yes, S, I need some shoes (order #124). 
... 

S可以收到大量邮件与订单,但由于#与每个请求一起发送,这不是什么大不了的事。如果我们之前错过了,我们现在就得到它。如果我们没有得到它,呜呼!我们现在拥有它。系统工作!在我的示例中,您会注意到B发送消息5次。在现实的情况下,您可能会发送数百或数千次的消息,直到您获得所需的可靠性。

现在上述解决方案是处理和带宽密集型,但它确实工作。一个更聪明的方法是做TCP的工作:有一个三方握手。

S: Hello B. Are you there? -> SYN 
B: Hello S, yep I'm here. What's up? -> SYN+ACK 
S: Oh good, you're there. -> ACK 
S: B, anything new? 
B: Yes, S, I need a jacket (order #123). 

但HTTP ..已经这样做。所以如果有什么东西没有到位,你会知道的。连接超时,连接断开等。

现在,您可以在应用程序级别(输入WS-ReliableMessaging)中重新编写这些方案,但确实TCP已经可靠。对这些SOAP(ish)框架和人造协议(他们通常在HTTP之上工作)的一些批评者指责他们在更高级别的抽象层面上本质上重塑了轮子 - 轮子的问题。

底线是任何系统都可能失败,包括可靠的消息传递系统。

就最终一致性而言,我想你可能会感到困惑。最终的一致性仅适用于分布式存储系统,在Write()之后,您可能无法确定性检索Read()一段时间。这看起来并不像你的问题。我的意思是,我看到你在说什么,但是在一个eventually consistent系统中,假设节点之间有可靠的(足够的)连接。你不会做出这样的假设(即使我认为你应该...... TCP是相当可靠的)。

+0

有趣的评论。我所描述的确实可以模拟为分布式存储系统 - 但是大多数分布式系统都可以。想想看,你重复和参考TCP的方法正在攻击错误的问题(可能我曾经笨拙地描述过)。在公司之间IP连接关闭(没问题,只是重试),或者它工作。但后端系统经常停机,或者无法处理该非ASCII字符,或者对于超过35个字符的电子邮件地址有缓冲区溢出......所以更多的是关于“在正确的位置重试”。 – max 2010-11-03 22:30:28

建立在什么,蒂娜提到。 Webservices将是上述问题的完美解决方案。 有些协议可以商定哪些可以定义记录的数量。

S ---> D (Call a service which would list record keys) 
D----> S (provide xml of keys) 
S----> D (Request each of the records) 
D----> S (Submit record) 

在一个新的记录条目的情况下,同步后制成,目的地可以调用部署在源服务,这会处理的新纪录。

由于通信处理购买Web服务引擎,您不必担心消息参数。为了安全起见,可以添加SSL。

干杯!

我认为你试图说B公司是被动参与者。 S(供应商)只需要能够获得所有B岗位的订单(最终一致性)。但是B不需要也不关心S已经有什么命令(不需要提交)。

如果公司B具有半精确时钟,则可以使用日期作为单调递增的GUID,具体取决于事件的分辨率 - 无论如何您都不需要轮询是否需要毫秒分辨率。你只使用B的时钟,所以你不必担心同步。如果B公布所有订单,S可以从最后一次停止的订单中提取订单。

我不确定您是否意味着最佳实践或最佳折衷方案,以实现易于实施的系统。根据音量和响应时间,无论如何您都无需使其成为动态系统。将订单作为文本文件(由时间戳命名)转储到由日期命名的目录中,并将它们全部向下(或有选择地)拉下。你甚至可以按小时或任何有意义的方式将它们存储在目录中。 HTTP GET是幂等的。

这可能很丑陋,但听起来您并不认为B公司会带来太多复杂性。使用SSL和授权,它被锁定并加密。

如果你不需要性能,简单就没有问题。你真的从复杂的协议中获得了什么?

+0

在分钟左右的时间间隔内进行轮询的好主意,从而削弱了时钟同步的要求。 – max 2010-11-10 07:59:09