小工具知识网

当前位置: 首页 > 行业知识 > Tomcat

行业知识

Tomcat

2026-11-05 10:20:26 来源:互联网转载

��       自 2017 年 11 月编程语言排行榜 Java 占比 13%,高居榜首,Tomcat 也一度成为 Java开发人员的首选。其开源、占用系统资源少、跨平台等特性被深受喜爱。本章主要学习如何部署 Tomcat 服务,根据生产环境实现多个虚拟主机的配置,最后的重点是进行压测,根据压测结果如何优化 Tomcat 服务及常见的内存溢出如何处理。

1 简介

        Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。

        实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。

        另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。

        官网:Apache Tomcat® - Welcome!

1.1 web技术

1.1.1 http协议和     B/S (Browser/Server)结构

        操作系统有进程子系统,使用多进程就可以充分利用硬件资源。进程中可以多个线程,每一个线程可以被CPU调度执行,这样就可以让程序并行的执行。这样一台主机就可以作为—个服务器为多个客户端提供计算服务。

        客户端和服务端往往处在不同的物理主机上,它们分属不同的进程,这些进程间需要通信。跨主机的进程间通信需要使用网络编程。最常见的网络编程接口是socket。

        Socket称为套接字,本意是插座。也就是说网络通讯需要两端,如果一端被动的接收另一端请求并提供计算和数据的称为服务器端,另一端往往只是发起计算或数据请求,称为客户端。

        这种编程模式称为Client/Server编程模式,简称C/S编程,开发的程序也称为C.S程序。CIS编程往往使用传输层协议(TCPIUDP),较为底层,比如:QQ,迅雷,云音乐,云盘, foxmail, xshell等。

        Client/Server  客户端/服务端

        1990年HTTP协议和浏览器诞生。在应用层使用文本跨网络在不同进程间传输数据,最后在浏览器中将服务器惴返回的HTML渲染出来。由此,诞生了网页开发。

        网页是存储在WEB服务器端的文本文件,浏览器发起HTTP请求后,到达WNEB服务程序后,服务程序根据URL读取对应的HTML文件,并封装成HTP响应报文返回给浏览器端。

        起初网页开发主要指的是HTML、CSS等文件制作,目的就是显示文字或图片,通过超级链接跳转到另一个HTML并显示其内容。

        后来,网景公司意识到让网页动起来很重要,傍着SUN的ava的名气发布了JavaScript语言,可以在浏览器中使用5引攀执行的脚本语言,可以让网页元素动态变化。网页动起来了。

        为了让网页动起来,微软使用ActiveX技术、SUN的Applet都可以在浏览器中执行代码,但都有安全性问题。能不能直接把内容直接在WEB服务器端组织成HTML,然后把HTML返回给浏览器渲染呢?

        最早出现了CGl (Common Gateway Interface)通用网关接口,通过浏览器中输入URL直接映射到一个服务器端的脚本程序执行,这个脚本可以查询数据库并返回结果给浏览器端。这种将用户请求使用程序动态生成的技术,称为动态网页技术。先后出现了ASP、PHP、JSP等技术,这些技术的使用不同语言编写的程序都运行在服务器端,所以称为WEB后端编程。有一部分程序员还是要编写HTML、CSS、JavaScript,这些代码运行在浏览器端,称为WEB前端编程。合起来称为Browser/Server编程,即B/S编程。

        Browser/Server   浏览器/服务器

1.1.2 前端三大核心技术

        HTML  CSS  javascript

1.1.2.1 HTML

        HTML的全称为超文本标记语言,是一种标记语言。它包括一系列标签,通过这些标签可以将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接等。 

        超文本是一种组织信息的方式,它通过超级链接方法将文本中的文字、图表与其他信息媒体相关联。这些相互关联的信息媒体可能在同一文本中,也可能是其他文件,或是地理位置相距遥远的某台计算机上的文件。这种组织信息方式将分布在不同位置的信息资源用随机方式进行连接,为人们查找,检索信息提供方便。

1.1.2.2 CSS

        层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。

        CSS 可以用于给文档添加样式——比如改变标题和链接的颜色及大小。它也可用于创建布局——比如将一个单列文本变成包含主要内容区域和存放相关信息的侧边栏区域的布局。它甚至还可以用来做一些特效,比如动画。查看本段内容中所给出的特定案例。

1.1.2.3 javascript

        Javascript简称S,是一种动态的弱类型脚本解释性语言,和HTML、CSS并称三大WEB核心技术,得到了几乎主流浏览器支持。

        1994年,网景Netscape公司成立并发布了Netscape Navigator刘览器,占据了很大的市场份额,网景意识到WEB需要动态,需要一种技术来实现。

        1995年9月网景浏览器2发布测试版本发布了LiveScript,随即在12月的测试版就更名为JavaScript。同时期,微软推出IE并支持Sscript、VBScript,与之抗衡。

        1997年,网景、微软、SUN、Borland公司和其他组织在ECMA(European Ccomputer Manufacturers Association欧洲计算机制造商协会)确定了EGMAScript的本程序设计语言的标准。JavaScript和JScript都成为ECMAScript标准的实现。

        2008年后随着chrome浏览器的V8引|擎发布。

        V8JS引|擎不是解释执行,而是本地编译,在V8B引擎做了很多优化,JS程序在其上运行堪比本地二进制程序。V8引擎使用C++开发,可以嵌入到任何C++程序中。基于V8引擎,2009年基于服务器javascript的运行环境Node.js诞生,创建了第一版npm (Node js包管理嚣和开源库生态系统)提供了大显的库供程序员使用。从此,便可以在服务器端真正大规模使用jJvaScript编程了。也就是说JavaScript 也可以真正称为服务器端编程语言了,成为目前唯一的前,后端通用的语言。

        同步:

        交互式网页,用户提交了请求,就是想看到查询的结果。服务器响应到来后是一个全新的页面内容,哪怕URL不变,整个网页都需要重新渲染。例如,用户填写注册信息,只是2次密码不一致,提交后,整个注册页面重新刷新,所有填写项目重新填写(当然有办法让用户减少重填)。这种交互非常不友好。从代价的角度看,就是为了注册的一点点信息,结果返回了整个网页内容,不但浪费了网络带宽,还需要浏览器重新渲染网页,太浪费资源了,影响了用户体验和感受。上面这些请求的过程,就是同步过程,用户发起请求,页面整个刷新,直到服务器端响应的数据到来并重新渲染。

        异步:

        1996年微软实现了iframe标签,可以在一个网页使用iframe标签局部异步加载内容。

        1999年微软推出异步数据传输的ActiveX插件技术,太笨重了,但是也火了很多年。有一个组件XMLHttpRequest被大多数浏览器支持。

        传统的网页如果需要更新内容,必需重数整个网页面。Ajax的出现,改变这一切,同时极大的促进了Javascript的发展。Ajax即"Asynchronous Javascript AndXML”(异步JavaScript和XML),是指一种创建交互式、快速动态网页应用的网页开发技术,最早起源于1998年微软的Outook Web Access开发团队。Ajax通过在后台与服务器进行少量数据交换,可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。Javascript通过调用浏览器内置的WEB API中的XMLHttpRequest对象实现Ajax技术。早期Aijax结合数据格式XML,目前更多的使用)SON。利用AAX可实现前后端开发的彻底分离,改变了传统的开发模式。

2 java基础

2.1 web架构

2.1.1 web资源和访问

PC端或移动端浏览器访问

从静态服务器请求HTML、CSS、JS等文件发送到浏览器端,浏览器端接收后渲染在浏览器上从图片服务器请求图片资源显示 从业务服务器访问动态内容,动态内容是请求后有后台服务访问数据库后得到的,最终返回到浏览器端

手机 App访问

内置了HTML和]S文件,不需要从静态WEB服务器下载JS或HTML。为的就是减少文件的发送,现代前端开发使用的S文件太多或太大了有必要就从图片服务器请求图片,从业务服务器请求动态数据 客户需求多样,更多的内容还是需要由业务服务器提供,业务服务器往往都是由一组服务器组成。

2.1.2 后台应用架构

