gpt4 book ai didi

transactions - Erlang/OTP 消息可靠吗?消息可以复制吗?

转载 作者:行者123 更新时间:2023-12-03 01:12:54 29 4
gpt4 key购买 nike

长版:

我是 erlang 的新手,正在考虑将它用于可扩展的架构。我发现该平台的许多支持者都在吹捧其可靠性和容错性。

但是,我正在努力理解在消息在 transient 内存中排队的系统中究竟是如何实现容错的。我知道可以安排一个主管层次结构来重生已故的进程,但我一直无法找到关于重生对正在进行的工作的影响的太多讨论。传输中的消息和在垂死节点上丢失的部分完成工作的工件会发生什么?

当消费者进程死亡时,所有生产者是否会自动重新传输未被确认的消息?如果不是,这怎么能被认为是容错的?如果是这样,是什么阻止了已处理的消息——但没有得到完全确认——被重新传输,从而不适本地重新处理?

(我认识到这些问题并不是 erlang 独有的;类似的问题会出现在任何分布式处理系统中。但 erlang 爱好者似乎声称该平台使这一切变得“容易”......?)

假设消息被重传,我可以很容易地想象一个场景,在一个复杂的消息链的下游影响在发生故障后可能变得非常困惑。如果没有某种繁重的分布式事务系统,我不明白如何在不解决每个过程中的重复的情况下保持一致性和正确性。我的应用程序代码必须始终强制执行约束以防止事务被多次执行吗?

短版:

分布式 erlang 进程是否会受到重复消息的影响?如果是这样,重复保护(即幂等性)是应用程序的责任,还是 erlang/OTP 以某种方式帮助我们解决这个问题?

最佳答案

我将把它分成我希望有意义的几点。我可能会重新散列一些我在 The Hitchhiker's Guide to Concurrency 中写的内容.您可能想阅读那篇文章以了解有关在 Erlang 中完成消息传递方式背后的基本原理的详细信息。

1.消息传输

Erlang 中的消息传递是通过发送到邮箱(一种用于存储数据的队列)的异步消息来完成的。绝对没有关于是否收到消息的假设,甚至没有假设它被发送到一个有效的进程。这是因为可以合理地假设 [在语言级别] 有人可能只想在 4 天内处理一条消息,甚至在它达到某种状态之前都不会承认它的存在。

一个随机的例子可能是想象一个长时间运行的过程,它处理数据 4 小时。如果它无法处理它,它真的应该承认它收到了一条消息吗?也许应该,也许不。这实际上取决于您的应用程序。因此,不做任何假设。你可以让一半的消息异步,只有一个不是。

Erlang 期望您在需要时发送确认消息(并在超时后等待)。与超时有关的规则和回复的格式留给程序员指定——Erlang 不能假设你想要消息接收时的确认,当任务完成时,无论它是否匹配(消息当新版本的代码热加载时,可以在 4 小时内匹配)等。

简而言之,如果您不希望消息在传输过程中未被读取、无法接收或被某人拔掉插头打断,这并不重要。如果你想让它重要,你需要设计一个跨进程的逻辑。

在 Erlang 进程之间实现高级消息协议(protocol)的负担交给了程序员。

2.消息协议(protocol)

正如您所说,这些消息存储在 transient 内存中:如果一个进程死亡,它尚未读取的所有消息都将丢失。如果您想要更多,则有多种策略。其中一些是:

  • 尽快读取消息并在需要时将其写入磁盘,发送回确认并稍后处理。将此与具有持久队列的队列软件(例如 RabbitMQ 和 ActiveMQ)进行比较。
  • 使用进程组在多个节点上的一组进程中复制消息。此时,您可能会输入事务语义。这个用于事务提交的mnesia数据库;
  • 在您收到一切正常的确认或失败消息之前,不要假设任何事情都有效
  • 进程组和失败消息的组合。如果第一个进程无法处理任务(因为节点出现故障),VM 会自动向故障转移进程发送通知,由后者来处理它。此方法有时与完整应用程序一起使用以处理硬件故障。

  • 根据手头的任务,您可以使用其中的一个或多个。它们都可以在 Erlang 中实现,并且在许多情况下,模块已经被编写来为您完成繁重的工作。

    所以这可能会回答你的问题。 因为您自己实现协议(protocol),所以您可以选择是否多次发送消息。

    3.什么是容错

    选择上述策略之一确实取决于容错对您意味着什么。在某些情况下,人们的意思是“没有数据丢失,没有任务失败”。其他人使用容错说“用户永远不会看到崩溃”。在 Erlang 系统的情况下,通常的含义是保持系统运行:也许让一个用户挂断电话而不是让每个人都挂断电话是可以的。

    这里的想法是让失败的东西失败,但让其余的东西继续运行。为了实现这一点,VM 为您提供了一些东西:
  • 您可以知道进程何时终止以及它为何终止
  • 如果其中一个出错,您可以强制相互依赖的进程一起死亡
  • 您可以运行一个记录器,为您自动记录每个未捕获的异常,甚至定义您自己的
  • 可以监控节点,以便您知道它们何时出现故障(或断开连接)
  • 您可以重新启动失败的进程(或失败的进程组)
  • 如果一个节点失败,让整个应用程序在不同的节点上重新启动
  • 还有更多关于 OTP 框架的内容

  • 使用这些工具和一些为您处理不同场景的标准库模块,您可以在 Erlang 的异步语义之上实现几乎您想要的东西,尽管能够使用 Erlang 的容错定义通常是值得的。

    4. 一些注意事项

    我个人的观点是,除非你想要纯事务语义,否则很难有比 Erlang 中存在的更多的假设。您将始终遇到的一个问题是节点出现故障。您永远无法知道它们是否因为服务器实际崩溃或网络故障而停机。

    在服务器崩溃的情况下,只需重新执行任务就足够容易了。但是,对于净拆分,您必须确保某些重要操作不会被执行两次,但也不会丢失。

    它通常归结为 CAP theorem这基本上为您提供了 3 个选项,您必须从中选择两个:
  • 一致性
  • 分区容差
  • 可用性

  • 根据您定位自己的位置,将需要不同的方法。 CAP 定理通常用于描述数据库,但我相信每当您在处理数据时需要某种程度的容错能力时,都会提出类似的问题。

    关于transactions - Erlang/OTP 消息可靠吗?消息可以复制吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3172542/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com