<路径 clip-rule="evenodd" d="M33.377 4.574a3.508 3.508 0 0 0-2.633-1.126c-1 0-1.993.67-2.604 1.334l.002-1.24-1.867-.002-.02 10.17v.133l1.877.002.008-3.18c.567.611 1.464.97 2.462.973 1.099 0 2.022-.377 2.747-1.117.73-.745 1.1-1.796 1.103-3.002.003-1.232-.358-2.222-1.075-2.945Zm-3.082.55c.637 0 1.176.23 1.602.683.438.438.663 1.012.66 1.707-.003.7-.22 1.33-.668 1.787-.428.438-.964.661-1.601.661-.627 0-1.15-.22-1.6-.666-.445-.46-.662-1.086-.662-1.789.003-.695.227-1.27.668-1.708a2.13 2.13 0 0 1 1.596-.675h.005Zm5.109-.067-.008 4.291c-.002.926.263 1.587.784 1.963.325.235.738.354 1.228.354.376 0 .967-.146.967-.146l-.168-1.564s-.43.133-.64-.01c-.198-.136-.296-.428-.296-.866l.008-4.022 1.738.002.002-1.492-1.738-.002.005-2.144-1.874-.002-.005 2.143-1.573-.002 1.57 1.497ZM20.016 1.305h-9.245l-.002 1.777h3.695l-.016 8.295v.164l1.955.002-.008-8.459 3.621-.002V1.305Z" fill="#262D3D" fill-rule="evenodd"><路径 clip-rule="evenodd" d="M10.06 5.844 7.277 3.166 4.015.03 2.609 1.374l2.056 1.978-4.51 4.313 6.065 5.831 1.387-1.327-2.073-1.994 4.526-4.331ZM4.274 8.7a.211.211 0 0 1-.124 0c-.04-.013-.074-.03-.15-.102l-.817-.787c-.072-.069-.092-.104-.105-.143a.187.187 0 0 1 0-.12c.013-.039.03-.07.105-.143L5.76 4.938c.072-.07.108-.09.15-.099a.21.21 0 0 1 .123 0c.041.012.075.03.15.101L7 5.727c.072.07.093.104.103.144.013.04.013.08 0 .119-.013.04-.03.072-.106.143L4.422 8.601a.325.325 0 0 1-.147.099Z" fill="#204ECF" fill-rule="evenodd"><路径 clip-rule="evenodd" d="M24.354 4.622a3.94 3.94 0 0 0-2.876-1.149 4.1 4.1 0 0 0-2.829 1.084c-.804.725-1.214 1.733-1.217 2.992-.002 1.26.405 2.267 1.207 2.995a4.114 4.114 0 0 0 2.832 1.094c.04.002.082.002.123.002a3.967 3.967 0 0 0 2.75-1.138c.538-.532 1.183-1.473 1.186-2.938.002-1.465-.637-2.408-1.176-2.942Zm-.59 2.94c-.003.73-.228 1.334-.671 1.794-.441.458-.99.69-1.633.69a2.166 2.166 0 0 1-1.614-.697c-.43-.45-.65-1.057-.65-1.797s.222-1.344.655-1.795a2.17 2.17 0 0 1 1.617-.69c.64 0 1.189.235 1.63.698.443.46.668 1.064.665 1.797ZM41.15 6.324c0-.458.25-1.465 1.632-1.465.49 0 .768.159 1.003.347.227.18.34.626.34.994v.174l-2.282.341C40.035 6.98 39 7.913 38.993 9.28c-.002.708.266 1.314.777 1.76.503.438 1.191.67 2.004.673 1.023 0 1.792-.354 2.341-1.084.003.31.003.621.003.91h1.903l.013-5.246c.002-.856-.289-1.685-.864-2.14-.567-.449-1.31-.679-2.386-.681h-.015c-.82 0-1.69.208-2.274.695-.689.572-1.027 1.478-1.027 2.178l1.682-.02Zm.864 3.814c-.676-.002-1.115-.371-1.112-.938.003-.589.43-.933 1.346-1.081l1.875-.305v.017c-.005 1.36-.87 2.307-2.102 2.307h-.008Zm4.917-8.712-.018 10.058v.044l1.684.005.018-10.06v-.045l-1.684-.002Zm2.654 9.491c0-.173.062-.322.19-.445a.645.645 0 0 1 .462-.186c.18 0 .338.062.465.186a.596.596 0 0 1 .193.445.583.583 0 0 1-.193.443.644.644 0 0 1-.465.183.634.634 0 0 1-.461-.183.59.59 0 0 1-.191-.443Zm.108 0c0 .146.052.273.158.376a.54.54 0 0 0 .389.154.539.539 0 0 0 .547-.53.498.498 0 0 0-.16-.373.531.531 0 0 0-.387-.156.531.531 0 0 0-.387.155.497.497 0 0 0-.16.374Zm.702.344-.176-.3h-.118v.3h-.109v-.688h.292c.144 0 .23.082.23.196 0 .096-.076.168-.176.188l.178.304h-.121Zm-.294-.596v.21h.167c.093 0 .14-.034.14-.104 0-.072-.047-.106-.14-.106h-.167Z" fill="#262D3D" fill-rule="evenodd">作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Truog迈克尔

