1 序
准备花一些时间介绍Erlang。
Erlang算不上是一种“大众流行”的程序设计语言。就年龄而言,Erlang 大约与Perl同年,比C++年轻四岁,长Java差不多十岁,但Java早已经是工业主流语言,C++和Perl 甚至已经进入其生命周期的下降阶段。照理说,一个被扔在角落里二十多载无人理睬的设计语言合理的命运就是被慢慢淘汰,没想到Erlang却像是吃了返老还童丹似的青春常在,这是怎么回事呢?
借用Erlang创始人Joe Armstrong的话:这个世界是并行的, 如果希望将程序的行为设计得与真实世界物体的行为相一致,那么 程序就应该具有并发结构,Erlang程序模拟了人类如何思考,如何交互。
换言之,普通的过程语言,注重的是术;而Erlang注重的是道。
2 MQTT
现在的物联网概念似乎无处不在。提到物联网,就离不开MQTT。
MQTT 是一种发布/订阅协议,专为连接物联网(IoT)设备而设计。与 HTTP 的请求/响应模式不同,MQTT 采用事件驱动的方式工作,允许消息被推送到客户端。此架构方法通过解耦数据生产者和数据消费者,消除了它们之间的依赖关系,从而实现高度可扩展的解决方案。在 MQTT 连接中,消息的发布和订阅依赖两个关键组件:MQTT 客户端和MQTT 代理(Broker)
- MQTT 客户端:设备或应用程序,负责向代理发布消息或从代理订阅消息。
- MQTT 代理(Broker):消息中介,负责管理客户端之间的通信,确保消息正确传递。
这种发布/订阅模式非常适合高频、低带宽的物联网环境,支持海量并发连接。客户端比较简单,我们按下不表。到目前为止,比较流行的 MQTT Broker 有几个:
- Eclipse Mosquitto
使用 C 语言实现的 MQTT Broker。Eclipse 组织还还包含了大量的 MQTT 客户端项目; - EMQX
使用 Erlang 语言开发的 MQTT Broker,支持许多其他 IoT 协议比如 CoAP、LwM2M 等; - Mosca
使用 Node.JS 开发的 MQTT Broker,简单易用; - VerneMQ
同样使用 Erlang 开发的 MQTT Broker。
从支持 MQTT5.0、稳定性、扩展性、集群能力等方面考虑,EMQX 的表现应该是最好的。
3 EMQX
EMQX 是一款高度可扩展的分布式 MQTT Broker,适用于企业级的工业物联网部署。它支持 MQTT 5.0、MQTT-SN、SSL/TLS、MQTT over QUIC 等多种协议。它通过集群方式实现了高可用性和水平扩展性。
凭借在 GitHub 上的 11.5k 个 Star,EMQX 已经成为市场上最受欢迎的 MQTT Broker 之一。EMQX 项目于 2012 年启动,采用 Apache 2.0 许可证进行开源。EMQX 由 Erlang/OTP 编写,这是一种能够构建高度可扩展的软实时系统的编程语言。
兜兜转转,终于说到Erlang啦!
那么Erlang究竟何德何能,如此历久弥新,在服务器领域大放异彩呢?
4 Erlang哲学
4.1 大不了重头再来
工作中,经常帮助企业排除大型网络中协议的故障,这些问题真是千奇百怪。实在没有办法时,一般是终极必杀:重启交换机。生活告诉我们,重启有时候是个好办法。
Erlang的思想是不要怕崩溃,某些地方有问题如果无法解决,则将这个地方局部重启,是不是和现实生活中很多场景很类似?它采用进程的分层容错机制实现分层监督控制,能够根据问题出现点按必要的粒度进行自动重启。
上图是一个分层的监督机制,如果出于某种原因监督者A崩溃或退出,它辖区内所有还在存活的进程都会被强制关闭,同时C会收到通知,于是进程树的左半边会被重启,监督者B不受影响,除非C决定关闭整个系统。
当你还在绝望地纠结于如何挽回那些你可能根本无能无力的局面时,Erlang哲学却是鼓励崩溃:精确记下事发位置和经过,把一切彻底抛下重新再来。这不太常见,但的确是一条强大的容错秘诀,而且按这个思路建立起来的系统无论多高复杂度均可调试。
4.2 世界是并行的
在现实世界里,万事是并行发生的,但在大多数编程语言里事情是顺序发生的。现实世界并行性和编程语言顺序性之间的不匹配,使得用顺序性语言编写控制现实问题的程序变得困难。 在Erlang里,可以直观地将现实世界的并行性映射到Erlang的并发性上。这就使代码变得清晰和易于理解。
编程语言有两种:顺序和并发。顺序语言被设计用于编写顺序程序,没有描述并发计算的语言结构。并发编程语言被设计用于编写并发程序,语言本身带有表达并发性的特殊结构,如Erlang中进程和并发是可以用来定型和解决问题的工具。这使按粒度控制程序的并发结构成为可能,而用操作系统的进程是很难做到的。
4.3 任务是相似的
在代码的世界忙忙碌碌,无非就是多些功劳,少些BUG。
Erlang提供了一个并发系统平台(OTP),可以让我们少费很多脑筋。且让我们看看OTP优点:
- 生产效率: 运用OTP可在短时间内交付产品级的系统
- 稳定性:基于OTP可以更集中于逻辑,并避免重新实现那些容易出错而每个实际系统又都必备的基础功能,比如进程管理、服务器、状态机等
- 监督:OTP提供一套简便易行的分级监督控制方案
- 可升级:OTP框架为处理代码升级提供了一套系统化的模式,注意:是可以热升级的!
- 可靠: OTP的代码坚如磐石并全部经过严格的实战检验
4.4 软实时
Erlang 最开始是给电话系统使用的,目前这个星球上有近一半的电话系统是用 Erlang写的,这就要求它必须保证处理响应在可接受的时间范围内。 相比绝大多数软实时系统而言,Erlang对软实时的支持是最为理想的,这主要因为它拥有一个低延迟的垃圾回收机制和高效的并发模型,可以处理成千上万的并发进程。而且,这些进程在虚拟机中相互独立,一个进程的崩溃不会影响到其他进程,这增加了系统的稳定性。
5 结语
上面简单介绍了一些Erlang的特点,只是从另外一个角度来看解决技术问题的宏观构思,如果我们采用不同思想来看问题,结果会大不同。
以一个大家比较熟悉领域的例子作为结尾。在嵌入式领域,为了实现实时功能,有很多RTOS系统供选择,它在提供诸多便利的同时,也会带来很多负担和约束。其实在绝大部分情况下,对于大多数的嵌入式应用,根本没有必要采用RTOS,对于多任务切换,采用状态机的方式就可以达到目的,如果采用状态机思想,在一个普通的72M的STM32MCU上面,实现us级别的N多任务切换,是一件很简单的事。 Erlang为提供了很多类似的思想窗口,可以打开看一下不同的世界。