我阅读了官方文档和官方白皮书,但在以下情况下,我无法找到Thrift如何处理故障的令人满意的答案:
假设您有一个客户端向服务器发送方法调用,以在一个驻留在该服务器中的数据结构中插入一个条目(它实际上并不重要)。假设服务器已处理呼叫并插入条目,但客户端由于网络故障而无法接收响应。在这种情况下,客户应该如何处理?发送呼叫的简单重试可能导致插入重复条目。 Thrift库是否会在某处保留响应,以便在重新联机时重新发送给客户端?或者这样做的责任是什么?
如果有人可以指出其工作原理的详细信息,除了指向其源代码外,我将不胜感激。
答案 0 :(得分:2)
这个问题很有意思,但绝不仅限于Thrift。更好的名字是
因为它本质上就是它的本质。在RPC风格的API的特定情况下,例如Thrift服务,客户端阻塞并且似乎是同步调用,它实际上不是这样的。
整个问题可以改写为关于
的更普遍的问题那么我们必须处理的主要问题是什么?我们必须假设我们所做的每一次电话都可能失败。特别是,它可能以三种方式失败:
在某些情况下,无论具体情况如何,这都不是什么大问题。如果客户只想检索一些值,他可以简单地重新查询,如果他经常尝试的话,最终会得到一些结果。
在其他情况下,尤其是当客户端修改服务器上的数据时,可能会出现更多问题。在这种情况下,一般建议是使服务调用 idempotent ,这意味着:无论我多久进行一次相同的呼叫,最终结果总是相同的。这可以通过各种手段来实现,或多或少取决于用例。
例如,一种方法是发送一些逻辑"票"值与每个请求一起过滤掉服务器上的加倍或过期请求。在最终处理开始之前,服务器会跟踪和/或检查这些票证。但同样,如果该方法适合您的需求取决于您的用例。
Command and Query Responsibility Segregation (CQRS) pattern是另一种处理复杂性的方法。它基本上将API分解为setter和getter。我建议调查这个主题,但它对每个场景都没用。我还建议您查看Data Consistency Primer文章。最后,CAP theorem总是很好读。
良好的服务/ API设计并不简单,而且我们必须处理分布式并行系统这一事实并不容易,恰恰相反。
答案 1 :(得分:2)
让我试着直接回答。
<块引用>... 这样做是应用程序的责任吗?
是的。
Thrift RPC 涉及 4 种异常类型,包括 TTransportException、TProtocolException、TApplicationException 和 User-defined例外。
根据Apache Thrift 程序员指南一书,前 2 个是本地例外,而后 2 个不是。
顾名思义,TTransportException 包括 NOT_OPEN、TIMED_OUT 等异常,TProtocolException 包括 INVALID_DATA、BAD_VERSION等。这些异常不会从服务器传播到客户端,其行为与普通语言异常非常相似。
TApplicationException 涉及诸如调用未实现的方法或未能为方法提供必要参数等问题。
用户定义的异常在 IDL 文件中定义并由用户代码引发。
对于所有这些异常,Thrift RPC 框架本身不会执行任何重试操作。相反,它们应该由应用程序代码正确处理。