Michael是分布式系统和容错专家,曾在AT工作过&T、E*Trade、诺基亚等.

专业知识

以前在

AT&T

云必须高效地提供有用的容错和可伸缩性, 但它们也必须易于使用.

CloudI (发音为“cloud-e”/kla / di/)是一个用Erlang构建的开源云计算平台 密切相关的平台即服务 (PaaS)云. CloudI在几个关键方面有所不同, 最重要的是:软件开发人员不会被迫使用特定的框架, 慢 硬件虚拟化,或特定的操作系统. 通过允许在没有虚拟化的情况下进行云部署, CloudI使开发过程和运行时性能不受阻碍, 虽然服务质量可以通过明确的问责制来控制.

是什么使云成为云?

“云”这个词已经变成了 无处不在的 在过去的几年里. 而它的真正含义在某种程度上已经失去了. 在最基本的技术意义上, 这些是云计算平台必须具备的属性:

这些是我们要 就像 有一朵云:

  • 轻松集成
  • 简单的部署

我构建CloudI的目标 是把这四种特质结合在一起.

重要的是要了解很少有编程语言能够提供真正的可伸缩性容错. 事实上,我认为Erlang在这方面是独一无二的.

我开始看 Erlang编程 语言(在此基础上构建CloudI). Erlang虚拟机提供 容错功能 和一个 高度可扩展的架构 而Erlang编程语言使所需的源代码保持小而易于遵循.

重要的是要了解很少有编程语言能够提供真正的可伸缩性容错. 事实上,我认为Erlang在这方面是独一无二的. 让我绕个弯路来解释为什么和如何.

容错是云计算中的一个重要考虑因素.

云计算中的容错是什么?

容错是对错误的鲁棒性. 这是, 容错系统能够在发生(但愿是孤立的)错误时继续相对正常地运行.

这里,我们看到服务C向服务A和服务B发送请求. 虽然服务B暂时崩溃,但系统的其余部分仍在继续,相对畅通无阻.

Erlang初学者教程

