Elixir 分布式平台
概述
分布式平台的核心在于并发,容错。 而 Elixir 的优势正是在于对于并发和容错的处理。
分布式模型
- CSP(Communicating Sequential Process) 模型 :: 多个进程通过管道(channel)进行交互
- Actor 模型 :: 每个进程管理自己的内部状态,通过消息和外界交互
对于 CSP 来说,重点在与 channel,通过 channel 管理并发的任务,并不关心执行任务的执行者。 Actor 模型关心的是任务的执行者(也就是 Actor),每个 Actor 都是可以通过消息和外界交互,根据消息完成任务。
Elixir 采用的是 Actor 模型,golang 的并发是 CSP 模型。
并发
并行(concurrency)经常会和并行(parallelize)的概率混淆,并发是指同时发生,并行是指同时运行, 比如,在一个 4core 的机器上,并发的量可能上万,但是并行可能只有 4。
Elixir 的并发是由 BEAM VM 来管理的,理论上,一个 BEAM VM 上可以创建 268,000,000 个进程,基本就可以当做是无限制。 一般来说,BEAM VM 都是通过少量的调度进程来管理大量的 processes Elixir 的并发进程之间不会共享任何东西(包括内存在内)。
容错
对错误的处理方式,最普遍的就是 try/catch,这种方式对于单机的系统来说可以适用,但是对于分布式系统来说,存在不足之处:
- 分布式系统涉及多个系统间的交互,try/catch 只能在单点上捕获异常
- 分布式系统中可能发生的错误往往很难重现,也无法预测,即使捕获到异常,也很难预置处理方式,也就是很多异常会导致系统无法恢复
- try/catch 机制一般都是捕获错误,然后自己处理或者直接往上层抛异常,随着系统的复杂,异常的层级也会越来越多
Elixir 中也有类似 try/catch 的机制,但是它的容错性不是依靠这种机制来保证的。 Elixir 不是致力于去减少错误的发生,而是致力于提供一种机制去减少错误的影响,并使得系统能够自己从错误中恢复。
Elixir 中通过进程树来确保整个应用的可用性,少数几个进程作为 supervisor,用来监管其他完成实际业务的进程。 如果进程出现问题,由 supervisor 进程负责重启或者销毁。
除了进程树,对于分布式系统的容错,Erlang 的理念是 let it crash 原因也就是因为在分布式系统中,很多的错误和环境相关,难于重现,并且很多时候在错误的基础上恢复系统相当困难, 远远没有直接重启来的简单有效。
当然,let it crash 不是 let everything crash,以下情况还是要处理:
- 对于关键性的进程,是绝对不能让它 crash 的,比如有些主干上的 supervisor - 可以预期的错误,就要有对应的错误处理,不能什么都靠重启来解决 - let it crash 是指把那些无法预期的错误交给 supervisor 来处理
OTP 平台
OTP 平台的分布式系统核心是 process 和 message Elixir 本身也可以实现非常健壮的分布式系统,但是借助 OTP 平台上已经成熟的组件,可以更快的创建一个分布式应用
下面是 OTP 平台上提供的成熟组件:(各个组件的示例参考:)
- agent
- GenServer
- GenEvent
- task
- supervisor
上一篇: Erlang调度器细节探析