单体应用架构

        传统架构(单机系统)。一个项目一个工程:比如商品、订单、支付、库存、登录、注册等等,统一部署,一个进程

  • all in one的架构方式,把所有的功能单元放在一 个应用里。然后把整个应用部署到一台服务器上。如果负载能力不行,将整个应用进行水平复制,进行扩展,然后通过负载均衡实现访问。
  • Java实现: JSP、 Servlet, 打包成一个jar. war部署
  • 易于开发和测试:也十分方便部署:当需要扩展时,只需要将war复制多份,然后放到多个服务器上,再做个负载均衡就可以了。
  • 如果某个功能模块出问题,有可能全站不可访问,修改Bug后、某模块功能修改或升级后,需要停掉整个服务,重新整体重新打包、部署这个应用war包,功
  • 能模块相互之间耦合度高,相互影响,不适合当今互联网业务功能的快速迭代。
  • 特别是对于一个大型应用,我们不可能吧所有内容都放在一 个应用里面,我们如何维护、如何分工合作都是问题。如果项目庞大,管理难度大
  • web应用服务器:开源的tomcat. jetty. glassfish。 商用的有weblogic、websphere. Jboss

    特点 :

    1、所有的功能集成在一个项目工程中。

    2、所有的功能打在一个war包部署到服务器。

    3、通过部署应用集群和数据库集群来提高系统的性能。

    优点 :

    1、项目架构简单 ,前期开发成本低 ,周期短 ,小型项目的首选。

    2、 开发效率高 ,模块之间交互采用本地方法调用。

    3、容易部署 ,运维成本小 ,直接打包为一个完整的包 ,拷贝到web容器的某个目录下即可运行。

    4、容易测试 :IDE都是为开发单个应用设计的、 容易测试——在本地就可以启动完整的系统。

    缺点 :

    1、全部功能集成在一个工程中 ,对于大型项目不易开发、 扩展及维护。

    2、版本迭代速度逐渐变慢 ,修改一个地方就要将整个应用全部编译、 部署、 启动 ,开发及测试周期过长。

    3、 无法按需伸缩 ,通过集群的方式来实现水平扩展 ,无法针对某业务按需伸缩。

    分布式架构

            针对单体架构的不足 ,为了适应大型项目的开发需求 ,许多公司将一个单体系统按业务垂直拆分为若干系统 ,系统 之间通过网络交互来完成用户的业务处理 ,每个系统可分布式部署 ,这种架构称为分布式架构。

    特点 :

    1、按业务垂直拆分成一个一个的单体系统 ,此架构也称为垂直架构。

    2、系统与系统之间的存在数据冗余 ,耦合性较大。

    3、系统之间的接口多为实现数据同步。

    优点 :

    1、通过垂直拆分 ,每个子系统变成小型系统 ,功能简单 ,前期开发成本低 ,周期短。

    2、每个子系统可按需伸缩。

    3、每个子系统可采用不同的技术。

    缺点 :

    1、子系统之间存在数据冗余、 功能冗余 ,耦合性高。

    2、按需伸缩粒度不够,对同一个子系统中的不同的业务无法实现 ,比如订单管理和用户管理。

    SOA架构

            SOA是一种面向服务的架构 ,基于分布式架构 ,它将不同业务功能按服务进行拆分 ,并通过这些服务之间定义良好 的接口和协议联系起来。

            总的来说,SOA不是具体的什么技术,而是一种开发项目的思想,一种架构。

            微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底去掉耦合,每一个微服务提供单个业务功能,一个服务只做一件事。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等

            从技术角度讲就是一种小而独立的处理过程,类似与进程的概念,能够自行单独启动或销毁

    微服务架构(分布式系统),各个模块/服务,各自独立出来,"让专业的人干专业的事”,独立部署。分布式系统中,不同的服务可以使用各自独立的数据库。·服务之间采用轻量级的通信机制(通常是基于HTTP的RESTful API)。

            微服务设计的思想改变了原有的企业研发团队组织架构。传统的研发组织架构是水平架构,前端、后端、DBA、测试分别有自己对应的团队,属于水平团队组织架构。而微服务的设计思想对团队的划分有着一定的影响,使得团队组织架构的划分更倾向于垂直架构,比如用户业务是一个团队来负责,支付业务是一个团队来负责。但实际上在企业中并不会把团队组织架构拆分得这么绝对,垂直架构只是一种理想的架构微服务的实现框架有多种,不同的应用架构,部署方式也有不同

    特点 :

    1、基于SOA的架构思想 ,将重复公用的功能抽取为组件 ,以服务的方式向各各系统提供服务。

    2、各各系 统与服务之间采用webservice、 rpc等方式进行通信。

    3、 ESB企业服务总线作为系统与服务之间通信的桥梁。

    优点 :

    1、将重复的功能抽取为服务 ,提高开发效率 ,提高系统的可重用性、 可维护性。

    2、 可以针对不同服务的特 点按需伸缩。

    3、采用ESB减少系统中的接口耦合。

    缺点 :

    1、系统与服务的界限模糊,会导致抽取的服务的粒度过大,系统与服务之间耦合性高。

    2、 虽然使用了ESB,但是服务的接口协议不固定,种类繁多,不利于系统维护。

    微服务架构

            https://www.martinfowler.com/microservices/

            基于SOA架构的思想 ,为了满足移动互联网对大型项目及多客户端的需求 ,对服务层进行细粒度的拆分 ,所拆分的 每个服务只完成某个特定的业务功能 ,比如订单服务只实现订单相关的业务 ,用户服务实现用户管理相关的业务等 等 ,服务的粒度很小 ,所以称为微服务架构。

    特点 :

    1、 服务层按业务拆分为一个一个的微服务。

    2、微服务的职责单一。

    3、微服务之间采用RESTful、 RPC等轻量级协议传输。

    4、有利于采用前后端分离架构。

    优点 :

    1、 服务拆分粒度更细 ,有利于资源重复利用 ,开发简单、提高开发效率。

    2、 可以更加精准的制定每个服务的优化方案 ,按需伸缩。

    3、适用于互联网时代 ,产品迭代周期更短。

    4、易于和第三方集成,微服务运行容易且灵活的方式集成自动部署,通过持续集成工具,如: Jenkins、Hudson、Bamboo·微服务易于被一个开发人员理解、修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值。

    5、微服务只是业务逻辑的代码,不会和HTML/CSS或其他界面组件混合,即前后端分离·每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一数据库

    缺点 :

    1、开发的复杂性增加 ,因为一个业务流程需要多个微服务通过网络交互来完成。

    2、微服务过多 ,服务治理成本高 ,不利于系统维护。

    2.1.2.1 单体架构和微服务比较

    2.2 java

    2.2.1 java历史

            Java原指的是印度尼西亚的爪哇岛,人口众多,盛产咖啡、橡胶等。

            Java语言最早是在1991年开始设计的,最初叫Oak项目,它初衷是跑在不同机顶盒设备中的。

            1993年网景公司成立。Oak项目组很快他们发现了浏览器和动态网页技术这个巨大的市场,转向WEB方向。并首先发布了可以让网页动起来的Applet技术(浏览器中嵌入运行Java字节码的技术)。

            在1995年,一杯爪哇岛咖啡成就了Java这个名字。

            Sun公司第一个Java公开版本1.0发布于1996年。口号是"一次编写,到处运行"(Write once,Run anywhere),跨平台运行。

            1999年,SUN公司发布了第二代Java平台(Java2)。

            2009年4月20日,Oracle甲骨文公司宣布将以每股9.50美元,总计**74**亿美金收购SUN(计算机系统)公司。2010年1月成功收购

            2010年,Java创始人之一的 **James Gosling** 离开了Oracle,去了Google。

            2010年8月13日,Oracle在加利福尼亚地方法院起诉Google侵犯版权和专利权。Oracle声称Google侵犯了Java 37个API和部分专利。地方法院的陪审团认为未侵犯专利,且API无版权。

            2016年5月26日,地方法院二审陪审团认定未侵犯版权,对37个JAVA API的重新实现受到合理使用的保护。

            2017年Oracle上诉美国联邦巡回上诉法院,2018年3月27日判决Oracle胜诉,Google应赔偿近90亿美金。

            2019年1月Google想让美国最高法院撤销联邦法院裁决。谷歌表示裁决是"对软件业的毁灭性一击"。现任特朗普政府支持Oracle公司,但微软、Mozilla、 红帽支持Google。目前案件已经受理,但由于疫情推迟。有更多的企业和组织加入进来,包括IBM、计算机和通信协会、互联网协会、超过150名学者和教授。此案如果Oracle胜诉,将在美国形成判例,将深远广泛影响软件业。例如: POSIX接口, 是商用系统UNIX的兼容接口规范。

    2.2.2   java 组成

    Java包含下面部分:

    • 语言、语法规范。关键字,如: if、for、class等
    • 源代码source code
    • 依赖库,标准库(基础).I第三方库(针对某些应用)。底层代码太难使用且开发效率低,封装成现成的库
    • JVM虚拟机。将源代码编译为中间码即字节码后,再运行在JVM之上

              由于各种操作系统ABl不一样,采用编译方式,需要为不同操作系统编译成相应格式的二进制程序才能运行。

              1995年,Java发布Applet技术,Java程序在后台编译成字节码,发送到浏览器端,在浏览器中运行一个Applet程序,这段程序是运行在另外一个VM进程中的但是这种在客户端运行ava代码的技术,会有很大的安全问题。1997年CGl技术发展起来,动态网页技术开始向后端开发转移,在后端将动态内容组织好,拼成HTML发回到浏览器端。

              实现java  hello

      yum install epel-release.noarch -yyum install java -yyum install java-1.8.0-openjdk-devel -y[root@localhost data]#vim Hello.javaclass Hello{      public static void main(String[] args)    {          System.out.println("hello, world");      }  }[root@localhost data]#javac  Hello.java#生成 class 文件[root@localhost data]#lsHello.class  Hello.java[root@localhost data]#java  Hellohello, world

      2.2.3 实现动态网页功能

      2.2.3.1 servlet

      本质是一段java程序

      在Servlet中最大的问题是,HTML输出和java代码混在一起,如果网页布局要调整,Java源代码就需要随之进行调整,对于开发人员来说就是噩梦。

       如下所示:

      import java.io.*;import javax.servlet . * ;import javax. servlet . http .*;public class Helloword extends HttpServlet {private string message;public void init( )throws Serv1etException{message = "He1lo wor 1d";}public void doGet(HttpservletRequest request,                  HttpServletResponse response)         throws servletException,IOException{response.setContentType("text/htm1");//响应报文内容类型printwriter out = response.getwriter(; //构建响应报文内容out.print1n("

      " + message + "

      ");out.print1n("

      战斗爽

      ");}public void destroyo{ {}}可以看到java和HTML代码混在一起并且没要加入一段HTML代码都要在前面加上out.print1n 十分麻烦。
      2.2.3.2 jsp

      JSP本质是提供一个HTML模板,也就是在网页中预留以后填充的空,后续将Java程序运行生成的数据对HTML进行填空就可以了。如果网页布局需要调整!JAVA源代码不需要很大的调整

      I        jsp例子本行后面的内容是服务器端动态生成字符串,最后拼接在一起 directory 
      3.3.3.2 核心组件
      • Tomcat启动一个Server进程。可以启动多个Server,即tomcat的多实例, 但一般只启动一个
      • 创建一个Service提供服务。可以创建多个Service,但一般也只创建一个
        •   每个Service中,是Engine和其连接器Connector的关联配置
      • 可以为这个Service提供多个连接器Connector,这些Connector使用了不同的协议,绑定了不同的端口。其作用就是处理来自客户端的不同的连接请求或响应
      • Service 内部还定义了Engine,引擎才是真正的处理请求的入口,其内部定义多个虚拟主机Host
        • Engine对请求头做了分析,将请求发送给相应的虚拟主机
        • 如果没有匹配,数据就发往Engine上的defaultHost缺省虚拟主机
        • Engine上的缺省虚拟主机可以修改
      • Host 定义虚拟主机,虚拟主机有name名称,通过名称匹配
      • Context 定义应用程序单独的路径映射和配置

        引擎:

        一般而言,引擎是一个程序或一套系统的支持部分。常见的程序引擎有游戏引擎、搜索引擎、杀毒引擎等

        范例:多个组件关系 conf/server.xm

                                                                                解释:1.我开启了 tomcat 生成了一个server (主进程)监听8005端口 用来监控安全。2.开启server之后 还会再开启一个 service 服务(子进程) 是用来管理Connector、Engine、Host、Context3.Connector连接器是用来监听8080端口的, redirectPort="8443"的意思是转交到8443(接收请求并转发请求)第二个连接器是监听8009端口的,并把监听到的转交到84434.Engine引擎,用来响应并处理用户请求  defaultHost="localhost" 定义默认host假如请求的host为www.baidu.com, Engine引擎里并没有这个host 那么它就会交给 Host name="localhost"这个主机处理(虚拟主机)如果Engine引擎里有那么直接访问指定的主机5.Host 虚拟主机 名字是localhost ,appBase="webapps" 这个意思是访问webapps目录下的index.htmlunpackWARs="true" autoDeploy="true"表示自动解压并且自动部署。
        3.3.3.3tomcat 处理请求过程
        • 假设来自客户的请求为: http://localhost:8080/test/index.jsp
        • 浏览器端的请求被发送到服务端端口8080,Tomcat进程监听在此端口上。通过侦听的HTTP/1.1Connector获得此请求。
        • Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的响应
        • Engine获得请求192.168.91.100:8080/test/index.jsp,遍历它所有虚拟主机Host
        • Engine匹配到名为localhost的Host。如果匹配不到,就把请求交给该Engine中的defaultHost处理. localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context
        • Host匹配到路径为/test的Context
        • path=/test的Context获得请求index.jsp,在它的mapping table中寻找对应的servlet
        • Context匹配到URLPATTERN为*.jsp的Sservlet,对应于]spServlet类构造HtpServletRequest对象和HttpServletResponse对象,作为参数调用)spSerlet的doGet或doPost方法。
        • Context把执行完了之后的HttpServletResponse对象返回给Host
        • Host把HttpServletResponse对象返回给Engine
        • Engine把HttpServletResponse对象返回给Connector
        • Connector把HttpServletResponse对象返回给浏览器端 

                  通常意义上的 Web 服务器接受请求后,只是单纯地响应静态资源,如 HTML 文件,图片

          文件等,不能在后端进行一定的处理操作。 Tomcat 是 Apache 下的一个子项目,它具备 Web

          服务器的所有功能,不仅可以监听接受请求并响应静态资源,而且可以在后端运行特定规范

          的 Java 代码 Servlet,同时将执行的结果以 HTML 代码的形式反回客户端。

           Tomcat 由一系列的组件构成,其中核心的组件有三个:

          1)Web 容器:完成 Web 服务器的功能。(https请求)

          2)Servlet 容器:名字为 catalina,用于处理 Servlet 代码。(具体的任务)

          3)JSP 容器:用于将 JSP 动态网页翻译成 Servlet 代码。

          ​    ① Web容器

          ​    负责底层的HTTP协议

          ​    ② Servlet容器

          ​    由catalina脚本帮忙处理的servlet代码,主要处理后端逻辑业务

          ​    catalina实际处理的是Servlet代码,而Servlet代码是由Java编写的

              ③ JSP容器(JAVA Scripts page)

          ​    JSP:在正常的html标签中嵌入一些java代码

          ​    这些JSP最终会被翻译成Servlet代码被执行

          ​    主要提供提供前端页面展示

          ​    小结:tomcat就是一个容器,在这个容器中有三大核心组件:

          ​    WEB、Servlet 和JSP,所以Tomcat是极其轻量级别的,核心组件都是支持基本运行的组件

          TIPS:

          多实例:

          多实例就是在一台服务器上同时开启多个不同的服务端口,同时运行多个服务进程,这些服务进程通过不同的socket监听不同的服务端口来提供服务

          磁盘文件 和访问的url对应关系

          apache 网页文件的根目录默认在:/var/www/html/   且默认访问index.html文件

          apache:/var/www/html/index.html  ----->  http://www.pc.com/index.html/var/www/html/test/index.html  ----->  http://www.pc.com/test/index.html

          tomcat 网页文件的根目录在(可自定义):/usr/local/tomcat/webapps

          yum安装根目录位置:/usr/share/tomcat/webapps

          /usr/local/tomcat/webapps/ROOT/index.jsp  ----->  http://www.pc.com:8080/index.jspROOT是默认项目,不指定 默认访问ROOT目录下的index.htmlwebapps 主站点   主站点下的默认目录ROOT/index.html/usr/local/tomcat/webapps/test/index.jsp  ----->  http://www.pc.com:8080/test/index.jsp
          主页文件的优先级
          • index.html
          • index.htm
          • index.jsp
            [root@localhost conf]#vim /usr/local/tomcat/conf/web.xml#此文件末尾定义了优先级,可以在站点的目录下配置,谁在上优先级越高            index.html        index.htm        index.jsp    在tomcat网页主目录下建立test文件夹并优先默认访问index.jsp配置:mkdir /usr/local/tomcat/webapps/testecho test.jsp > /usr/local/tomcat/webapps/test/index.jspecho test.html > /usr/local/tomcat/webapps/test/index.htmlcd /usr/local/tomcat/webappscp -ar ROOT/WEB-INF test/vim test/WEB-INF/web.xml            index.jsp        index.html        index.htm    验证:[root@wg tomcat]#curl 192.168.80.12:8080/test/test.jsp没有保留完整格式复制WEB-INF/及文件夹下的文件  需要修改属主、属组为tomcatchown tomcat:tomcat WEB-INF/ -R

            3.4 打包jar包实际操作

            • .war:WebApp打包,类zip格式文件,通常包括一个应用的所有资源,比如jsp,html,配置文件等
            • .jar:EJB类文件的打包压缩类zip格式文件,,包括很多的class文件, 网景公司发明
            • .rar:资源适配器类打包文件,目前已不常用
            • .ear:企业级WebApp打包,目前已不常用

                      传统应用开发测试后,通常打包为war格式,这种文件部署到Tomcat的webapps目录下,并默认会自动

              #conf/server.xml中文件配置

              自动解压并且自动部署

              手动部署:

              [root@localhost WEB-INF]#cd /opt[root@localhost opt]#vim test.jsp#直接复制jsp例子后面的内容是服务器端动态生成字符串,最后拼接在一起%
              [root@localhost opt]#vim test.htmlhtmllefllaldj[root@localhost opt]#lstest.html test.jsp[root@localhost opt]#jar cvf /opt/app1.war *已添加清单正在添加: test.html(输入 = 15) (输出 = 17)(压缩了 -13%)正在添加: test.jsp(输入 = 346) (输出 = 298)(压缩了 13%)[root@localhost opt]#cp app1.war /usr/local/tomcat/webapps/[root@localhost opt]#cd /usr/local/tomcat/webapps/[root@localhost webapps]#lsapp1 app1.war docs examples host-manager manager ROOT test#可以看到自动生成了一个app1文件夹http://192.168.80.12:8080/app1/test.jsphttp://192.168.80.12:8080/app1/test.html#####下线只要删除war包直接自动删除
              [root@localhost opt]#cd /opt[root@localhost opt]#mv app1.war app1.war.zip[root@localhost opt]#unzip app1.war.zip Archive:  app1.war.zip   creating: META-INF/  inflating: META-INF/MANIFEST.MF      inflating: test.html                 inflating: test.jsp                [root@localhost opt]#lsMETA-INF    test.html   app1.war.zip      test.jsp

              3.4.1 自建博客

              需要 jpress-v3.2.1.war 包[root@localhost ~]#cd /opt[root@localhost opt]#lsjpress-v3.2.1.war[root@localhost opt]#cp jpress-v3.2.1.war /usr/local/tomcat/webapps/#默认自动解包[root@localhost opt]#cd /usr/local/tomcat/webapps/[root@localhost webapps]#lsdocs      host-manager   jpress-v3.2.1.war  ROOTexamples  jpress-v3.2.1  manager            test[root@localhost webapps]#ln -s jpress-v3.2.1 jpress未完成实验,连接数据库失败[root@localhost ~]#vim /etc/yum.repos.d/mysql.repo[mysql57-community]name=MySQL 5.7 Community Serverbaseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/enabled=1gpgcheck=0yum安装mysql数据库[root@localhost ~]#yum -y install mysql-community-serveryum安装的数据库为了安全默认设置了密码,使用下面的方式查看密码:[root@localhost ~]#grep password /var/log/mysqld.log2024-03-01T03:59:19.735718Z 1 [Note] A temporary password is generated for root@localhost: qd/wmraW1EeD[root@localhost ~]#mysql -u root -p'qd/wmraW1EeD'#最好加上引号mysql> statusERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.#翻译:在执行该语句之前,必须使用ALTER USER语句重置密码。set global validate_password_policy=0;set global validate_password_length=1;#修改密码策略alter user root@'localhost' identified by 'abc123';#修改密码为abc123#quit退出 再次尝试进入[root@localhost ~]#mysql -u root -p'abc123'#建立数据库blogCREATE DATABASE blog;GRANT all ON blog.* TO 'bloguser'@'%' IDENTIFIED BY 'admin123';GRANT all ON blog.* TO 'bloguser'@'localhost' IDENTIFIED BY 'admin123';flush privileges;

              在真实浏览器中访问http://192.168.80.12:8080/jpress

              3.5状态页

              默认的管理页面被禁用,启用方法如下

              修改 conf/tomcat-users.xml

              3.5.1 开启状态页   但是 只能本地访问

              • server  status  状态页
              • manger  app  管理项目
              • host   manger  配置虚拟主机的设置
                [root@localhost ~]#cd /usr/local/tomcat/[root@localhost tomcat]#vim conf/tomcat-users.xml#加下面两行,指定用户和密码  [root@localhost tomcat]#systemctl restart tomcat

                 如果是虚拟机在虚拟机本机上使用浏览器访问127.0.0.1:8080

                3.5.2 开启允许远程状态页

                [root@localhost ~]#cd /usr/local/tomcat/webapps/host-manager/META-INF[root@localhost META-INF]#lscontext.xml[root@localhost ~]#vim /usr/local/tomcat/webapps/manager/META-INF/context.xml          allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192\.\d+\.\d+\.\d+" />#允许127开头且192开头的IP访问状态页\d 表示数字  +表示一个及以上字符[root@localhost META-INF]#systemctl restart tomcat

                3.5.3 host manger

                配置虚拟主机的设置

                [root@localhost ~]#vim /usr/local/tomcat/conf/tomcat-users.xml#最后一行加入,可以合并用户和组此时还只是可以本地登录不能远程登录 ,注意 路径与上面的不同[root@localhost ~]#vim  /usr/local/tomcat/webapps/host-manager/META-INF/context.xml

                3.6常见配置详解

                3.6.1端口8005/tcp安全配置管理

                在conf/server.xml 有以下内容

                                                

                8005是Tomcat的管理端口,默认监听在127.0.0.1上。无需验证就可发送SHUTDOWN (大小写敏感)这个字符串,tomcat接收到后就会关闭此Server。

                [root@localhost ~]#yum install -y telnet[root@centos7 ~]#telnet 127.0.0.1 8005Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.SHUTDOWN                         #执行命令关闭tomcat  优雅的关闭Connection closed by foreign host.如果输入SHUTDOWN后无用户访问网页,将关闭服务。

                此管理功能建议禁用,可将SHUTDOWN改为一串猜不出的字符串实现或者port修改成 0,会使用随机端口如:36913

                port设为-1等无效端口,将关闭此功能此行不能被注释,否则无法启动tomcat服务

                范例:

                [root@localhost ~]#vim /usr/local/tomcat/conf/server.xml

                3.7 tomcat  端口号

                8080: 默认接收 http 请求的端口

                8005: 安全端口,可以关闭tomcat

                8009: apache 和 tomcat 联动 AJP 协议

                3.8.虚拟主机配置

                        可能有时候公司会有多个项目需要运行,那么肯定不可能是一台服务器上运行多个

                Tomcat 服务,这样会消耗太多的系统资源。此时,就需要使用到 Tomcat 虚拟主机。例如现

                在新增两个域名 www.pc.com,www.accp.com希望通过这两个域名访问到不同的项目内

                容。

                例子:

                #创建虚拟主机前,必须先创建相关目录,否则创建虚拟机不成功mkdir -p /data/web{1,2,3}/ROOT/echo  web1 > /data/web1/ROOT/index.htmlecho  web2 > /data/web2/ROOT/index.htmlecho  web3 > /data/web3/ROOT/index.htmlchown -R tomcat.tomcat /data/注意: 一定要有  ROOT  这是默认 的主目录修改配置文件vim /usr/local/tomcat/conf/server.xml#找到  host  主机项#注意 默认的   结束      这段要在  默认结束的后面加上                                                    vim /etc/hosts192.168.80.12 www.a.com  www.b.com  www.c.com[root@localhost ~]#curl www.a.com:8080web1[root@localhost ~]#curl www.b.com:8080web2[root@localhost ~]#curl www.c.com:8080web3

                3.9  Context配置

                Context作用:

                • 路径映射:将url映射至指定路径,而非使用appBase下的物理目录,实现虚拟目录功能
                • 应用独立配置,例如单独配置应用日志、单独配置应用访问控制
                  #映射指定路径#映射站点的根目录#还可以添加日志等独立的配置  

                  说明:

                  • path:指的是访问的URL路径,如果path与appBase下面的子目录同名,context的docBase路径优先更高
                  • docBase:可以是磁盘文件的绝对路径,也可以是相对路径(相对于Host的appBase)
                  • reloadable:true表示如果WEB-INF/classes或META-INF/lib目录下.class文件有改动,就会将WEB应用重新加载。生产环境中,建议使用false来禁用。

                    例子:

                    [root@localhost ~]#cd /data[root@localhost data]#mkdir test[root@localhost data]#echo test > test/index.html[root@localhost test]#vim /usr/local/tomcat/conf/server.xml                #如果  访问  www.a.com/test/   那么 就替换成"/data/test      [root@localhost data]#systemctl restart tomcat[root@localhost data]#curl www.a.com:8080/test/test

                    4. tomcat  nginx  动静分离

                    实际操作:反向代理多机

                    1.部署Nginx 负载均衡

                    ---------------------------Nginx+Tomcat负载均衡、动静分离---------------------------Nginx 服务器:192.168.80.7:80Tomcat服务器1:192.168.80.11:8080Tomcat服务器2:192.168.80.12:8080systemctl stop firewalldsetenforce 0yum -y install pcre-devel zlib-devel openssl-devel gcc gcc-c++ make#安装依赖包useradd -M -s /sbin/nologin nginx#新建nginx用户便于管理,不建立nginx程序用户会报错cd /opt/wget http://nginx.org/download/nginx-1.18.0.tar.gz#官网下载安装包 tar xf nginx-1.18.0.tar.gz cd nginx-1.18.0/#解压软件包mkdir /apps/nginx -p./configure --prefix=/apps/nginx \--user=nginx \--group=nginx \--with-http_ssl_module \--with-http_v2_module \--with-http_realip_module \--with-http_stub_status_module \--with-http_gzip_static_module \--with-pcre \--with-stream \--with-stream_ssl_module \--with-stream_realip_module  make -j 2make installln -s /apps/nginx/sbin/nginx /usr/bin#设置软连接#复制同一版本的nginx的yum安装生成的service文件 vim /usr/lib/systemd/system/nginx.service#建立文件[Unit]Description=nginx - high performance web serverDocumentation=http://nginx.org/en/docs/After=network-online.target remote-fs.target nss-lookup.targetWants=network-online.target [Service]Type=forkingPIDFile=/apps/nginx/logs/nginx.pid#注意文件位置,如果不对 启动不了ExecStart=/apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf#注意启动文件位置ExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s TERM $MAINPIDLimitNOFILE=100000 [Install]WantedBy=multi-user.target  [root@localhost nginx]#systemctl daemon-reload#重新加载配置 systemctl enable --now nginx#开机自启并立即启动    如果卡住是因为logs下有 nginx.pid  文件  删除即可  chown -R nginx.nginx /apps/nginx#修改权限

                    2.部署2台Tomcat 应用服务器

                    安装 tomcatsystemctl stop firewalldsetenforce 0Oracle JDK的二进制文件安装要有 jdk-8u291-linux-x64.tar.gz 安装包切换到有 jdk-8u291-linux-x64.tar.gz 安装包的目录[root@localhost data]#tar xf jdk-8u291-linux-x64.tar.gz -C /usr/local/[root@localhost ~]#cd /usr/local/[root@localhost local]#ln -s jdk1.8.0_291/ jdk#初始化环境变量[root@localhost ~]#vim /etc/profile.d/jdk.shexport JAVA_HOME=/usr/local/jdkexport PATH=$JAVA_HOME/bin:$PATH#!!!注意 :$PATH 要放在$JAVA_HOME/bin后面#以下两项非必须项export JRE_HOME=$JAVA_HOME/jreexport CLASSPATH=$JAVA_HOME/lib/:$JRE_HOME/lib/[root@localhost ~]#. /etc/profile.d/jdk.sh#加载profile文件中的配置 ,使用source效果相同。  不要使用bash(不影响当前环境)#验证安装[root@localhost local]#java -versionjava version "1.8.0_291"Java(TM) SE Runtime Environment (build 1.8.0_291-b10)Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)二进制安装tomcat需要有 apache-tomcat-9.0.16.tar.gz 安装包tar xf apache-tomcat-9.0.16.tar.gzcp -r apache-tomcat-9.0.16 /usr/local/tomcatuseradd -s /sbin/nologin tomcat#新建程序用户cd /usr/local/chown tomcat:tomcat tomcat/ -R#修改属主和属组[root@localhost local]#vim /usr/lib/systemd/system/tomcat.service[Unit]Description=TomcatAfter=syslog.target network.target[Service]Type=forkingExecStart=/usr/local/tomcat/bin/startup.shExecStop=/usr/local/tomcat/bin/shutdown.shRestartSec=3PrivateTmp=trueUser=tomcatGroup=tomcat[Install]WantedBy=multi-user.target[root@localhost local]#systemctl daemon-reload[root@localhost local]#systemctl start tomcat[root@localhost local]#ss -ntap |grep 8080LISTEN     0      100         :::8080                    :::*                   users:(("java",pid=16384,fd=56))

                    3.网页配置

                    (1)Tomcat1 server 配置[root@wg local]#hostnamectl set-hostname tomcat1[root@wg local]#su[root@tomcat1 ~]#vim /usr/local/tomcat/webapps/ROOT/test.jspJSP test1 page   #指定为 test1 页面(2)Tomcat2 server 配置[root@localhost ~]#hostnamectl set-hostname tomcat2[root@localhost ~]#su[root@tomcat2 ~]#vim /usr/local/tomcat/webapps/ROOT/test.jspJSP test2 page   #指定为 test2 页面

                    4.nginx 配置

                    mkdir /datavim test.htmlnginxtest1vim 1.jpgtupianvim /apps/nginx/conf/nginx.conf#编辑配置文件#gzip  on;    upstream tomcat {                    server 192.168.80.11:8080 weight=1;                    server 192.168.80.12:8080 weight=1;      #配置负载均衡服务器列表,weight参数表示权重,权重越高,被分配到的概率越大                                  }        server {        listen 80;        server_name  www.pc.com;                location ~ .*\.jsp$ {        proxy_pass http://tomcat;proxy_set_header HOST $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        }        location ~ .*\.(gif|jpg|jpeg|png|bmp|html)$ {        #静态图片正则        root /data;        expires 5d;        #指定缓存时间五天。        }                location / {        root html;        index index.html index.htm; }        }             #测试#http://192.168.80.7/1.jpg#http://192.168.80.7/test.html#http://192.168.80.7/test.jsp

                    Nginx 负载均衡模式:

                    ●rr 负载均衡模式:

                    每个请求按时间顺序逐一分配到不同的后端服务器,如果超过了最大失败次数后(max_fails,默认1),在失效时间内(fail_timeout,默认10秒),该节点失效权重变为0,超过失效时间后,则恢复正常,或者全部节点都为down后,那么将所有节点都恢复为有效继续探测,一般来说rr可以根据权重来进行均匀分配。

                    ●least_conn 最少连接:

                    优先将客户端请求调度到当前连接最少的服务器。

                    ●ip_hash 负载均衡模式:

                    每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题,但是ip_hash会造成负载不均,有的服务请求接受多,有的服务请求接受少,所以不建议采用ip_hash模式,session 共享问题可用后端服务的 session 共享代替 nginx 的 ip_hash(使用后端服务器自身通过相关机制保持session同步)。

                    ●fair(第三方)负载均衡模式:

                    按后端服务器的响应时间来分配请求,响应时间短的优先分配。

                    ●url_hash(第三方)负载均衡模式:

                    基于用户请求的uri做hash。和ip_hash算法类似,是对每个请求按url的hash结果分配,使每个URL定向到同一个后端服务器,但是也会造成分配不均的问题,这种模式后端服务器为缓存时比较好。

                    Nginx 四层代理配置:

                    ./configure --with-stream

                    和http同等级:所以一般只在http上面一段设置,stream {

                    5 Tomcat优化

                    在目前流行的互联网架构中,Tomcat在目前的网络编程中是举足轻重的,由于Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优 JVM 和 Tomcat 自身调优两部分

                    5.1 JVM组成

                    [root@localhost local]#java -version

                    java version "1.8.0_201"

                    Java(TM) SE Runtime Environment (build 1.8.0_201-b09)

                    Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

                    javac    java程序      生成   *.class

                    java      *.class

                    JVM组成部分

                    • 类加载子系统: 使用Java语言编写.java Source Code文件,通过javac编译成.class Byte Code文件。class loader类加载器将所需所有类加载到内存,必要时将类实例化成实例

                    • 运行时数据区: 最消耗内存的空间,需要优化

                    • 执行引擎: 包括JIT (JustInTimeCompiler)即时编译器, GC垃圾回收器

                    • 本地方法接口: 将本地方法栈通过JNI(Java Native Interface)调用Native Method Libraries, 比如:C,C++库等,扩展Java功能,融合不同的编程语言为Java所用

                      JVM运行时数据区域由下面部分构成:

                      • Method Area (线程共享):方法区是所有线程共享的内存空间,存放已加载的类信息(构造方法,接口定义),常量(final),静态变量(static), 运行时常量池等。但实例变量存放在堆内存中. 从JDK8开始此空间由永久代改名为元空间

                      • heap (线程共享):堆在虚拟机启动时创建,存放创建的所有对象信息。如果对象无法申请到可用内存将抛出OOM异常.堆是靠GC垃圾回收器管理的,通过-Xmx -Xms 指定最大堆和最小堆空间大小

                      • Java stack (线程私有):Java栈是每个线程会分配一个栈,存放java中8大基本数据类型,对象引用,实例的本地变量,方法参数和返回值等,基于FILO()(First In Last Out),每个方法为一个栈帧 1 50 %

                      • Program Counter Register (线程私有):PC寄存器就是一个指针,指向方法区中的方法字节码,每一个线程用于记录当前线程正在执行的字节码指令地址。由执行引擎读取下一条指令.因为线程需要切换,当一个线程被切换回来需要执行的时候,知道执行到哪里了 ,计数器

                      • Native Method stack (线程私有):本地方法栈为本地方法执行构建的内存空间,存放本地方法执行时的局部变量、操作数等。

                        5.1.1 虚拟机

                                目前Oracle官方使用的是HotSpot, 它最早由一家名为"Longview Technologies"公司设计,使用了很多优秀的设计理念和出色的性能,1997年该公司被SUN公司收购。后来随着JDK一起发布了HotSpot VM。目前HotSpot是最主要的 JVM。

                                安卓程序需要运行在JVM上,而安卓平台使用了Google自研的Java虚拟机——Dalvid,适合于内存、处理器能力有限系统。

                                在堆内存中如果创建的对象不再使用,仍占用着内存,此时即为垃圾.需要即时进行垃圾回收,从而释放内存空间给其它对象使用

                                其实不同的开发语言都有垃圾回收问题,C,C++需要程序员人为回收,造成开发难度大,容易出错等问题,但执行效率高,而JAVA和Python中不需要程序员进行人为的回收垃圾,而由JVM或相关程序自动回收垃圾,减轻程序员的开发难度,但可能会造成执行效率低下

                                堆内存里面经常创建、销毁对象,内存也是经常被使用、被释放。如果不妥善处理,一个使用频繁的进程,可能会出现虽然有足够的内存容量,但是无法分配出可用内存空间,因为没有连续成片的内存了,内存全是碎片化的空间。

                                所以需要有合适的垃圾回收机制,确保正常释放不再使用的内存空间,还需要保证内存空间尽可能的保持一定的连续

                                java   什么是垃圾?    没有被使用的进程 线程

                        对于垃圾回收,需要解决三个问题

                        • 哪些是垃圾要回收    A计数法(计数为0 就是垃圾)  B根搜索法(具体是谁在用 这个进程)
                        • 怎么回收垃圾   
                        • 什么时候回收垃圾

                          5.1.2 Garbage 垃圾确定方法

                          • 引用计数: 每一个堆内对象上都与一个私有引用计数器,记录着被引用的次数,引用计数清零,该对象所占用堆内存就可以被回收。循环引用的对象都无法将引用计数归零,就无法清除。Python中即使用此种方式。 简单来说就是有个笔记本,记录有没有人在用,缺陷,AB 资源互相调用

                          • 根搜索(可达)算法 Root Searching

                            5.2 垃圾回收基本算法

                            5.2.1 标记-清除 Mark-Sweep

                                    分垃圾标记阶段和内存释放阶段。标记阶段,找到所有可访问对象打个标记。清理阶段,遍历整个堆,对未标记对象(即不再使用的对象)逐一进行清理。

                                    标记-清除最大的问题会造成内存碎片,但是不浪费空间,效率较高(如果对象较多,逐一删除效率也会影响)

                            5.2.2  标记压缩 (压实)Mark-Compact

                                    分垃圾标记阶段和内存整理阶段。标记阶段,找到所有可访问对象打个标记。内存清理阶段时,整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。

                                    标记-压缩算法好处是整理后内存空间连续分配,有大段的连续内存可分配,没有内存碎片。缺点是内存整理过程有消耗,效率相对低下

                            5.2.3 复制 Copying

                                    先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如A。当A用完后,则将A中存活的对象复制到B。复制到B的时候连续的使用内存,最后将A一次性清除干净。缺点是比较浪费内存,只能使用原来一半内存,因为内存对半划分了,复制过程毕竟也是有代价。好处是没有碎片,复制过程中保证对象使用连续空间,且一次性清除所有垃圾,所以效率很高。

                            5.2.4 多种算法总结

                            没有最好的算法,在不同场景选择最合适的算法

                            • 效率: 复制算法>标记清除算法> 标记压缩算法
                            • 内存整齐度: 复制算法=标记压缩算法> 标记清除算法
                            • 内存利用率: 标记压缩算法=标记清除算法>复制算法

                              5.2.5 STW

                                      对于大多数垃圾回收算法而言,GC线程工作时,停止所有工作的线程,称为Stop The World。GC 完成时,恢复其他工作线程运行。这也是JVM运行中最头疼的问题。

                              5.3 分代堆内存GC策略

                              5.3.1 堆内存分代

                                      上述垃圾回收算法都有优缺点,能不能对不同数据进行区分管理,不同分区对数据实施不同回收策略,分而治之

                                      将heap内存空间分为三个不同类别: 年轻代、老年代、持久代

                              Heap堆内存分为

                              • 年轻代Young:Young Generation

                                伊甸园区eden: 只有一个,刚刚创建的对象

                                幸存(存活)区Servivor Space:有2个幸存区,一个是from区,一个是to区。大小相等、地位相同、可互换。

                                from 指的是本次复制数据的源区

                                to 指的是本次复制数据的目标区

                                • 老年代Tenured:Old Generation, 长时间存活的对象

                                  默认空间大小比例:

                                  规律: 一般情况*99%的对象都是临时对象

                                  范例: 在tomcat 状态页可以看到以下的内存分代   持久代是 元空间  metaspace

                                  如何进入状态页?

                                  [root@localhost ~]#cd /usr/local/tomcat/

                                  [root@localhost tomcat]#vim conf/tomcat-users.xml

                                  .......

                                  #加下面两行,指定用户和密码

                                   

                                   

                                  [root@localhost tomcat]#systemctl restart tomcat

                                  范例: 查看JVM内存分配情况

                                  [root@localhost ~]#cat Heap.java#注意名字要一致public class Heap {    public static void main(String[] args){        //返回虚拟机试图使用的最大内存,字节单位        long max = Runtime.getRuntime().maxMemory();        //返回JVM初始化总内存        long total = Runtime.getRuntime().totalMemory();        System.out.println("max="+max+"字节\t"+(max/(double)1024/1024)+"MB");        System.out.println("total="+total+"字节\t"+(total/(double)1024/1024)+"MB");    }}[root@tomcat1 ~]#javac Heap.java [root@tomcat1 ~]#java -cp . Heapmax=425197568字节405.5MBtotal=30408704字节29.0MBecho   405.5*4|bcecho   1700/29|bc[root@tomcat1 ~]#java -XX:+PrintGCDetails -cp . Heap#详细情况max=425197568字节405.5MBtotal=30408704字节29.0MBHeap PSYoungGen      total 9216K, used 671K [0x00000000f6800000, 0x00000000f7200000, 0x0000000100000000)  eden space 8192K, 8% used [0x00000000f6800000,0x00000000f68a7f68,0x00000000f7000000)  from space 1024K, 0% used [0x00000000f7100000,0x00000000f7100000,0x00000000f7200000)  to   space 1024K, 0% used [0x00000000f7000000,0x00000000f7000000,0x00000000f7100000) ParOldGen       total 20480K, used 0K [0x00000000e3800000, 0x00000000e4c00000, 0x00000000f6800000)  object space 20480K, 0% used [0x00000000e3800000,0x00000000e3800000,0x00000000e4c00000) Metaspace       used 2527K, capacity 4486K, committed 4864K, reserved 1056768K  class space    used 269K, capacity 386K, committed 512K, reserved 1048576K#说明年轻代+老年代占用了所有heap空间, Metaspace实际不占heap空间,逻辑上存在于Heap#默认JVM试图分配最大内存的总内存的1/4,初始化默认总内存为总内存的1/64

                                  5.3.2 年轻代回收Minor GC

                                  1. 起始时,所有新建对象(特大对象直接进入老年代)都出生在eden,当eden满了,启动GC。这个称为Young GC 或者 Minor GC。

                                  2. 先标记eden存活对象,然后将存活对象复制到s0(假设本次是s0,也可以是s1,它们可以调换),eden剩余所有空间都清空。GC完成。

                                  3. 继续新建对象,当eden再次满了,启动GC。

                                  4. 先同时标记eden和s0中存活对象,然后将存活对象复制到s1。将eden和s0清空,此次GC完成

                                  5. 继续新建对象,当eden满了,启动GC。

                                  6. 先标记eden和s1中存活对象,然后将存活对象复制到s0。将eden和s1清空,此次GC完成以后就重复上面的步骤。

                                  通常场景下,大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但是,如果一个对象一直存活,它最后就在from、to来回复制,如果from区中对象复制次数达到阈值(默认15次,CMS为6次,可通过java的选项  -XX:MaxTenuringThreshold=N 指定),就直接复制到老年代。

                                  5.3.3 老年代回收 Major GC

                                          进入老年代的数据较少,所以老年代区被占满的速度较慢,所以垃圾回收也不频繁。如果老年代也满了,会触发老年代GC,称为**Old GC**或者 Major GC。

                                          由于老年代对象一般来说存活次数较长,所以较常采用 标记 压缩算法。

                                          当老年代满时,会触发 Full GC,即对所有"代"的内存进行垃圾回收

                                          Minor GC比较频繁,Major GC较少。但一般Major GC时,由于老年代对象也可以引用新生代对象,所以先进行一次Minor GC,然后在Major GC会提高效率。可以认为回收老年代的时候完成了一次Full GC。所以可以认为 MajorGC = FullGC

                                  5.4 java 内存调整相关参数

                                  5.4.1 JVM 内存常用相关参数

                                  Java 命令行参考文档: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

                                  帮助:man java 

                                  选项分类

                                  • -选项名称         此为标准选项,所有HotSpot都支持
                                  • -X选项名称      为稳定的非标准选项
                                  • -XX:选项名称   非标准的不稳定选项,下一个版本可能会取消

                                    Xms和Xmx建议调整成一样大小

                                    参数说明举例
                                    -Xms设置应用程序初始使用的堆内存大小(年轻代+老年代)-Xms2g
                                    -Xmx设置应用程序能获得的最大堆内存早期JVM不建议超过32G,内存管理效率下降-Xms4g
                                    -XX:NewSize设置初始新生代大小-XX:NewSize=128m
                                    -XX:MaxNewSize设置最大新生代内存空间-XX:MaxNewSize=256m
                                    -Xmnsize同时设置-XX:NewSize 和 -XX:MaxNewSize,代-Xmn1g
                                    -XX:NewRatio以比例方式设置新生代和老年代-XX:NewRatio=2new/old=1/2
                                    -XX:SurvivorRatio以比例方式设置eden和survivor(S0或S1)-XX:SurvivorRatio=6eden/survivor=6/1new/survivor=8/1
                                    -Xss设置每个线程私有的栈空间大小,依据具体线程-Xss256k

                                            标准选项:

                                    [root@localhost ~]#java用法: java [-options] class [args...]           (执行类)   或  java [-options] -jar jarfile [args...]           (执行 jar 文件)其中选项包括:    -d32  使用 32 位数据模型 (如果可用)    -d64  使用 64 位数据模型 (如果可用)    -server  选择 "server" VM                  默认 VM 是 server,                  因为您是在服务器类计算机上运行。    -cp     -classpath                   用 : 分隔的目录, JAR 档案                  和 ZIP 档案列表, 用于搜索类文件。    -D=                  设置系统属性    -verbose:[class|gc|jni]                  启用详细输出    -version      输出产品版本并退出    -version:                  警告: 此功能已过时, 将在                  未来发行版中删除。                  需要指定的版本才能运行    -showversion  输出产品版本并继续    -jre-restrict-search | -no-jre-restrict-search                  警告: 此功能已过时, 将在                  未来发行版中删除。                  在版本搜索中包括/排除用户专用 JRE    -? -help      输出此帮助消息    -X            输出非标准选项的帮助    -ea[:...|:]    -enableassertions[:...|:]                  按指定的粒度启用断言    -da[:...|:]    -disableassertions[:...|:]                  禁用具有指定粒度的断言    -esa | -enablesystemassertions                  启用系统断言    -dsa | -disablesystemassertions                  禁用系统断言    -agentlib:[=]                  加载本机代理库 , 例如 -agentlib:hprof                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help    -agentpath:[=]                  按完整路径名加载本机代理库    -javaagent:[=]                  加载 Java 编程语言代理, 请参阅 java.lang.instrument    -splash:                  使用指定的图像显示启动屏幕

                                    有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation/index.html

                                            非标准的稳定选项

                                    [root@localhost ~]#java -X    -Xmixed           混合模式执行 (默认)    -Xint             仅解释模式执行    -Xbootclasspath:                      设置搜索路径以引导类和资源    -Xbootclasspath/a:                      附加在引导类路径末尾    -Xbootclasspath/p:                      置于引导类路径之前    -Xdiag            显示附加诊断消息    -Xnoclassgc       禁用类垃圾收集    -Xincgc           启用增量垃圾收集    -Xloggc:    将 GC 状态记录在文件中 (带时间戳)    -Xbatch           禁用后台编译    -Xms        设置初始 Java 堆大小    -Xmx        设置最大 Java 堆大小    -Xss        设置 Java 线程堆栈大小    -Xprof            输出 cpu 配置文件数据    -Xfuture          启用最严格的检查, 预期将来的默认值    -Xrs              减少 Java/VM 对操作系统信号的使用 (请参阅文档)    -Xcheck:jni       对 JNI 函数执行其他检查    -Xshare:off       不尝试使用共享类数据    -Xshare:auto      在可能的情况下使用共享类数据 (默认)    -Xshare:on        要求使用共享类数据, 否则将失败。    -XshowSettings    显示所有设置并继续    -XshowSettings:all                      显示所有设置并继续    -XshowSettings:vm 显示所有与 vm 相关的设置并继续    -XshowSettings:properties                      显示所有属性设置并继续    -XshowSettings:locale                      显示所有与区域设置相关的设置并继续-X 选项是非标准选项, 如有更改, 恕不另行通知。

                                    有不稳定选项的当前生效值

                                    [root@centos7 ~]#java -XX:+PrintFlagsFinal

                                    查看所有不稳定选项的默认值

                                    [root@centos7 ~]#java -XX:+PrintFlagsInitial

                                    实例:指定内存空间

                                    [root@localhost ~]#java -Xms1024m -Xmx1024m -XX:+PrintGCDetails -cp  . Heapmax=1029177344字节981.5MBtotal=1029177344字节981.5MBHeap PSYoungGen      total 305664K, used 10486K [0x00000000eab00000, 0x0000000100000000, 0x0000000100000000)  eden space 262144K, 4% used [0x00000000eab00000,0x00000000eb53d888,0x00000000fab00000)  from space 43520K, 0% used [0x00000000fd580000,0x00000000fd580000,0x0000000100000000)  to   space 43520K, 0% used [0x00000000fab00000,0x00000000fab00000,0x00000000fd580000) ParOldGen       total 699392K, used 0K [0x00000000c0000000, 0x00000000eab00000, 0x00000000eab00000)  object space 699392K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000eab00000) Metaspace       used 2527K, capacity 4486K, committed 4864K, reserved 1056768K  class space    used 269K, capacity 386K, committed 512K, reserved 1048576K

                                    范例: 查看OOM

                                    [root@localhost ~]#cat HeapOom2.java import java. util. Random;public class HeapOom2 {public static void main(String[] args) {String str = "I am lao wang";while (true){str += str + new Random().nextInt(88888888);  //生成0到88888888的随机数}}}[root@localhost ~]#javac HeapOom2.java[root@localhost ~]#java -cp . HeapOom2Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3332)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)at java.lang.StringBuilder.append(StringBuilder.java:136)at HeapOom2.main(HeapOom2.java:6)[root@localhost ~]#java -Xms100m -Xmx100m -XX:+PrintGCDetails -cp . HeapOom2

                                    5.4.2 JDK工具监控使用情况

                                    5.4.2.1 jvisualvm
                                    方法一:注意:先在windows上开启Xwindows Server,如Xmanagerexport DISPLAY=192.168.80.1:0.0方法二:使用 MobaXterm 连接yum -y install xorg-x11-xauth xorg-x11-fonts-* xorg-x11-font-utils xorg-x11-fonts-Type1export DISPLAY=192.168.80.1:0.0jvisualvm

                                    安装插件:visual gc

                                    [root@tomcat1 ~]#cat HeapOom.javaimport java.util.ArrayList;import java.util.List;public class HeapOom {    public static void main(String[] args) {        List list =new ArrayList();        int i = 0;        boolean flag = true;        while(flag){            try{                i++;                list.add(new byte[1024* 1024]);//每次增加一个1M大小的数组对象                Thread.sleep(1000);            }catch(Throwable e){                e.printStackTrace();                flag = false;                System.out.println("count="+i);//记录运行的次数            }        }    }}[root@tomcat1 ~]#java -cp . -Xms5m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError HeapOomjava.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid63253.hprof ...Heap dump file created [9691173 bytes in 0.025 secs]java.lang.OutOfMemoryError: Java heap spaceat HeapOom.main(HeapOom.java:12)count=7
                                    5.4.2.2 Jprofiler

                                    Jprofiler定位OOM的问题原因

                                    JProfiler是一款功能强大的Java开发分析工具,它可以快速的帮助用户分析出存在的错误,软件还可对需要的显示类进行标记,包括了内存的分配情况和信息的视图等

                                    JProfiler官网:http://www.ej-technologies.com/products/jprofiler/overview.html

                                    java -cp . -Xms5m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError HeapOom

                                    JProfiler 11 安装与破解 - 哑吧 - 博客园 (cnblogs.com)

                                     启动 license ke y生成器,选择 JProfiler 版本,点击 general。

                                    5.4.3 Tomcat的JVM参数设置

                                    默认不指定,-Xmx大约使用了1/4的内存,当前本机内存指定约为1G。

                                    在bin/catalina.sh中增加一行

                                    vim /usr/local/tomcat/bin/catalina.sh......118行# OS specific support. $var _must_ be set to either true or false.  #添加下面一行    JAVA_OPTS="-server -Xms128m -Xmx512m -XX:NewSize=100m -XX:MaxNewSize=200m"                                                            cygwin=falsedarwin=falseJAVA_OPTS="-server -Xms4g -Xmx4g -XX:NewSize= -XX:MaxNewSize= "-server:服务器模式-Xms:堆内存初始化大小-Xmx:堆内存空间上限-XX:NewSize=:新生代空间初始化大小 -XX:MaxNewSize=:新生代空间最大值[root@localhost opt]#ps aux |grep java#中间段可以看到tomcat    38422 34.8  8.1 4137428 151488 ?      Sl   02:26   0:03 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -server -Xms128m -Xmx512m -XX:NewSize=100m -XX:MaxNewSize=200m .....

                                            Tomcat默认安装下的缺省配置并不适合生产环境,它可能会频繁出现假***现象需要重启,只有通过不断压测优化才能让它最高效率稳定的运行。优化主要包括三方面,分别为操作系统优化(内核参数优化),Tomcat配置文件参数优化,Java虚拟机(JVM)调优。

                                    #Tomcat 配置文件参数优化##常用的优化相关参数如下:【redirectPort】如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS   443 请求时,则转发至此属性定义的 8443 端口。【maxThreads】Tomcat使用线程来处理接收的每个请求,这个值表示Tomcat可创建的最大的线程数,即支持的最大并发连接数,默认值是 200。【minSpareThreads】最小空闲线程数,Tomcat 启动时的初始化的线程数,表示即使没有人使用也开这么多空线程等待,默认值是 10。【maxSpareThreads】最大备用线程数,一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值是-1(无限制)。一般不需要指定。【processorCache】进程缓冲器,可以提升并发请求。默认值是200,如果不做限制的话可以设置为-1,一般采用maxThreads的值或者-1。【URIEncoding】指定 Tomcat 容器的 URL 编码格式,网站一般采用UTF-8作为默认编码。【connnectionTimeout】网络连接超时,单位:毫秒,设置为 0 表示永不超时,这样设置有隐患的。通常默认 20000 毫秒就可以。【enableLookups】是否反查域名,以返回远程主机的主机名,取值为:true 或 false,如果设置为 false,则直接返回 IP 地址,为了提高处理能力,应设置为 false。【disableUploadTimeout】上传时是否使用超时机制。应设置为 true。【connectionUploadTimeout】上传超时时间,毕竟文件上传可能需要消耗更多的时间,这个根据你自己的业务需要自己调,以使Servlet有较长的时间来完成它的执行,需要与上一个参数一起配合使用才会生效。【acceptCount】指定当所有可以使用的处理请求的线程数都被使用时,可传入连接请求的最大队列长度,超过这个数的请求将不予处理,默认为 100 个。【maxKeepAliveRequests】指定一个长连接的最大请求数。默认长连接是打开的,设置为1时,代表关闭长连接;为-1时,代表请求数无限制【compression】是否对响应的数据进行GZIP压缩,off:表示禁止压缩;on:表示允许压缩(文本将被压缩)、force:表示所有情况下都进行压缩,默认值为 off,压缩数据后可以有效的减少页面的大小,一般可以减小 1/3 左右,节省带宽。【compressionMinSize】表示压缩响应的最小值,只有当响应报文大小大于这个值的时候才会对报文进行压缩,如果开启了压缩功能,默认值就是 2048。【compressableMimeType】压缩类型,指定对哪些类型的文件进行数据压缩。【noCompressionUserAgents="gozilla, traviata"】对于以下的浏览器,不启用压缩#如果已经进行了动静分离处理,静态页面和图片等数据就不需做 Tomcat 处理,也就不要在 Tomcat 中配置压缩了。以上是一些常用的配置参数,还有好多其它的参数设置,还可以继续深入的优化,HTTP Connector 与 AJP Connector 的参数属性值,可以参考官方文档的详细说明进行学习。vim /usr/local/tomcat/conf/server.xml......

                                    6 tomcat 多实例

                                    ---------------------Tomcat多实例部署---------------------1.安装好 jdk2.安装 tomcatcd /opttar zxvf apache-tomcat-9.0.16.tar.gzmkdir /usr/local/tomcatmv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1cp -a /usr/local/tomcat/tomcat1 /usr/local/tomcat/tomcat23.配置 tomcat 环境变量vim /etc/profile.d/tomcat.sh#tomcat1export CATALINA_HOME1=/usr/local/tomcat/tomcat1export CATALINA_BASE1=/usr/local/tomcat/tomcat1export TOMCAT_HOME1=/usr/local/tomcat/tomcat1#tomcat2export CATALINA_HOME2=/usr/local/tomcat/tomcat2export CATALINA_BASE2=/usr/local/tomcat/tomcat2export TOMCAT_HOME2=/usr/local/tomcat/tomcat2source /etc/profile.d/tomcat.sh4.修改 tomcat2 中的 server.xml 文件,要求各 tomcat 实例配置不能有重复的端口号vim /usr/local/tomcat/tomcat2/conf/server.xml#22行,修改Server prot,默认为8005 -> 修改为8006 修改为8081#116行,修改Connector port AJP/1.3,默认为8009 -> 修改为8010----------------------------------------------------------------------------------------------------------第一个连接器默认监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。第二个连接器默认监听8009端口,AJP端口,即容器使用,如Apache能通过AJP协议访问Tomcat的8009端口。----------------------------------------------------------------------------------------------------------5.修改各 tomcat 实例中的 startup.sh 和 shutdown.sh 文件,添加 tomcat 环境变量vim /usr/local/tomcat/tomcat1/bin/startup.sh # -----------------------------------------------------------------------------# Start Script for the CATALINA Server# -----------------------------------------------------------------------------##添加以下内容export CATALINA_BASE=$CATALINA_BASE1export CATALINA_HOME=$CATALINA_HOME1export TOMCAT_HOME=$TOMCAT_HOME1vim /usr/local/tomcat/tomcat1/bin/shutdown.sh# -----------------------------------------------------------------------------# Stop script for the CATALINA Server# -----------------------------------------------------------------------------export CATALINA_BASE=$CATALINA_BASE1export CATALINA_HOME=$CATALINA_HOME1export TOMCAT_HOME=$TOMCAT_HOME1vim /usr/local/tomcat/tomcat2/bin/startup.sh # -----------------------------------------------------------------------------# Start Script for the CATALINA Server# -----------------------------------------------------------------------------export CATALINA_BASE=$CATALINA_BASE2export CATALINA_HOME=$CATALINA_HOME2export TOMCAT_HOME=$TOMCAT_HOME2vim /usr/local/tomcat/tomcat2/bin/shutdown.sh# -----------------------------------------------------------------------------# Stop script for the CATALINA Server# -----------------------------------------------------------------------------export CATALINA_BASE=$CATALINA_BASE2export CATALINA_HOME=$CATALINA_HOME2export TOMCAT_HOME=$TOMCAT_HOME26.启动各 tomcat 中的 /bin/startup.sh /usr/local/tomcat/tomcat1/bin/startup.sh /usr/local/tomcat/tomcat2/bin/startup.sh netstat -natp | grep java7.浏览器访问测试http://192.168.80.101:8080http://192.168.80.101:8081

上一篇:茶壶下载秘籍,轻松掌握下载方法与步骤指南

下一篇:怎么测试服务器带宽跑满?