摘要:本文主要介绍如何理解 Java 应用的扩展方式以及不同类型的扩展技术和具体技巧,介绍一些有关 Java 企业级应用的一般扩展策略。

老实说,“可扩展性”是个全面且详尽的话题,而且往往得不到充分理解。人们通常认为可扩展性等同于高可用性,笔者见过编程新手和架构师“老手”都建议将集群作为可扩展性和高可用性的解决方案。建议确实没错,但问题是,人们通常是通过互联网搜索,而非实际理解应用本身的情况来实现集群。

笔者并未自称“专家”,只想通过这篇文章介绍一些有关 Java 企业级应用的一般扩展策略。

问题

可扩展性并非 Java 企业级平台规范内的标准组件。相关技术通常因供应商(应用服务器)而异,并且往往需要使用不止一款产品(应用服务器本身除外)。正因如此,设计可扩展的 Java 企业级应用才会有些棘手,要完成任务,往往不仅没有可以参照的实例,而且要求我们必须彻彻底底地理解应用。

扩展类型

笔者确信你们不是第一次看到这些内容。扩展一般分为两大类:纵向扩展,和横向扩展。

扩展的第一个自然阶段是纵向扩展。

  • 纵向扩展:包括给服务器增加更多资源,例如内存 (RAM)、磁盘空间、处理器等。这在某些方案中具备实用价值,但经过特定时间点后就会发现,这种扩展费用高昂,不如借助横向扩展。

  • 横向扩展:在这个过程中会增加更多机器或额外的服务器实例/节点,这也叫做集群(Clustering),因为所有服务器是作为一个集体或集群一起运行的。

高可用性不等于可扩展性

系统高度可用(拥有多个服务器节点以方便故障转移),并不表示系统可扩展。高可用性只是意味着,如果当前处理节点崩溃,请求会传递或转移到集群中的另一个节点,以便从开始处继续。可扩展性则是通过增加可用资源(内存、处理器等)而提升系统特定性能(例如用户数量、吞吐量、响应时间)的能力,即使将失败请求传递到另一个节点,也无法保证应用会在这种场景中正确运行(原因我们会在下面揭晓)。

下面我们来了解一些关于可扩展性的观点和相关讨论。

让横向扩展的集群达到负载均衡

假设您已经纵向扩展至最大容量,现在又用多个节点形成集群,将系统进行了横向扩展。接下来您要做的可能是在集群基础架构前放置一台负载均衡器,让负载分散在集群各部分之间(如果要详细了解负载均衡,大家可以参考其他方面的资料,在这里我们重点还是说扩展问题)。

应用有状态还是无状态?

现在你已经横向扩展了,这就够了吗?如果你的应用无状态,即应用逻辑在处理请求时不依靠现有服务器状态,则横向扩展已经足够。

但如果应用具有 HTTP 会话对象、有状态 EJB、会话域 bean (CDI、JSF) 等组件时,又会怎样?这取决于具体客户(具体来说,即调用线程),存储特定状态并依靠当前显示的状态来执行请求(例如,HTTP 会话对象可能会存储用户的身份验证状态、购物车信息等)。

在横向扩展或集群式应用中,节点的任何集群都可能为后续请求提供服务。如果首个请求的 JVM 实例处的状态数据没有被接收,其他节点会如何处理请求?

会话保持

会话保持配置可在负载均衡器层面上完成,确保来自特定客户/终端用户的请求始终被转发到同一个实例/应用服务器节点,即维持服务器亲和力。这样,我们就缓解了所需状态无法显示的问题。但这里有个陷阱 – 如果节点崩溃怎么办?状态会被破坏,用户会被转至服务器请求处理所依赖的、但不具备现有状态的实例。

集群复制

为解决上述问题,您可对应用服务器集群机制进行配置,以支持有状态组件的复制,借此可确保 HTTP 会话数据(和其他有状态对象)显示在所有服务器实例上。如此一来,终端用户请求便可转至任何服务器节点,即使某个服务器实例崩溃或不可用,集群中的其他任何节点都能够处理请求。现在您的集群就不是一般集群了,而是复制集群。

