我在Erlang社区网站Trapexit中发现了以下声明:
Erlang是一种使用的编程语言 构建可大规模扩展的软件 具有要求的实时系统 高可用性。
此外,我还记得在Twitter上从Twitter切换到Scala以解决可扩展性问题。
因此,我想知道编程语言与可伸缩性之间的关系是什么?
我认为可伸缩性仅取决于系统设计,异常处理等。这是因为语言的实现方式,库还是其他一些原因?
希望得到启迪。感谢。
答案 0 :(得分:7)
Erlang针对电信环境进行了高度优化,运行时间为5 9s左右。
它包含一组名为OTP的库,可以在不关闭应用程序的情况下将代码重新加载到应用程序中!此外,还有一个管理程序模块的框架等等,这样当出现故障时,它会自动重新启动,否则故障会逐渐自行运行,直到它到达可以处理它的管理程序模块。 / p>
当然,在其他语言中也是可能的。在C ++中,您可以动态重新加载dll,加载插件。在Python中,您可以重新加载模块。在C#中,您可以在运行中加载代码,使用反射等等。
只是该功能内置于Erlang中,这意味着:
也就是说,语言之间存在一些根本性的区别,有些是被解释的,有些是字节码运行,有些是本机编译的,所以性能和运行时类型信息等的可用性不同。 / p>
Python在其运行时库周围有一个全局解释器锁,因此无法使用SMP。
Erlang最近才添加了更改以利用SMP。
一般来说,我同意你的观点,我觉得一个重要的区别在于内置的库,而不是语言本身之间的根本区别。
最终,我觉得任何变得非常大的项目都会因为写入的语言而陷入困境。正如你所说,我觉得架构和设计对于可扩展性非常重要,而选择一种语言不是另一种语言。感觉神奇地提供了令人敬畏的可扩展性......
答案 1 :(得分:4)
Erlang来自于另一种考虑可靠性以及如何实现可靠性的文化。理解文化是很重要的,因为Erlang代码不会因为它的Erlang而被魔法变为容错。
一个基本的想法是,如果发生故障,高正常运行时间不仅来自非常长的平均故障时间,而且还来自非常短的平均恢复时间。
然后人们意识到,当检测到故障时,需要自动重启。并且人们意识到,在第一次检测到不太正确的事情时,应该“崩溃”以导致重启。需要优化恢复,并且可能的信息损失需要最小化。
此策略之后是许多成功的软件,例如日记文件系统或事务日志数据库。但绝大多数情况下,软件往往只考虑故障之间的平均时间,并向系统日志发送有关错误指示的消息,然后尝试继续运行,直到不再可能。通常需要人工监控系统并手动重启。
这些策略中的大多数都是Erlang中的库形式。作为语言特征的部分是进程可以相互“链接”和“监视”。第一个是双向合同,“如果你崩溃,那么我得到你的崩溃消息,如果没有被困,将使我崩溃”,第二个是“如果你崩溃,我得到一条消息”。
链接和监视是库用于确保其他进程尚未崩溃的机制。流程被组织成“监督”树。如果树中的工作进程失败,则主管将尝试重新启动它,或者树中该分支的同一级别的所有工作程序。如果失败则会升级,等等。如果顶级主管放弃应用程序崩溃并且虚拟机退出,那么系统操作员应该重新启动计算机。
过程堆之间的完全隔离是Erlang表现良好的另一个原因。除了少数例外,在进程之间“共享值”是不可能的。这意味着所有进程都是非常独立的,并且通常不会受到另一个进程崩溃的影响。此属性也存在于Erlang集群中的节点之间,因此处理未通过集群的节点的风险较低。复制并发送更改事件而不是单点故障。
Erlang采用的哲学有很多名称,“快速失败”,“仅崩溃系统”,“面向恢复的编程”,“暴露错误”,“微重启”,“复制”......
答案 2 :(得分:2)
Erlang是一种设计时考虑了并发性的语言。虽然大多数语言都依赖于操作系统来实现多线程,但Erlang内置了并发性。 Erlang程序可以由数千到数百万个极轻量级的进程组成,这些进程可以在单个处理器上运行,可以在多核处理器上运行,也可以在处理器网络上运行。 Erlang还为进程之间的消息传递,容错等提供语言级支持.Erlang的核心是一种函数式语言,函数式编程是构建并发系统的最佳范例。
简而言之,在Erlang中制作分布式,可靠且可扩展的系统非常简单,因为它是专门为此目的而设计的语言。
答案 3 :(得分:2)
简而言之,“语言”主要影响缩放的垂直轴 ,但不会影响您在问题中已经提到过的所有方面。这里有两件事:
1)可扩展性需要根据有形度量进行定义。我建议钱。
S =用户数/费用
如果没有足够的定义,我们将讨论这一点 ad vitam eternam 。使用我提出的定义,比较系统实现变得更容易。要使系统可扩展(读取:有利可图),则:
可扩展性随着S
而增长
2)系统可以根据2个主轴进行缩放:
a)垂直扩展涉及隔离增强节点,即更大的服务器,更多的RAM等。
b)水平缩放与通过添加节点来增强系统有关。这个过程涉及更多,因为它需要处理现实世界的属性,如光速(延迟),分区容忍,多种类型的故障等。
(Node =>物理分离,与另一个不同的“命运共享”)
遗憾的是,可扩展性这个术语经常被滥用。
很多时候,人们会将语言与库和&实施。这些都是不同的东西。使语言适合特定系统的原因通常更多地与围绕所述语言的支持有关:库,开发工具,实现效率(即内存占用,内置函数的性能等) 。)
在Erlang的情况下,它恰好被设计为具有真实世界约束(例如分布式环境,失败,需要可用性以满足违约赔偿金暴露等)作为输入要求。 / p>
无论如何,我可以在这里待上太久。
答案 4 :(得分:1)
首先,您必须区分语言及其实现。例如ruby语言支持线程,但在官方实现中,线程不会使用多核芯片。
然后,语言/实现/算法通常被称为可伸缩,当它支持并行计算时(例如通过多线程)并且当CPU数量增加时它表现出良好的加速增长(参见Amdahl Law)。
Erlang , Scala , Oz 等语言也有语法(或很好的库),有助于编写清晰明了的并行代码
答案 5 :(得分:1)
除了这里提到的关于Erlang(我不知道)的观点之外,还有一种语言更适合脚本和较小的任务。
像ruby和python这样的语言有一些功能,这些功能非常适合原型设计和创造性,但对于大型项目来说却很糟糕。可以说,他们最好的特点是缺乏“正规性”,这在大型项目中会让你受伤。
例如,静态类型是小脚本类型事物的麻烦,并使像java这样的语言非常冗长。但是在具有数百或数千个类的项目中,您可以轻松查看变量类型。将其与可以容纳异构集合的地图和数组进行比较,作为类的使用者,您无法轻易地知道它所持有的数据类型。随着系统变得越来越大,这种事情变得更加复杂。例如你也可以做一些非常难以追踪的事情,比如在运行时动态地向类添加位(这可能很有趣,但如果你试图弄清楚数据的来源是一个噩梦),还是调用引发的方法没有被编译器强制声明异常的异常。并不是说你不能用优秀的设计和规范的编程解决这些问题 - 这样做更难。
作为一个极端情况,你可以(抛开性能问题)用shell脚本构建一个大型系统,你可以通过非常处理一些混乱,缺乏输入和全局变量的问题。 严格和谨慎的编码和命名约定(在这种情况下,您可以按照惯例创建静态类型系统),但这不是一个有趣的练习。
答案 6 :(得分:0)
答案 7 :(得分:0)
Erlang的核心是基于异步通信(共存和分布式交互),这是平台实现可扩展性的关键。您可以在许多平台上使用异步通信进行编程,但Erlang语言和Erlang / OTP框架提供了可管理的结构 - 无论是技术上还是头脑中。例如:如果没有erlang进程提供的隔离,你将自己射击。使用链接/监视器机制,您可以更快地对故障做出反应。