首页  ·  知识 ·  架构设计
应用程序水平伸缩的最佳实践
openshift  架构头条  综合  编辑:Osborn   图片来源:网络
性能是指系统提供一定程度的响应时间的能力,而可伸缩性是指系统或组件在保持可维护性的同时通过修改自身来解决问题,可以处理更大的流量或数据集。

在介绍这些可伸缩性最佳实践前,我们需要定义一下“可伸缩性”的含义。大多数人将可伸缩性与性能混淆起来了。性能是指系统提供一定程度的响应时间的能力,而可伸缩性是指系统或组件在保持可维护性的同时通过修改自身来解决问题,可以处理更大的流量或数据集。一个系统可能是高性能的,但不一定具备伸缩性。例如,在面对 100 个用户和 1GB 的数据时,Web 应用程序能做出非常快的响应,但如果在处理 100 倍的数据和服务 100 倍的用户时无法保持同样速度,那它就不具备可伸缩性。当你可以通过添加更多相同的东西来处理更多负载时,就实现了一个可伸缩的架构。

什么是最佳实践?最佳实践是一种技术或方法,经过经验的验证和研究,被证明能够为我们带来更好的结果。

伸缩性类型

  • 垂直伸缩:给一台机器增加更多的资源,比如更快的 CPU、更多的内存、SSD,等等。垂直可伸缩性是有限制的,并且成本呈指数级增长。

  • 水平伸缩:通过添加更多的机器来处理更多的请求和负载。

水平伸缩最佳实践

现在,我将列出一些有助于伸缩 Web 应用程序的最佳实践。其中大多数是通用的,能应用于任何编程语言。


1拆分单体

这个实践背后的思想是将单体拆分成功能相关的服务组,同一组内的服务能一起进行维护和伸缩。你可以遵循 SOA(面向服务架构)、ROA(面向资源架构)或者其他设计实践进行服务拆分,目的是根据功能将大型的单体拆分成较小的应用程序。例如,所有与用户相关的服务可以分为一组,所有与搜索相关的服务分为一组,等等。

Web 应用程序的可伸缩性就是指系统的松散耦合,让独立的组件之间彼此通信。如果一个组件坏了,应该不会影响整个系统,这有助于避免“单点故障”。不相关功能的解耦程度越高,就越有必要对它们进行独立的伸缩。服务被拆分后,我们可以执行的操作和执行这些操作所需的代码也需要被拆分。不同的团队可以成为掌握系统局部知识的专家,不需要担心系统的其他部分。这不仅有助于应用程序层的伸缩,也有助于数据库层的伸缩,你可以根据不同的需要选择不同的数据库。


2使用分布式缓存

使用分布式缓存能避免访问速度较慢的数据库或文件系统,直接从高速的本地内存中获取数据,从而有助于 Web 应用程序的水平伸缩。我们只需要向缓存集群添加更多的节点就可以实现应用程序的线性伸缩。使用分布式缓存的 Java Web 应用程序可以将经常访问的数据(例如数据库查询结果或计算密集型计算结果)放在缓存中。应用程序可以使用 Memcached 或 Infinispan 来创建分布式缓存集群。

缓存的作用是减轻系统的负担。

我建议缓存系统要拥有自己独立的层,而不是把它们放在应用服务器的机器上,这样你就可以独立于应用程序层对缓存层进行伸缩。


3使用 CDN

你应该用 CDN 来分担 Web 应用程序的流量。

CDN 是部署在网络上的大型分布式服务器系统,目标是为终端用户提供具备高可用性和高性能的内容。

CDN 主要用于为较近的用户提供静态内容,如 CSS、图像、JavaScript、静态 HTML 页面。它会尝试找到最合适的服务器,在最短的时间内经过更少的网络跳数,并具备最高的可用性,或使用更少的请求。你可以通过 Akamai 或 Amazon CloudFrond 来实现 CDN 功能。


4将共享服务部署到单独的集群中

一些应用程序使用文件系统来保存用户上传的文件或保存配置文件。你需要将这些文件复制到所有节点,让所有节点都可以访问它们。随着节点的增加,在服务器实例之间复制文件将占用更大的网络带宽,并消耗大量的 CPU 资源。

对于集群来说,可以使用数据库代替外部文件、SAN 或 Amazon S3,这将有助于实现更好的可伸缩性。


5异步化

伸缩性的下一个最佳实践是使用异步调用。如果两个组件 X 和 Y 之间进行同步的调用,那么 X 和 Y 就是紧密耦合的。在进行伸缩时,要么它们都伸缩,要么 X 和 Y 都不伸缩。这是紧密耦合系统的一个特点——要伸缩 X,必须同时伸缩 Y,反之亦然。例如,用户注册后系统会向用户发送电子邮件进行验证,如果用户注册服务和电子邮件服务紧密结合,那么用户注册服务的可伸缩性将依赖于电子邮件服务。

但是,如果你通过队列、多播消息传递或其他方式进行异步注册,那么注册服务可以继续往下走,因为你确定验证电子邮件将会被发送给用户。同步调用会导致整个程序挂起,因为需要等待响应,这会将所有服务捆绑在一起,导致级联失败。这不仅影响了可伸缩性,还会影响系统的可用性。换句话说,如果 Y 宕机了,那么 X 也会宕机。通过进行异步化,X 和 Y 现在有了独立的可用性——即使 Y 宕机,X 仍然可以继续提供服务。


6并行处理任务

有时候,你可以将单线程的任务拆分为多个较小的任务,这些小任务不仅可以在单个机器上并行运行,还可以在一组机器上并行运行。单线程任务会成为系统的可伸缩性瓶颈。Java 7 引入了 fork/join 框架,能帮你更好地利用多处理器核心。它是为那些可以递归拆分成小任务的任务而设计的,目标是使用所有可用的处理能力来提高应用程序的性能。


7不要在应用程序层保存状态

实现可伸缩性的一个黄金规则是不将状态保存在应用程序层,而是将它们保存在数据库中,让集群中的每个节点都可以访问它们。然后,你可以使用标准的负载均衡器来路由传入的流量。因为所有的应用服务器都是一样的,并且没有任何事务状态,所以它们中的任何一个都能够处理请求。如果我们需要更多的处理能力,只需要添加更多的应用服务器。


8使用非阻塞 IO

java.nio 包帮助开发人员在数据处理方面获得更好的性能,并提供更好的可伸缩性。NIO 和 NIO 2 提供的非阻塞 IO 操作通过“更接近底层”来提高 Java 应用程序的性能。NIO 和 NIO 2 API 暴露了相对底层的操作系统入口点。

在 Web 应用程序中,传统的阻塞 IO 为每个传入的请求分配一个专用的工作线程。一个线程将负责请求的整个生命周期——从网络中读取请求数据、解码参数、计算或调用其他业务逻辑函数、对结果进行编码并将其发送给请求者,然后这个线程将返回线程池,被其他请求重用。使用 NIO 后,一个线程可以处理多个 HTTP 连接,具体取决于可用的堆内存。要在 Tomcat 中启用 NIO,可以通过修改元素的 protocol 属性,如下所示:


<Connector

    protocol="org.apache.coyote.http11.Http11NioProtocol"

    port="80"

    redirectPort="8443"

    connectionTimeout="20000"



本文作者:openshift 来源:架构头条
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读