集群复制特定于 Java 企业级容器/应用服务器,最好查阅相关文档,了解如何复制集群。一般而言,大多数应用服务都支持 Java 企业级组件(如有状态和无状态的 EJB、HTTP 会话、JMS 队列等)集群。

然而这造成了另一个问题 – 应用服务器中的每一个节点都处理会话数据,导致 JVM 堆内存越来越多,因此垃圾回收也越来越频繁,另外,复制集群时还会消耗一定的处理能力。

有状态组件的外部存储

在另一层存储会话数据和有状态的对象,这可以借助 RDBMS 实现,大多数应用服务器本身就支持这一功能。

你可能已经注意到了,我们已经将存储从内存层转移到持久层 - 一天工作结束时,你可能会遇到由数据库导致的扩展问题。不是说这一定会发生,但数据库确实可能因为应用而过载,而后逐渐延时(例如在故障转移时)。设想一下,从数据库中再现整个用户会话状态以便用在另一个集群实例中,不仅耗费大量时间,还会影响峰值负载下的终端用户体验。

最后的边界:分布式内存中缓存

这是最后的边界,至少在我看来如此,因为它把我们带回了内存方法。没有比这更好的办法了!Oracle Coherence、Hazelcast 这类产品或其他任何分布式缓存/内存网格产品可用于清理有状态的状态存储和复制/分布 - 这就是缓存层。好的一面是这些产品大多默认支持 HTTP 会话存储。

这种结构设置意味着,应用服务器的重启不会影响现有用户会话 - 给系统打补丁而不造成宕机和终端用户断电(虽然并不像听上去那么容易,但显然是个办法!),这始终是好事。总的来说,其理念是:应用层和 web 会话缓存层可独立运行和扩展,彼此不受干扰。

分布式不等于重复式

这两个词之间存在巨大差异,就缓存层而言,理解其中的差异是极为关键的。两者各有长短:

  • 分布式:缓存共享数据的各个部分,即数据集被分在各缓存集群节点之间(利用与产品特定的算法)。

  • 重复式:所有缓存节点都拥有所有数据,即每个缓存服务器都包含整个数据集的一份复本。

延伸阅读(主要关于 Weblogic)

结束语

  • 高度可扩展性可能不是所有 Java 企业级应用的必要条件。但如果你打算构建互联网/面向大众的应用,将高可扩展性纳入设计因素显然非常实用。

  • 对于希望充分利用自动灵活性(经济可行!)和高可用性等云平台(主要是PaaS)特点的应用而言,可扩展的设计是必要的。

  • 不难发现,有状态的应用通常更难以扩展。完全「无状态」或许无法实现,但我们应当朝这方面努力。

你用哪些技巧和方法来扩展 Java 企业级应用,快来和大家分享吧。

