• 无服务器架构设计的情景分析
  • Anna 发表于 2017/2/14 10:21:00 | 分类标签: 无服务器架构 架构设计
  •  首先我应该提到,“无服务器”技术肯定有服务器涉及。 我只是使用这个术语来描述这种方法和技术,它将任务处理和调度抽象为与服务器管理无关。 在 2012 年为 ReadWrite 撰写的有关软件和应用程序未来的文章中,我将“无服务器”描述如下。

    短语“无服务器”并不意味着服务器不再涉及。 它只是意味着开发人员不再需要对它们有太多的关注。 计算资源被用作服务,而不必管理物理容量或限制。 服务提供商越来越多地承担管理服务器,数据存储和其他基础设施资源的责任...无服务器架构允许开发人员将重点从服务器级别转移到任务级别。 无服务器解决方案允许开发人员通过消除后端基础架构的复杂性来专注于其应用程序或系统需要做什么。

    在那篇文章的时候,“无服务器”这个术语并没有受到好评,当时在 Hacker News 的评论中也可以看到。但随着一些无服务器平台的诞生和微服务和事件驱动架构发挥越来越重要地位,这些质疑很幸运的逐渐得到了消退。

    无服务器架构使用场景示例

    为了更好理解这个技术,最好基于一个实际使用场景的示例来讨论,因此假设我们要使用无服务器管道来处理电子邮件以及检测垃圾邮件。 它是事件驱动的,因为当电子邮件进来时,它将产生一系列的工作或功能,旨在专门操作该电子邮件。

    在此管道中,您可能具有执行电子邮件中的文本,图像,链接,邮件属性和其他项目或嵌入对象的解析的任务。 每个项目或元素可能具有不同的处理要求,这又要求一个或多个单独的任务以及甚至其自己的处理流水线或序列。 例如,可以跨越几个不同的处理向量来分析图像链接,以确定图像的内容和真实性。 根据消息评分和结果(是否是垃圾邮件),将采取各种行动,这可能反过来涉及其他无服务器功能。

    无服务器架构分析

    无服务器环境中的基本单位是任务或作业,它是围绕特定工作负载处理的实例化和执行。 任务处理自从编程开始就存在,所以它也不是一个全新的事物。 但是考虑到这些工作负载处理的高度分布的性质和抽象的方式,因此跨过具体的实现层次,并有广泛的理解是必要的。

    同步与异步

    虽然处理任务的性质 - 无论是同步还是异步 - 通常是一个平台问题,但它也是在任务级别需要考虑的一个重要因素。 传统的工作和作业处理系统在很大程度上是异步的,这意味着调用进程不保持与执行任务处理组件的持久连接。 作业将排队,因此,它们可能不会立即运行。 调用函数和处理器之间唯一的特定连接将任务排队等待运行。 (注意,某些平台可以允许对任务获得状态,但是通过API调用而不是直接/持久连接)。

    许多新的无服务器平台允许同步处理,从而保持连接并且客户端在功能正在处理时等待。 同步处理的优点是可以直接从处理平台获得结果,而在异步处理中,获得结果必须作为独立的调用来完成。 我将在平台部分讨论更多细节,虽然一般的规则是同步处理适用于轻量级函数(类似于API调用获得天气信息),而异步处理更多的涉及处理作业(音频转录或作为小批量处理作业的一组事件的处理),以及启动处理的应用/组件/功能不是处理结果的应用/组件/功能的地方。

    无状态

    无论处理方法如何,开发微服务和/或无服务器功能的核心原则之一是每个服务或方法应被视为无状态。(小编:无状态也反复在在高可用架构群讨论及分享中提及)。 无状态是指每个任务是一个单独且不同的处理请求,其包含足够的信息来满足该请求。 服务和方法不应存储任何唯一的软件配置或状态。 任何配置数据都应来自方法外部,通常作为任务的一部分或通过平台内的配置服务。 该方法应该仅用于其计算资源,仅用于处理单个工作负载。

    另外,应当有明显的开始状态和结束状态,并且服务或方法应以相同的方式处理每个任务。 借用一个 principles of clean code, bad code — and bad microservices and serverless functions  [1] 一文中的观点,我们应该聚焦并使用单一责任原则(SRP)[2] 。 思考无服务器函数的一个好方法是每个函数应该有一个且只有一个维度或向量的变化。 换句话说,如果有多种方式可以扩展函数(例如,将检查多个特征的图像分析),则对于每个向量应当存在两个或更多个不同的函数。

    在我们使用的用例中,每个电子邮件是一个单独的事件,因此每个电子邮件都有一个单独的任务序列。 每个任务将承载为相应的任务或方法提供处理的数据。

    短生命周期

    无服务器功能也是短暂的 - 意味着它们持续有限的一段时间。 无服务器应用程序的基础主要围绕事件处理和为这些事件服务时发生的任务处理。 强大的容器技术的出现使得任务可以在分布式环境中处理,并且决定在运行时在何处运行。

    换句话说,任务处理基本上变成容器处理,其中容器在任务的基础上建立和移除。作为示例,电子邮件处理示例中的每个任务仅持续对特定电子邮件执行特定动作。 完成后,任务和容器应该终止。

    可能存在需要持久或长时间运行的进程的情况,如实现应用服务器或API服务器,这些场景我们通常放在无服务器范例之外。 在大多数情况下,你觉得可能需要长时间运行的任务,很可能有办法避免这种开销。 例如,无服务器平台,消息队列或其他组件可能能够适应任何路由需求。 同样,计划任务可能能够提供定期状态检查或处理周期。这里的示例是整合和处理来自各种数量的IoT设备的流数据。 如果数据被收集在一个或多个队列或数据库中,则调度作业可以在周期性(和频繁)基础上运行,查看队列中或数据库中的数据,并启动一个或多个子任务以执行每个数据的合并和处理片。

    注意,在实际处理场景中,容器可能不会在每个任务之后终止,主要是出于性能原因。 容器可以从任务持续到下一个任务,但是它们的状态和存储将被擦除和重置,使得每个任务或事件处理循环被隔离并且短周期的。

    幂等

    幂等是构建到微服务和无服务器函数的关键属性(小编:在高可用架构群讨论及分享中,这一术语也被反复提及)。 在基本级别,能够运行重复的任务并获得相同的结果。它也能够使多个重复的请求具有与单个请求相同的效果。 这是第二个定义,对于任务以高度并发和异步方式操作时的设计至关重要。 在任何作业处理环境中,任务可能由于多种原因(服务器崩溃,资源限制,第三方服务超时,任务超时等)而无法完成。

    在其他情况下,任务可以完成,但是可能已经调用了针对相同的重复处理请求。 这样的一个示例是注册消息的超时的队列,因为任务可能仍然在处理请求(并且因此没有及时删除或取消保留消息)。 结果,队列可能触发对该消息的另一处理请求。
    如果只是简单继续处理这些任务 - 将其放在队列上或将其写入数据库,可能会有不良影响,尤其是在事务情况下。 例如,会产生两个重复的订单。 这是最重要的,然后确保只有一个请求处理相同的任务。 正是由于这个原因,在无服务器平台(如大多数其他处理领域)中,开发人员需要在处理之前和/或在写入或输出结果之前,执行重复任务的检查。
    以一个开发者朋友的话来说,另一种思考方式是“想象一下,如果服务器崩溃,而任务正在中间处理并且任务被重试。 或者,如果它只是排队或安排两次。 你需要做什么,以确保你不会覆盖数据,添加重复的事务,因为它可能会多次运行。” 因此在处理周期中,在适当点检查和验证,以确保尚未执行工作。

    多语言编程(Polyglot

    Polyglot是指以多种语言编程。 在无服务器编程的情况下,它指的是以多种语言编写和执行任务的能力。 虽然每个功能可能只是一种语言,正确的无服务器平台应该能够处理多种语言。 这意味着它还应该提供一个重要级别的代码独立性,使开发人员可以透明地工作,而不必关心操作系统和服务器级依赖关系。

    多语言的优点是能够在不同的任务中使用合适的工具。 或者,为对应的团队使用适合他们使用的工具。 在实际情况中经常发生的是,如果你拥有一把锤子,你看到一切都像钉子。使用单一语言,常常会约束解决问题的方法。 开发人员可能艰难的适应那种语言的代码包来完成他们的需要,而事实上,其他语言的其他库也许可以更好地服务于目的。

    为了计算贝叶斯统计或进行机器学习,您可能希望使用用C,C ++,Python或Java编写的包。 同样,与您合作的开发团队可能精通特定的网络爬行包,它是为特定语言编写的(例如以Ruby编写的Nokogiri)。 能够利用这种知识和经验可以消除开发周期,以及降低项目延迟或失败的风险。
    请注意,许多较新的无服务器平台目前仅支持少数几种语言,但我希望在今年内能够快速改变。 (例如,IronWorker可以处理大多数常用语言和可执行代码。)

    兼容性

    无服务器任务需要考虑两个兼容性顺序。 第一个是任务之间,第二个是版本之间。 当你分解任务时候,你需要强大的服务契约和组件之间的规范。 规范的API格式可以通过常用的身份验证和传输协议解决部分问题,但是使用自定义函数和服务,开发人员仍然需要定义有意义且易于理解的输入和输出模式。
    除了干净的接口,开发人员需要解决版本控制需求。 例如,假设函数X在平台内运行,并且它调用函数Y,如果函数Y已经被更新而没有让函数X知道并被正确设计,则它可能在处理时失败或者它可能产生不正确的结果(或者它导致期望原始结果的任务中的下游故障)。

    与代码包一样,无服务器任务中的更改和更新可以通过应用程序发布。 在代码包的情况下,这些冲突可能会通过打包和编译工具早期发现。 然而,使用微服务和无服务器编程,它可能只是通过运行服务(最好在测试或仿真环境),问题才会被发现。

    这意味着,所有这些无状态性和任务和服务独立性,团队需要注意不仅设计良好构建的接口,而且解决向后兼容性的意识。 一个帮助可以是在描述/版本化无服务器任务中使用语义版本[3] 。 它不是万能的,但随着这个版本化约定的传播,它为可能正在使用您创建的任务的其他开发人员提供了一些基础。

  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:Anna
  • 加入时间:2014/6/1 14:44:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