Elixir Phoenix

Table of Contents

Elixir非常适合web开发

可靠性

  • Elixir继承了Erlang语言的所有优势,并且提供了更加友好的语法和工具。可以理解为:Elixir是一个Erlang虚拟机的友好接口罢了。
  • Erlang从上个世纪[80年代](Erlang Programming Language)就开始被用来创建一些非常可靠的系统。Erlang被用来运行电话系统。电话系统如果不工作可要命了。并且因为他们要把服务运行在很多电话交换机上,他们就发明了并行运行代码的非常棒的模型。
  • Erlang的创造者就创建了一门[几乎不死机]的语言策略来运行复杂的系统。这些策略包括系统中多层级的监督者进程,当遇到错误的时候重启进程。当微服务广为人知之前他们已经在用微服务了。

并发

  • 近年来,CPU频率提升已经不大,但是CPU核心数却是越来越多。这就要求软件系统能够更具并发来适应硬件系统的发展——这就意味着系统的不同部分并行运行在不同的核心上。
  • 并发代码的主要问题就是 竞态 问题,导致非预期的结果。OO语言如Ruby不能很好地解决类似问题。但是函数式语言,如Elixir,可以解决类似问题。
  • 在Ruby中,我们从不会问“我能够创建另外一个对象吗?” Ruby的一切都是对象,并且创建对象的代价很小。我们想创建多少就创建多少。
  • 在Elixir中,进程就像对象——我们可以创建数以千计的进程,同时运行,并且从不用关心他们。这个能力简化了我们在Ruby中很多难题。

简单

  当我们写Rails应用时,需要依赖很多其他组件。Rails应用同一个时刻只能处理一个web请求,并且我们不能在需要时新创建进程,因此我们不得不

  • 在web服务前面应用 Ngnix 来处理并发
  • 请求然后 创建多个应用服务器实例 来处理并发请求
  • 我们不能在不阻塞web请求的情况下处理后台慢任务,因此我们不得不添加 redis和队列 来处理后台任务
  • 我们不能用珍贵的 进程 来维持用户连接,因此我们不得不添加 推服务 来增加实时功能
  • 我们不能让一个大的Ruby进程一直处理 定时任务 ,因此我们不得不增加 cron
  • 我们没有内置的Ruby工具来管理系统运行中的多个部分,因此我们只能使用[foreman](ddollar/foreman)和[god](A Process Monitoring Framework in Ruby)等来 启动和监控 系统。

  而在Elixir中,我们可以根据需要创建几乎无穷多个进程,因此我们可以(理论上) 放弃所有这些工具 。Elixir代码也比OO代码更容易理解,因为他们更明确。

Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler."

函数式编程与并发性有关,但它不是设计出来的。碰巧的是,通过明确系统的复杂部分,解决更复杂的问题(如并发性)变得简单多了。”

—— Jose Valim

性能

  • Phoenix web框架的性能比Rails高大概10倍,而且Phoenix服务器的负载更低
  • Rails更倾向于预处理请求。这会导致“链式响应”,因为Rails应用配置为只有固定数量的应用进程,因此如果有些进程慢了,会导致其他请求不得不等待,因此显著增加了响应时间。

  不用缓存的Phoenix应用比用了缓存的Ruby应用性能更高。这点很重要的原因是缓存极大的增加了系统地方复杂性和错误,并且缓存也不是时时有效的;根据Bleacher Report提供的数据显示,(他们使用Phoenix开发的系统)支持处理250K并发用户的新闻和推特。根据a talk their developers gave,他们的服务器从100个AWS缩减到了5个,cpu负载很少超过10%,并且性能比原来的Rails实现高出10多倍。

  Phoenix比Rails性能更高、内存更少的其中一个原因就是Erlang虚拟机处理string IO的方式。[一个Erlang web框架是这样描述的](About The Project)

无需缓存也很快

