为什么我们放弃了Erlang技术栈

简介: 结合小博无线技术团队的具体经验,深入讨论了Erlang技术栈在云计算环境中所遇到的问题。

至2013年小博无线云端系统上线以来,我们一直是Erlang的重度使用者。尽管小博无线技术团队不乏拥有10年以上经验的精英级Erlang程序员,然而,从2016年开始,我们已不再使用Erlang开发新业务,而我们放弃Erlang技术栈的原因可被简要概括为下面这句话:

让开发和运维更简单

总的来说,Erlang技术栈的优点在云计算环境中要么难以体现,要么容易寻找到成熟的替代方案,但弱点却既顽强又难以绕开。以下逐一展开说明。

优点: 易用的高并发轻量级进程

这一度是Erlang独有的优势,但在今天,基于nginx+lua的openresty框架和golang都能提供,并且后两者还拥有更好的社区生态。

优点: 公平可靠的软实时调度

虽然lua, golang, nodejs在语言层面都内置了高并发机制,然而,不论是lua中需手动调用yield/resume的coroutine,或是golang中在系统调用时插入yield的goroutine,还是nodejs中依靠异步io回调实现的单线程多并发,都存在面对cpu密集型计算任务时调度不均的问题,因为它们都没有实现cpu使用统计与抢占式调度器。

Erlang VM对每个进程[1]的cpu占用进行了统计并实现了抢占式调度,即使某个进程不停计算,其他进程也不会被饿死。

这听上去很好,但在互联网业务系统中,却并没有多少实用价值。如果发现有部分业务计算逻辑需要消耗大量cpu以致影响了系统的整体响应或吞吐,说明应当将这部分计算功能抽离到一个单独的运行环境并给它分配更多的资源,而不是依赖VM的抢占调度!

优点: 位置透明性

Erlang内建的rpc机制可以让任意两个进程相互之间无需知晓对方的所在的结点,仅通过pid就能透明的向对方发送消息。

这一优点可以使用成熟的消息队列中间件获得,消息队列中间件能自然实现业务处理的前后端分离,并且前后端还可独立进行伸缩。

优点: 热更新

采用Erlang构建的系统可以在服务不中断,用户无感知的情况下部署变更。

使用“漂移上线”[2]可以获得同样的效果,并且对于采用任何技术栈构建的系统都是有效的。

弱点:全连通集群

Erlang集群采用的是全连通的组网方式,每加入一个新节点,都需要在当前集群中所有节点的/etc/hosts文件中加入这个新节点的hostname和ip,这样的设计使得伸缩和漂移都非常麻烦。

在云计算环境中,使用以负载均衡器为根,业务容器为叶结点的网络拓扑则要简单很多,可以很方便的实现秒级伸缩和漂移。

一种绕开的方案是自建DNS服务负责集群的域名解析,然而,这个方案又会带来诸如DNS服务的高可用性,新建记录的生效时间以及本地记录的缓存刷新等一系列问题。

弱点:部署之痛

Erlang设计的运行时是直接运行于宿主机上的,当第一次启动Erlang VM, 会随之启动一个epmd进程来负责集群结点之间的通信。这样的设计与容器化的部署方案格格不入,导致很难在一个宿主机上运行两个位于不同集群的Erlang容器。

弱点:数据库之伤

OTP中的mnesia是Erlang技术栈标配的高性能分布式内存数据库,支持对原生erlang term的透明存取,就单一的Erlang系统而言,mnesia的易用性和性能都是不错的。但是,在一个较复杂的云端系统中,它存在下面几个劣势:

  • 定位过于专一,除了erlang外,几乎找不到其他编程语言可用的客户端,只能通过erlang代码代理访问,导致开发成本高
  • 本身太小众,云厂商不会提供基于mnesia的SasS服务,只能自建,而且mnesia的数据分片功能对网络稳定性有很高的要求,导致运维成本高
  • 未对数据进行压缩存储,当数据量上去后,会消耗大量内存,导致资源成本高

现在,我们已从mnesia全面切换到了redis。


[1]这里的“进程”指的是由Erlang VM负责调度的轻量级进程,而不是由内核调度的OS原生进程

[2]《云计算十字真言及其在小博无线的实践》(https://yq.aliyun.com/articles/62686) 一文详细介绍了“漂移上线”的设计思路以及一种具体的实现方法

目录
打赏
0
2
2
2
32
分享
相关文章
哇塞!Ruby 代理模式太逆天啦!实现延迟加载,让你的程序性能飙升,快来一探究竟!
【8月更文挑战第31天】在软件开发中,设计模式提供了可靠的解决方案,有助于构建可维护和可扩展的系统。代理模式是一种常用模式,尤其适用于 Ruby,可实现延迟加载等优化。本文以 Ruby 为例,介绍如何利用模块和方法委托实现图像延迟加载,从而提升性能。通过代理模式,首次访问时才加载图像数据,节省资源。此外,代理模式还支持访问控制、日志记录和缓存等功能,但需注意可能增加代码复杂性。合理应用该模式可显著提升软件质量和性能。
50 0
我佛了!Java开发者福音:并发编程源码剖析+高并发系统搭建
多线程和高并发的关系和区别 “高并发和多线程”总是被人一起提起,给人感觉两者好像相等,实则 高并发 ≠ 多线程 多线程 多线程是Java的特性,因为现在cpu都是多核多线程的,可以同时执行几个任务,为了提高jvm的执行效率,Java提供了这种多线程的机制,以增强数据处理效率。多线程对应的是cpu,高并发对应的是访问请求,可以用单线程处理所有访问请求,也可以用多线程同时处理访问请求。
NodeJS 多线程发展史
在开始了解多线程之前先来了解一下程序任务按照性能的分类,从性能方面来看,计算机程序主要分为两个维度,CPU密集型(也叫计算密集型)和UO密集型。
342 0
RabbitMQ面试必备知识点及实战(二)-核心概念(下)
RabbitMQ面试必备知识点及实战(二)-核心概念(下)
101 0
RabbitMQ面试必备知识点及实战(二)-核心概念(下)
Go语言学习笔记(二)十分钟上手
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 变量&常量 变量   变量名由字母、数字、下划线组成,不能以数字开头。 ... var ( A int //默认为0 B string //默认为"" C bool //默认为f...
1036 0

热门文章

最新文章