当前位置: 首页 > 科技观察

逐步了解Java企业应用程序的可伸缩性

时间:2023-03-22 12:57:21 科技观察

老实说,“可伸缩性”是一个全面而详尽的主题,经常被人理解。可伸缩性通常等同于高可用性,我见过新手程序员和“资深”架构师都推荐将集群作为同时兼顾可伸缩性和高可用性的解决方案。很好的建议,但问题是人们通常通过搜索Internet来实现集群,而不是真正了解应用程序本身发生了什么。笔者不自称是“专家”,只是想借这篇文章介绍一些通用的Java企业应用伸缩策略。问题可伸缩性不是JavaEnterprisePlatform规范的标准组件。所涉及的技术通常因供应商(应用程序服务器)而异,并且通常需要使用不止一种产品(应用程序服务器本身除外)。正因为如此,设计可扩展的Java企业级应用程序有点棘手。要完成任务,往往不仅没有实例可以参考,还要对应用理解透彻。ExtendedType作者相信你不是第一次看到这样的内容。扩展一般分为两类:纵向扩展和横向扩展。缩放的第一个自然阶段是垂直缩放。Scalingup:涉及向服务器添加更多资源,如内存(RAM)、磁盘空间、处理器等。这在某些场景下具有实用价值,但在某个时间点之后,事实证明这种扩展是昂贵的并且最好使用水平扩展。水平扩展:在这个过程中,添加了更多的机器或额外的服务器实例/节点。这也称为集群(Clustering),因为所有服务器作为一个集体或集群一起运行。高可用性不等于可伸缩性高可用性系统(具有多个服务器节点以便于故障转移)并不意味着系统是可伸缩的。高可用性只是意味着如果当前处理节点崩溃,请求将被传递或转移到集群中的另一个节点以从它开始的地方继续。可扩展性是通过增加可用资源(内存、处理器等)来提高系统特定性能(如用户数、吞吐量、响应时间)的能力,即使失败的请求被传递到另一个节点,也无法保证该应用程序将在这种情况下正常工作(原因我们将在下面看到)。让我们来看看关于可扩展性的一些观点和相关讨论。让scale-out集群实现负载均衡假设你已经scaleup到最大容量,现在使用多个节点组成一个集群来scaleout系统。接下来你要做的事情可能是在集群基础设施前面放置一个负载均衡器,以在集群的各个部分之间分配负载(如果你想了解更多关于负载均衡的知识,可以参考其他资料,这里我们专注于说扩展问题)。应用程序是有状态的还是无状态的?现在你已经横向扩展了,这就够了吗?如果您的应用程序是无状态的,则横向扩展就足够了,即应用程序逻辑在处理请求时不依赖于现有的服务器状态。但是,如果应用程序具有HTTP会话对象、有状态EJB、会话域bean(CDI、JSF)等组件怎么办?由客户端(特别是调用线程)存储特定状态并依赖当前显示的状态来执行请求(例如,HTTP会话对象可能存储用户的身份验证状态、购物车信息等)。在横向扩展或集群应用程序中,任何节点集群都可以为后续请求提供服务。如果没有收到请求的JVM实例的状态数据,其他节点将如何处理请求?会话持久性会话持久性配置可以在负载均衡器级别完成,以确保来自特定客户端/最终用户的请求始终转发到同一实例/应用程序服务器节点,即保持服务器亲和力。通过这种方式,我们可以缓解未显示所需状态的问题。但问题是——如果节点崩溃了怎么办?状态被销毁,用户被重定向到服务器请求处理所依赖的实例,但没有现有状态。集群复制为了解决上述问题,您可以配置应用程序服务器集群机制以支持有状态组件的复制,从而确保HTTP会话数据(和其他有状态对象)存在于所有服务器实例中。这样,最终用户的请求可以到达任何服务器节点,即使服务器实例崩溃或变得不可用,集群中的任何其他节点也可以处理该请求。现在你的集群不是普通集群,而是复制集群。集群复制特定于Java企业容器/应用程序服务器,最好查阅有关如何复制集群的文档。通常,大多数应用程序服务都支持Java企业组件的集群,例如有状态和无状态EJB、HTTP会话、JMS队列等。但是,这又产生了另一个问题——应用服务器中的每个节点都要处理session数据,导致JVM堆内存越来越多,垃圾回收越来越频繁,另外复制时会消耗一定的处理能力簇。有状态组件的外部存储将会话数据和有状态对象存储在另一层,这可以借助RDBMS的帮助来实现,而RDBMS是大多数应用程序服务器原生支持的。您可能已经注意到,我们已将存储从内存层移至持久层-最终,您可能会遇到由数据库引起的扩展问题。并不是说这会发生,但数据库有可能因应用程序而过载,并逐渐延迟(例如在故障转移期间)。想象一下,从数据库中检索整个用户会话状态以用于另一个集群实例,不仅要花费大量时间,而且会影响峰值负载下的最终用户体验。最佳前沿:分布式内存缓存这是最佳前沿,至少在我看来是这样,因为它将我们带回了内存方法。没有比这更好的方法了!OracleCoherence、Hazelcast或任何其他分布式缓存/内存网格产品等产品可用于清理有状态存储和复制/分布——这就是缓存层。好的一面是,这些产品中的大多数默认都支持HTTP会话存储。这种架构设置意味着应用服务器的重启不会影响现有的用户会话——在不停机和最终用户断电的情况下修补系统(并不像听起来那么容易,但它显然是可行的方法!),这总是一件好事。总的来说,这个想法是应用层和网络会话缓存层可以独立运行和扩展而不会相互干扰。distributeddoesnotequalrepeated这两个词之间存在巨大差异,理解这种差异对于缓存层来说至关重要。两者各有利弊:分布式:缓存共享部分数据,即数据集在缓存集群节点之间划分(使用特定于产品的算法)。复制:所有缓存节点拥有所有数据,即每个缓存服务器都包含整个数据集的副本。进一步阅读(主要是关于Weblogic)集群配置RDBMS会话持久性分布式Web会话复制的配置-OracleCoherence,Hazelcast高可扩展性-很棒的资源!结论高可伸缩性可能不是所有Java企业应用程序的要求。但是,如果您要构建面向互联网/面向大众的应用程序,那么将高可扩展性纳入您的设计显然很有用。对于希望充分利用云平台(主要是PaaS)特性(例如自动灵活性(经济上可行!)和高可用性)的应用程序来说,可扩展的设计是必要的。不难看出,有状态应用程序通常更难扩展。完全“无国籍”可能是不可能的,但我们应该朝着这个方向努力。你用什么技巧和方法来扩展Java企业应用,快来和大家分享一下。