Erlang Respects Your RAM! Erlang is different from other platforms because when rendering a server-side template, it doesn't create a separate copy of a web page in memory for each connected client. Instead, it constructs pointers to the same pieces of immutable memory across multiple requests. So if two people request two different profile pages at the same time, they're actually sent the same chunks of memory for the header, footer, and other shared template snippets. The result is a server that can construct complex, uncached web pages for hundreds of users per second without breaking a sweat. With Erlang, you can run a website on a fraction of the hardware that Ruby and the JVM require, saving you money and operational headaches.

Erlang尊重你的内存!Erlang与其他平台的不同之处在于,当呈现服务器端模板时,它不会在内存中为每个连接的客户端创建一个单独的网页副本。相反,它在多个请求中构造指向同一块不可变内存的指针。因此,如果两个人同时请求两个不同的配置文件页面,他们实际上会为页眉、页脚和其他共享模板片段发送相同的内存块。其结果是,一台服务器可以毫不费力地每秒为数百个用户构建复杂的、未缓存的网页。使用Erlang,您可以在Ruby和JVM所需硬件的一小部分上运行网站,从而节省资金和解决操作上的麻烦。

vs Java

So, we like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds. We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.

所以,我们喜欢《Elixir》,并且看到它取得了一些巨大的成功。管理速率限制的Pinterest API和广告API的系统是建立在Elixir。它的50%响应时间约为500微秒,90%响应时间为800微秒。是的,微秒。我们还看到了代码清晰度的提高。我们正在将通知系统从Java转换为Elixir。Java版本使用了Actor系统,大约有1万行代码。新的Elixir系统将其缩小到1000行左右。基于Elixir的系统也比Java系统更快,更一致,并且运行在一半数量的服务器上。

伸缩性

  Erlang虚拟机的并发模型非常适合多核cpu,但是在多核cpu发明之前虚拟机就存在了。她的原始目的是通过在多个不同机器上运行来支持并发和容错。这就使得她提供了非常优秀的工具来创建轻松处理非常大的负载的系统,并且能够非常容易地增加服务器。就如Erlang web服务器文档所说:

At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU!

The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match.

Of course, various platforms need to scale beyond a few million connections. This is where Erlang's built-in distribution mechanisms come in. If one server isn't enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.

在撰写本文时,有一些用Erlang编写的应用程序服务器可以在实际生产应用程序的单个服务器上处理超过200万个连接,并且有空闲的内存和CPU!

Web是并发的,而Erlang是一种为并发性设计的语言,因此它是一个完美的匹配。

当然,各种平台需要扩展到数百万连接之外。这就是Erlang内置分发机制发挥作用的地方。如果一台服务器不够,那就添加更多!Erlang允许您使用相同的代码与本地进程或集群其他部分的进程进行通信,这意味着如果有需要,您可以非常快速地进行扩展。

灵活性

  使用Elixir和Phoenix打开了一扇创建应用的大门,这些是使用RoR不能达到的。Phoenix框架通过websockets(或者polling,作为降级方案)提供了实时通信功能。在基准测试中,单台服务器支持2百万持续链接!同时,他们也开发了支持iOS、Android和C#(视窗设备)本地channels客户端。有了这些支持,你可以轻松创建出聊天应用、网络游戏和更多其他的应用。

  Elixir还可以用在嵌入式设备如Nerves。这对于Ruby来说是不可想象的(即使有[mruby])。

Correctness

  Rails的ActiveRecord鼓励开发者在应用代码中做所有的数据检查。但是,依赖数据库状态的检查只能依赖数据库,用约束或者锁。这些包括:

  • 已经有用户使用这个用户名了么?(唯一性约束)
  • 我评论的文章5还存在么? (外键约束)
  • 现在用户账户中有足够的钱来购买这个东西么?(检查约束)
  • 现在这个出租物是否保留到6月8号?(日期范围约束)

  Rails应用使用这些约束是可能的,但是是非典型应用,工具也不建议使用这些约束。Elixir的Ecto数据库工具拥抱这些约束,也有内建的添加约束、捕获约束检查、返回用户友好的错误信息的支持。