Erlang以实现而闻名 9x9s的可靠性 (99.9999999%的正常运行时间,所以小于31.(每年536毫秒的停机时间)与实际生产系统(在电信行业内). 正常的web开发技术只能实现 5 x9可靠性 (99.999%的正常运行时间,所以大约是5.每年256分钟的停机时间), 如果他们幸运的话, 由于缓慢的更新程序和完整的系统故障. Erlang是如何提供这种优势的?

Erlang虚拟机 实现所谓的“角色模型,一个并行计算的数学模型. 在Actor模型中, Erlang的轻量级进程是该语言本身的并发原语. 也就是说,在Erlang中,我们假设 一切都是演员. 通过定义, actors perform their actions concurrently; so if 一切都是演员, 我们得到了内在的并发性. (关于Erlang的Actor模型的更多信息,有更长的讨论 在这里.)

因此,Erlang软件是由许多 轻量级的流程 这使进程状态保持隔离,同时提供极大的可伸缩性. 当Erlang进程需要外部状态时, 消息通常被发送到另一个进程, 以便消息队列可以为Erlang进程提供有效的调度. 保持Erlang进程状态隔离, Erlang虚拟机单独对每个进程进行垃圾收集,以便其他Erlang进程可以继续并发运行而不被中断.

Erlang虚拟机垃圾回收 与Java虚拟机垃圾回收相比,有一个重要的区别,因为 Java依赖于单个堆,它缺乏Erlang提供的隔离状态. Erlang垃圾收集和Java垃圾收集之间的区别意味着,由于虚拟机垃圾收集,Java无法提供基本的容错保证, 即使库或语言支持是在Java虚拟机上开发的. 已经有了 试图在Java中开发容错特性 和其他基于Java虚拟机的语言, 但是由于Java虚拟机垃圾收集,它们仍然是失败的.

通过比较Erlang和JVM中的垃圾收集方法,可以看出它们对容错的影响.

基本上, 根据定义,在JVM之上构建实时容错支持是不可能的, 因为JVM本身不是容错的.

Erlang进程

在较低的层次上,当我们在Erlang进程中得到错误时会发生什么? 语言本身使用 消息传递 在进程之间,以确保任何错误都具有受并发进程限制的范围. This works by storing data types as immutable objects; these objects are copied to limit the scope of the process state (large binaries are a special exception because they are reference counted to conserve memory).

基本而言, 这意味着如果我们想把变量X传递给另一个进程P, 我们必须复制X作为它自己的不可变变量X '. 我们目前的流程无法修改X ', 所以即使我们触发了一些错误, 我们的第二个过程P将与它的效应分离. 最终结果是对Erlang进程中由于状态隔离而导致的任何错误的范围进行低级控制. 如果我们想了解更多的技术,我们会提到Erlang缺乏可变性 引用透明性 不像Java.

这种类型的容错比仅仅添加try-catch语句和异常要深入. 在这里,容错是关于处理意外错误和预期的异常. 在这里,即使其中一个变量意外爆炸,您也要尝试保持代码运行.

Erlang的进程调度为最少的源代码提供了极大的可伸缩性, 使系统更简单,更容易维护. 虽然其他编程语言确实能够模仿 可伸缩性 通过提供具有用户级线程(可能与内核级线程结合)和数据交换(类似于消息传递)的库来实现自己的Actor模型,从而在Erlang中本地找到, 这些努力无法复制Erlang虚拟机中提供的容错功能.

这使得Erlang在编程语言中独树一帜 可伸缩的容错,使其成为云计算的理想开发平台.

利用Erlang

So, 话虽如此, 我可以断言,CloudI将Erlang的容错性和可伸缩性带给了其他各种编程语言(目前是c++ /C), Erlang(当然), Java, Python, 和Ruby), 中实现服务 面向服务的体系结构 (SOA).

这种简单性使CloudI成为多语言软件开发的灵活框架, 提供Erlang的优势,而不需要程序员编写甚至理解一行Erlang代码.

在CloudI中执行的每个服务都与 CloudI API. 所有非Erlang编程语言服务都使用相同的内部CloudI Erlang源代码进行处理. 因为相同的最小Erlang源代码用于所有非Erlang编程语言, 其他编程语言支持可以通过CloudI API的外部编程语言实现轻松添加. 在内部,CloudI API只对请求和响应进行基本的序列化. 这种简单性使CloudI成为多语言软件开发的灵活框架, 提供Erlang的优势,而不需要程序员编写甚至理解一行Erlang代码.

服务配置指定启动参数和容错约束,以便服务故障可以以受控和隔离的方式发生. 启动参数清楚地定义了可执行文件及其所需的任何参数, 以及用于服务请求的默认超时, 查找服务的方法(称为“目的地刷新方法”), 允许和拒绝都很简单 访问控制列表 (ACL)用于阻止传出的服务请求和可选参数,以影响如何处理服务请求. 容错约束仅仅是两个整数(MaxR:最大重启次数), 和MaxT:以秒为单位的最大时间周期),它们以与Erlang管理器行为(Erlang设计模式)控制Erlang进程相同的方式控制服务. 服务配置为服务的生命周期提供了显式约束,这有助于使服务的执行易于理解, 即使出现错误.

在运行时期间保持服务内存隔离, 每个非Erlang服务(称为“外部”服务)使用单独的操作系统进程,并由Erlang VM调度一个相关的Erlang进程(用于每个非Erlang执行线程). Erlang CloudI API创建“内部”服务, 它们也与Erlang进程相关, 因此,“外部”服务和“内部”服务在Erlang VM中以相同的方式处理.

描述clouddi API与云计算实例和Erlang VM交互的图像.

在云计算中, 同样重要的是,您的容错扩展到单个计算机之外.e.、分布式系统容错). CloudI使用分布式Erlang通信来交换服务注册信息, 这样,通过为使用CloudI API发出的请求指定单个服务名称,就可以在CloudI的任何实例上透明地使用服务. 所有服务请求都由发送服务进行负载平衡,每个服务请求都是一个分布式事务, 因此,在不同的计算机上具有不同实例的相同服务能够在CloudI中提供系统容错. 如果有必要的话, CloudI可以部署在虚拟化的操作系统中,以提供相同的系统容错性,同时促进稳定的开发框架.