(编译自:https://dzone.com/articles/the-basics-of-scaling-java-ee-applications

OneAPM 为您提供端到端的 Java 应用性能解决方案,我们支持所有常见的 Java 框架及应用服务器,助您快速发现系统瓶颈,定位异常根本原因。分钟级部署,即刻体验,Java 监控从来没有如此简单。想阅读更多技术文章,请访问 OneAPM 官方技术博客

本文转自 OneAPM 官方博客

一步一步理解 Java 企业级应用的可扩展性的更多相关文章

  1. 破解class文件的第一步:深入理解JAVA Class文件

    摘要: java定义了一套与操作系统,硬件无关的字节码格式,这个字节码就是用java class文件来表示的,java class文件内部定义了虚拟机可以识别的字节码格式,这个格式是平台无关性的. j ...

  2. Java 学习第一步-JDK安装和Java环境变量配置

    Java学习第一步——JDK安装及Java环境变量配置 [原文]  2014-05-30 9:09  Java SE  阿超  9046 views Java作为当下很主流的编程语言,学习Java的朋 ...

  3. 一步一步理解GB、GBDT、xgboost

    GBDT和xgboost在竞赛和工业界使用都非常频繁,能有效的应用到分类.回归.排序问题,虽然使用起来不难,但是要能完整的理解还是有一点麻烦的.本文尝试一步一步梳理GB.GBDT.xgboost,它们 ...

  4. 一步一步理解Paxos算法

    一步一步理解Paxos算法 背景 Paxos 算法是Lamport于1990年提出的一种基于消息传递的一致性算法.由于算法难以理解起初并没有引起人们的重视,使Lamport在八年后重新发表到 TOCS ...

  5. 一步一步的理解C++STL迭代器

    一步一步的理解C++STL迭代器 "指针"对全部C/C++的程序猿来说,一点都不陌生. 在接触到C语言中的malloc函数和C++中的new函数后.我们也知道这两个函数返回的都是一 ...

  6. 一步一步理解 python web 框架,才不会从入门到放弃 -- 开始使用 Django

    背景知识 要使用 Django,首先必须先安装 Django. 下图是 Django 官网的版本支持,我们可以看到上面有一个 LTS 存在.什么是 LTS 呢?LTS ,long-term suppo ...

  7. 一步一步理解线段树——转载自JustDoIT

    一步一步理解线段树   目录 一.概述 二.从一个例子理解线段树 创建线段树 线段树区间查询 单节点更新 区间更新 三.线段树实战 -------------------------- 一 概述 线段 ...

  8. NLP(二十九)一步一步,理解Self-Attention

      本文大部分内容翻译自Illustrated Self-Attention, Step-by-step guide to self-attention with illustrations and ...

  9. 一步一步理解word2Vec

    一.概述 关于word2vec,首先需要弄清楚它并不是一个模型或者DL算法,而是描述从自然语言到词向量转换的技术.词向量化的方法有很多种,最简单的是one-hot编码,但是one-hot会有维度灾难的 ...

随机推荐

  1. UDP 校检和和算法

    #include <Winsock2.h> #include <stdio.h> #define IP_HDRINCL 2 // Header is included with ...

  2. Unity Panel open & close

    Making a Popup and Closable Panel in Unity 5 script: public GameObject thePanel; public open() { the ...

  3. GUI编程笔记(java)05:GUI事件监听机制原理和举例说明

    1.事件监听机制:       A:事件源          事件发生的地方       B:事件             就是要发生的事情       C:事件处理       就是针对发生的事情做 ...

  4. Chapter 5. The Gradle Wrapper 关于gradle wrapper

    Most tools require installation on your computer before you can use them. If the installation is eas ...

  5. ubuntu 12.04 编译安装 nginx

    下载源码包 nginx 地址:http://nginx.org/en/download.html 编译前先安装两个包: 直接编译安装会碰到缺少pcre等问题,这时候只要到再安装两个包就ok sudo ...

  6. nodejs 中koa框架下的微信公众号开发初始篇

    最近在搞微信公众号开发,后端采用的是nodejs下的koa框架,初识后端的菜鸟,自己搞难度太大了,网上找了很多文章,采用的中间件大都是express框架下的,不过好在爬了许多坑之后总算看见点曙光了,遂 ...

  7. GitHub详细教程

    GitHub详细教程 Table of Contents 1 Git详细教程 1.1 Git简介 1.1.1 Git是何方神圣? 1.1.2 重要的术语 1.1.3 索引 1.2 Git安装 1.3 ...

  8. ManualResetEvent的使用与介绍

    它可以通知一个或多个正在等待的线程已发生事件,允许线程通过发信号互相通信,来控制线程是否可心访问资源 当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 Manu ...

  9. Asp.Net Mvc4 Ajax提交数据成功弹框后跳转页面

    1.cshtml页面代码 @model Model.UserInfo @{     ViewBag.Title = "Edit"; var options = new AjaxOp ...

  10. the account is currently locked out. The system administrator can unlock it.

    今天遇到的问题比较有意思.首先是很久没有打开测试数据库了,今天打开,使用service程序测试的时候出现下面的错误提示:Message: System.Data.SqlClient.SqlExcept ...