Erlang/OTP架构:面向SOA的服务的RESTful协议

10

让我们想象一下,我们需要设计和构建一个披萨店的订单处理系统。

要求如下:

R1. 系统应该是客户端和用例无关的,这意味着系统可以被未在初始设计中考虑的客户端访问。例如,如果披萨店决定后来很多客户使用三星Bada智能手机,则编写针对Bada OS的客户端不需要重写系统的API和系统本身;或者例如,如果使用iPad而不是Android设备在送货司机方面更好,那么很容易创建一个iPad客户端并且不会以任何方式影响系统的API;

R2. 可重用性,这意味着如果业务流程发生变化,系统可以轻松重新配置而不需要重写太多代码。例如,如果披萨店将开始在线接受付款,同时与送货司机一起接受现金付款(接受订单前付款与到货时付款),那么很容易将系统适应新的业务流程;

R3. 高可用性和容错性,这意味着系统应该在线,并且应该全天候接受订单。

为了满足R3,我们可以使用Erlang/OTP并采用以下架构:Pure Erlang/OTP architecture with one RESTful API entry point 问题在于这种架构中有很多硬编码的功能。例如,如果比萨店从货到付款转向在线支付,那么重写整个系统并修改系统的API需要花费大量时间和精力。
此外,如果比萨店需要对其CRM客户端进行一些增强,则需要重新编写API、客户端和系统本身。
因此,以下架构旨在解决这些问题,并帮助满足R1、R2和R3:Service Oriented Architecture with multiple RESTful API entry points 系统中的每个“服务”都是一个具有RESTful API的Webmachine Web服务器。这种方法具有以下好处:
  • 具备 Erlang/OTP 的所有优点,因为每个 Webmachine 都是一个 Erlang 应用程序,可以被监控并放入 Erlang 发布中;
  • 享有面向服务的架构(SOA)的所有 benefits
  • 易于适应业务流程中的changes
  • 易于向客户端添加新客户和新功能(例如向 CRM 客户端添加新功能),因为客户端可以使用系统中所有服务的 RESTful API 而不是一个“中央”API(在 SOA 方面的服务组合)。

因此,第二张图片中提出的系统架构实质上是一个面向服务的架构,其中每个服务都有一个 RESTful API 而不是 WSDL 合同,并且每个服务都是一个 Erlang/OTP 应用程序。

下面是我的问题:

  1. 图片2:我是在试图重复造轮子吗?还是应该坚持使用纯Erlang/OTP架构?(“纯Erlang”指的是将Erlang应用程序打包到一个发布版本中,通过gen_server:call和gen_server:cast函数调用彼此通信);
  2. 您能否列举出建议方法的任何缺点?(图片2)
  3. 您认为像这样的系统(图片2)比真正的Erlang/OTP系统更容易维护和扩展吗?
  4. 这种系统(图片2)的安全性可能会成为一个问题,因为对于Web开放了许多入口点(所有服务的RESTful API),而不仅仅是一个入口点(图片1),是这样吗?
  5. 在这样的系统中是否可以有几个'编排模块',或者是否存在更好的做法?(图片2上的“接受订单”,“CRM”和“调度订单”服务);
  6. 纯Erlang/OTP(图片1)在消息传递和协议限制方面是否比这种方法(图片2)具有优势?(在我的类似question之前的部分讨论了这一点,gen_server:call VS HTTP RESTful calls)
2个回答

2
关于SOA,需要记住的是,体系结构不仅仅关乎技术(如REST、WS*)。因此,如果需要,可以使用多种类型的端点建立一个良好的SOA(我称之为边缘组件-将业务逻辑与其他问题(如通信和协议)分离)。另外,重要的是要注意服务边界是一个信任边界,因此当您跨越它时,可能需要进行身份验证和授权以及网络穿越等操作。此外,分层(如数据和逻辑)不应该驱动您如何划分服务。
所以从你的问题中所读到的,我可能会将服务划分为更粗粒度的服务(见下文)。服务边界内部的通信可以采用任何形式,而跨服务的通信则使用公共API(REST或Erlang本地由您决定,但重点是管理、版本化、安全等)。一项服务可能在多种技术中拥有端点,以便于不同的用户(有时您会使用ESB来协调服务和协议之间的关系,但这取决于系统的规模和复杂性)。
关于您特定的问题:
  • 1 如上所述,我认为有一个地方可以公开更多的公共API而不仅仅是一个入口点,我不确定将每个能力都作为公共API服务暴露出来是否是正确的做法。
  • 2&3 暴露每一个小细节的缺点是管理开销,性能下降(例如,你必须在这些调用上进行身份验证)。你会得到nano-services服务,它们的开销超过了它们的效用。
  • 关于安全性需要补充的一点是,某个服务具有REST API并不意味着该API必须向普通公众开放。在部署方面,你可以将其保留在防火墙后,并限制已知地址等访问权限。

    • 5 有几个编排模块是可以的,但如果超过几个,你应该考虑使用一些编排模块(和ESB或编排引擎),或者你可以使用基于事件的集成,并获得更灵活的编排集成(但有点难以管理)

    • 6 第一种选择的优点是易于开发,可能性能更好(如果这是一个问题的话)。硬编码的集成层可能随时间推移而变得更难维护。如果你编写的erlang服务保持API集成和消息传递之间的联系(幸运的是,Erlang通过其固有特性(例如不可变性)相对容易正确实现这一点),则它们应该能够独立发展。

Service


1
我将介绍第三种更具成本效益和变化响应性的方式。架构肯定应该是面向服务的,因为你有明确的服务。但没有要求将每个服务公开为Restful或WSDL定义的服务。我不是Erlang开发人员,但我相信有一种通过消息调用本地和远程进程的方法,从而避免内部调用的不必要的序列化/反序列化活动。但总有一天你会面临新的集成问题。例如,你需要集成会计或物流系统。那么,如果你根据SOA原则设计了良好的架构,大部分工作将涉及使用RESTful前端包装器公开现有服务,而无需重构与其他服务的现有连接。但问题在于保持职责领域的清晰。我的意思是,每个服务都应该对其最初设计的活动负责。
你提到的安全问题是众所周知的。你应该在所有公开的服务中使用令牌进行身份验证/授权。

维克托,我认为你描述的方法正是第一种方法。整个系统都有一个明确定义的REST接口,如果我们需要添加更多客户端或进行一些集成,我们只需将相应的资源添加到我们的REST接口并将其连接到与每个服务进行交互的相应Erlang / OTP函数调用。没有要求通过REST公开每个服务,但这是否会增加架构的灵活性呢?然后,如果我们必须集成会计,就不需要向现有的REST接口添加新资源。 - skanatek
1
让我澄清一下。在你的第一种方法中,你通过单个HTTP服务器公开整个系统作为单个超级服务,并提供大量操作列表,对吗?第二种方法建议使用Webmachine或Mochiweb将每个Erlang/OTP应用程序公开为独立服务。我相信第二种方式是进化的最后阶段。我建议避免一开始就暴露所有内容,并根据需求进行操作。在进一步延迟中,您可能会分解某些服务并公开其中的一部分,以允许新客户(例如会计)有效地运行。 - Viktor Stolbin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接