【问题标题】:How to ensure message transfer by pull-/polling from a webserver如何通过从网络服务器拉取/轮询来确保消息传输
【发布时间】:2011-05-01 03:13:36
【问题描述】:

这建立在How to send messages between Companies 之上。如果我决定公司 S(供应商)应该以某种简单的基于 HTTP 的方式轮询公司(B)的订单,那么最好的实现是什么。

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

实施这样一个系统的最佳实践是什么?

【问题讨论】:

    标签: rest soap distributed-computing edi b2b


    【解决方案1】:

    解决此类问题的一种方法是使用某种排队产品,作为 IBM 人员,我立即考虑使用 MQ。但是,由于我本人实际上并不是 MQ 人,因此我可能会对您采用的基于服务的方法感到满意。

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

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

    那么,自己动手呢?这里的关键是使所有服务具有幂等性。由于我们没有跨两个系统的事务保证,我们必须假设任何给定的服务调用都可能失败并导致未知结果。

    我将假设 B 想要确认 S 已接受订单,因此我们需要在订单转移时更新 B 和 S 的信息。

    B 必须提供以下服务:

     Give me the next order(s)
    
     I have stored {orders ...}
    

    那么我们如何定义“下一个”。如果我们正在处理的卷可以让我们拥有一个传输“线程”,那么最简单的情况就可以很好地工作。然后 B 正在逐个打勾发送的订单,并且订单的 ID 单调递增。然后我们可以简化为:

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

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

    【讨论】:

    • 单调递增的ID在e分布式系统中有些困难,但我们可以附加一个:“我现在已经存储了消息,你可以删除它”请求。
    • 你能给我一个“Webservices”的例子吗?WS-* 堆栈对我来说似乎是一个不兼容的复杂混乱,但这可能只是我缺乏经验。在 Github 上哪里可以找到 WS-* 的 Ruby/Python/PHP/Perl 库?
    【解决方案2】:

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

    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 
    

    应该适用于任何类型的数据。

    【讨论】:

    • 我认为让“另一端”实现(和测试)两阶段原子提交会相当困难。
    【解决方案3】:

    好的,首先,您不能通过不可靠的链接保证任何事情。 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 非常可靠)。

    【讨论】:

    • 有趣的评论。我所描述的确实可以建模为分布式存储系统 - 但大多数分布式系统都可以。想想你重复和引用 TCP 的方法是在攻击错误的问题(可能我描述得很笨拙)。公司之间的 IP 连接已关闭(没问题,只需重试)或它可以正常工作。但是后端系统经常出现故障,或者无法处理非 ASCII 字符,或者超过 35 个字符的电子邮件地址出现缓冲区溢出……所以更多的是“在正确的位置重试”。跨度>
    【解决方案4】:

    建立在迪娜提到的基础上。 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)
    

    如果在同步后创建了新记录条目,Destination 可以调用在源处部署的服务,该服务将处理新记录。

    由于通信是处理购买一个网络服务引擎,你不必担心消息参数。可以添加 SSL 以确保安全。

    干杯!

    【讨论】:

      【解决方案5】:

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

      如果 B 公司有一个半准确的时钟,您可以使用日期作为单调递增的 GUID,具体取决于事件的分辨率 - 如果您需要毫秒分辨率,您不会想要轮询。您只使用 B 的时钟,因此您不必担心同步问题。如果 B 发布了所有订单,则 S 可以从上次停止的地方继续接单。

      我不确定您是否指的是易于实施的系统的最佳做法或最佳权衡。根据音量和响应时间,如果您要轮询,则无需将其设为动态系统。将订单作为文本文件(以时间戳命名)转储到以日期命名的目录中,并将它们全部下拉(或有选择地)。您甚至可以按小时或任何有意义的方式将它们存储在目录中。 HTTP GET 是幂等的。

      这可能很难看,但听起来您并不期望 B 公司有太多复杂性。使用 SSL 和身份验证,它会被锁定和加密。

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

      【讨论】:

      • 以分钟左右的间隔轮询的好主意,从而削弱了时钟同步要求。
      猜你喜欢
      • 2014-05-02
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多