例如, 如果HTTP请求需要在数据库中存储一些帐户数据,则可以向配置的HTTP服务(由CloudI提供)发出请求,该服务将请求发送到帐户数据服务进行处理(基于用作服务名称的HTTP URL),然后将帐户数据存储在数据库中. 每个服务请求接收一个 通用唯一标识符 (UUID)创建时, 哪些可用于跟踪服务请求的完成情况, 使CloudI中的每个服务请求成为分布式事务. So, 以帐户数据服务为例, 可以同步或异步地发出其他服务请求,并在利用数据库之前使用服务请求uuid来处理响应数据. 对每个单独的服务请求进行显式跟踪有助于确保在请求的超时期间内交付服务请求,并且还提供了一种唯一标识响应数据的方法(服务请求uuid在所有连接的CloudI节点中是唯一的)。.

使用典型的部署, 每个CloudI节点可以包含一个配置好的帐户数据服务实例(它可以利用多个操作系统进程,其中每个线程都有一个CloudI API对象)和一个HTTP服务实例. 外部负载平衡器可以很容易地在CloudI节点之间分割HTTP请求,而HTTP服务可以将每个请求作为CloudI内的服务请求路由, 这样帐户数据服务就可以在CloudI中轻松扩展.

CloudI在行动

CloudI允许您使用不可伸缩的遗留源代码, 用一个瘦的CloudI服务包装它, 然后执行带有显式容错约束的遗留源代码. 这种特殊的开发工作流程对于充分利用多核机器,同时在处理实时请求期间提供容错的分布式系统非常重要. 在CloudI中创建一个“外部”服务只是在服务配置中配置的所有线程中实例化CloudI API对象, 以便每个线程能够并发地处理CloudI请求. 一个简单的服务示例可以利用单个主线程来创建单个CloudI API对象, 像下面的Python源代码一样:

导入系统
sys.路径.追加(“/ usr /地方/ lib / cloudi-1.2.3 / api / python / ')
从cloud_c导入API

类任务(对象):
    def __init__(自我):
        自我.__api = API(0) #第一个/唯一线程== 0

    def运行(自我):
        自我.__api.订阅(“hello_world_python /涨”,自我.__hello_world)
        自我.__api.poll ()

    Def __hello_world(自我, comm和, name, pattern, request_info, request,
                      超时,优先级,trans_id, pid):
        返回“Hello World”!'

如果__name__ == '__main__':
    断言API.Thread_count() == 1 #简单的例子,没有线程
    任务 = 任务 ()
    任务.run ()

示例服务只是返回一个“Hello World”!,通过首先订阅服务名称和回调函数来发送HTTP GET请求. 当服务开始在CloudI API轮询函数中处理传入的CloudI服务总线请求时, 来自提供HTTP服务器的“内部”服务的传入请求将根据服务名称路由到示例服务, 因为订阅. 服务也可能没有返回任何数据作为响应, 如果请求需要类似于提供发布/订阅功能的典型分布式消息传递API中的发布消息. 示例服务希望提供响应,以便HTTP服务器可以向HTTP客户端提供响应, 因此请求是一个典型的请求/应答事务. 具有来自服务的两种可能的响应, 要么有数据,要么没有数据, 服务回调函数控制所使用的消息传递范型, 而不是呼叫服务, 因此,请求能够通过尽可能多的服务进行路由,以便在必要时提供响应, 在为请求指定的超时内发生. 超时对于实时事件处理非常重要, 因此,每个请求都指定一个整数超时,当它通过任意数量的服务路由时,该超时会跟随请求. 最终的结果是实时约束与容错约束一起被强制执行, 在出现任何数量的软件错误时提供可靠的服务.

任何软件中存在的源代码错误都应该被理解为一个明确的事实,只有通过容错约束才能减轻. 软件开发可以在维护软件时减少bug的出现, 但随着软件功能的增加,它也会增加bug. CloudI提供的云计算能够在实时分布式系统软件开发中解决这些重要的容错问题. 正如我在本CloudI和Erlang教程中所演示的那样, CloudI提供的云计算是最小的,因此不会为了云计算的好处而牺牲效率.

就这一主题咨询作者或专家.
预约电话
Truog迈克尔

位于 西雅图,华盛顿州,美国

成员自 2016年4月4日

作者简介

Michael是分布式系统和容错专家,曾在AT工作过&T、E*Trade、诺基亚等.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

以前在

AT&T

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.