模块热更新

  • 模块可以在不停止系统的情况下安全的热升级。
  • Erlang 的模块热升级是多版本并存的。假设一个进程真正跑,它使用的是老版本模块。那么升级的时候,新进程会使用新版本。互不干扰。即使新版本带来了新问题,你还可以无缝的降回去。当然,你愿意,也可以把老的进程干掉一些,直接强制到新版本。其他系统这么做实在太可怕。可是 Erlang 的进程是容错的,状态可恢复而且可升级的,所以这么做还是可行。
  • 只是应对一些局部小修改。如果模块间有复杂依赖,需要一次进行多个模块热更怎么办?放心吧。Erlang 有完整的方案。

独立的 Application

  • 其他语言里,程序基本上就是,一个主入口,然后调用其他第三方模块这样的设计。但是这个设计太简陋。
  • Erlang 的设计是,整个系统是由一系列独立运行的 Application 组成的。包括俗话说的“系统标准库”这种玩意儿,Erlang 里也是独立的 Application。

有何区别?

  • 每个 Application 都有自己的一个启动过程,自己的一组进程(构成监督树,具备独立的容错性)。相互之间运行时耦合是松散的。
  • 所以,A 和 B 两个 Application 你想运行在同一台计算机,或者多台不同的计算机上,代码没有差别。这就很像微服务了。
  • Erlang 有自己的 Shell 用来管理和控制这整个系统。而这个 Shell 里就是 Erlang 语言本身。完美的一致,简直是操作系统一样。顺带一提,Erlang 是可以写脚本的,叫做 escript。原汁原味,保证鲜美。

为什么不流行

  其实应该能 get 到为什么 Erlang 不流行了吧?我可以向你介绍很多 Erlang 的好。而且我可以保证它真的就是这么好。但是即使你能理解,你能学会,其他人能吗?很多人根本不在乎到底一个技术好不好,他们只在乎到底几天能够学会,多少工作岗位,以后跳槽好跳吗。这没有错。甚至很正确。

  • 因为大多数人还是以活着为前提在努力。
  • 市场是面向大众的。
  • 大众是平凡的。
  • 平凡的人,用平凡的产品。
  • 只有疯子,才会追求有趣和不凡。

  这就是为什么 Whatsapp 能在创业后不久,就以 190 亿美元卖给了 Facebook ;而他们只需要 50 个工程师,就能支撑 9 亿用户。

结论

  其实 Erlang 也并不是什么万金油,任何项目都适合。不是说选择了什么牛逼的东西,自己就会变得牛逼。而是因为一个工程师有牛逼的思想,才能够在茫茫工具海洋里,看出哪一个才是真牛逼。使用工具也要付出智力代价的。真的不是免费的。

  • 现在Elixir的库比Ruby少,因此有时候你不得不自己开发轮子,但是,你可以使用很多Erlang库
  • 新的Elixir库增加的很快
  • 任何缺失的功能都是你“展示自己”的好时候
  • Erlang是广为人知的。Elixir编译为Erlang字节码,运行在Erlang虚拟机,并且可以使用Erlang代码,也可以被Erlang调用。她只是“更加友好的Erlang”。
  • 任何Rails适合做的事情,Phoenix都合适做。

如果你的应用有如下特点的话,Phoenix最适合不过了:

  • 系统要求高吞吐量或者要求非常快速/实时响应;
  • 不宕机
  • 实时更新(如股票交易)
  • 双向实时通信(如聊天、游戏等)
  综上,这个语言注定是个屠龙技,很难大规模应用到实际项目中。所以,还是在空闲时,再偷偷研究吧。

资源

Date: 2023-10-19 Thu 14:50