TOMCAT02 TOMCAT优化和Java编译工具maven, 私有仓库Nexus

Tomcat 性能优化

test.jsp --------> test_jsp.java --------> test_jsp.class

#tomcat性能优化本质上就是jvm性能优化, 即优化jvm中的GC垃圾回收机制

分代堆内存GC策略

Heap堆内存分为
    年轻代Young:Young Generation
        伊甸园区eden: 只有一个,刚刚创建的对象
        幸存(存活)区Servivor Space:有2个幸存区,一个是from区,一个是to区。大小相    
        等、地位相同、可互换。
            from 指的是本次复制数据的源区
            to 指的是本次复制数据的目标区
    老年代Tenured:Old Generation, 长时间存活的对象

#实际计算中Heap没有永久代(方法区Permanent)

默认空间大小比例:

默认JVM试图分配最大内存的总内存的1/4,初始化默认总内存为总内存的1/64,年青代中heap的1/3,老 年代占2/3

永久代:JDK1.7之前使用, 即Method Area方法区,保存JVM自身的类和方法,存储JAVA运行时的环境信息, 
JDK1.8后 改名为 MetaSpace,此空间不存在垃圾回收,关闭JVM会释放此区域内存,此空间物理上不属于
heap内存,但逻辑上存在于heap内存
  永久代必须指定大小限制,字符串常量JDK1.7存放在永久代,1.8后存放在heap中
  MetaSpace 可以设置,也可不设置,无上限

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

# 用程序查看
[root@ubuntu ~]# 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)+"KB");
       System.out.println("total="+total+"字节\t"+(total/(double)1024)+"KB");
   }
}

[root@ubuntu ~]# javac Heap.java 

[root@ubuntu ~]# java Heap
max=243269632字节 232.0MB
total=16252928字节 15.5MB

 

GC 触发条件

#本质上,垃圾回收,都会暂停程序,等垃圾回收完成,在继续程序执行

 年轻代满了,年轻代做垃圾回收。老年代满了,年轻代和老年代都做一次垃圾回收 full GC

 

Java 内存调整相关参数

#添加启动项,修改内存
[root@ubuntu ~]# cat /usr/local/tomcat/bin/catalina.sh
......
......
#添加此行,使用 JAVA_OPTS 也可以
#堆内存初始值1G,最大值1G,年轻代和老年代内存比例为 1:2,eden区和幸存区的内存比例为6:1:1
CATALINA_OPTS='-Xms1g -Xmx1g -XX:NewRatio=2 -XX:SurvivorRatio=6'
......
......

-Xms和-Xmx: 初始值和最大值生产建议设置一样(因为后续申请资源要等待时间,还能保证内存空间连续)

#重启服务
[root@ubuntu ~]# systemctl restart tomcat.service

#刷新状态页,再次查看内存分配情况
#说明: 年轻代为 (Eden+Survivor)

#也可以直接命令下启动
[root@ubuntu ~]# java -Xms1g -Xmx1g -XX:NewRatio=2 -XX:SurvivorRatio=6 -jar 
abc.jar

使用 jvisualvm 监控内存 (java老版本有,新版本没有了)

[root@ubuntu ~]# apt install libxrender1 libxrender1 libxtst6 libxi6 fontconfig -y
[root@ubuntu ~]# wget https://github.com/oracle/visualvm/releases/download/2.1.8/visualvm_218.zip
[root@ubuntu ~]# apt install unzip

 

垃圾收集方式和调整策略

#jvm8默认为垃圾回收策略关注吞吐率,可以选关注交互(STW间隔短)的
# -XX:+UseConcMarkSweepGC 这个选项关注交互
#jvm8上垃圾回收策略G1属于测试阶段,jvm11开始正式使用(用上面原来的策略更稳妥些)

以后垃圾回收器配置一般不用动,现在都用G1

#jvm11 查看默认垃圾回收器配置(下面为G1)
[root@ubuntu ~]# java -XX:+PrintCommandLineFlags 2>/dev/null
-XX:G1ConcRefinementThreads=2 -XX:GCDrainStackTargetSize=64 -
XX:InitialHeapSize=31592512 -XX:MaxHeapSize=505480192 -XX:+PrintCommandLineFlags 
-XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -
XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC 

范例:定位 JAVA 程序占用CPU率高的问题

#获取16进程线程ID(这里随便输入一个高占用率的线程id)  
[root@ubuntu ~]# printf '0x%x\n' 6869
0x1ad5

#定位代码,显示第15行(输入进程id 6852)  这里定位15行问题
[root@ubuntu ~]# jstack -l 6852 | grep -A10 0x1ad5
"Thread-0" #10 prio=5 os_prio=0 cpu=442964.71ms elapsed=444.97s 
tid=0x00007fc0841a4800 nid=0x1ad5 runnable [0x00007fc05c88f000]
   java.lang.Thread.State: RUNNABLE
 at CPUIntensiveTask$IntensiveTask.run(CPUIntensiveTask.java:15)
 at java.lang.Thread.run(java.base@11.0.22/Thread.java:834)
   Locked ownable synchronizers:
 - None
"Thread-1" #11 prio=5 os_prio=0 cpu=443123.08ms elapsed=444.97s 
tid=0x00007fc0841a6000 nid=0x1ad6 runnable [0x00007fc05c78f000]
   java.lang.Thread.State: RUNNABLE
 at CPUIntensiveTask$IntensiveTask.run(CPUIntensiveTask.java:15)

 

使用图形化工具来查看JAVA进程信息

#windows中装了java环境,里面会有jconsole

jconsole 和 JMX

图形化工具,可以用来查看Java进程信息
JMX(Java Management Extensions,即Java管理扩展)是一个为JAVA应用程序、设备、系统等植入管
理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无
缝集成的系统、网络和服务管理应用。
JMX最常见的场景是监控Java程序的基本信息和运行情况,任何Java程序都可以开启JMX,然后使用
JConsole或Visual VM进行预览。

 

Java 程序编译

Maven 仓库使用流程

Maven 安装和配置

#maven是基于java编写的,如果没有java会顺带先安装java
[root@ubuntu ~]# apt list maven
Listing... Done
maven/jammy 3.6.3-5 all
[root@ubuntu ~]# apt install maven -y

主要配置文件

settings.xml 用来配置 maven 项目中的各种参数文件,包括本地仓库、远程仓库、私服、认证等信息

#settings.xml位置,apt和源码安装不同
/etc/maven/settings.xml #包安装(apt安装)
/usr/local/maven/conf/settings.xml #源码安装

#offline 是否可以在没有网络的情况下进行编译,默认 false
#如果改成true就不管了,download不下来就强制编译

# mirror 配置依赖仓库地址,可以有多个仓库配置
#镜像仓库,官方仓库找不到找镜像仓库

修改maven仓库

#修改默认仓库为国内源,在 mirrors 标签内添加阿里源配置
[root@ubuntu ~]# vim /usr/local/maven/conf/settings.xml
   <mirror>
     <id>aliyunmaven</id>
     <mirrorOf>*</mirrorOf>
     <name>阿里云公共仓库</name>
     <url>https://maven.aliyun.com/repository/public</url>
   </mirror>
</mirrors>

Maven 命令和编译流程

项目编译范例

#clone 代码到本地
[root@ubuntu ~]# git clone https://gitee.com/lbtooth/spring-boot-helloworld.git
[root@ubuntu spring-boot-helloworld]#ls
deploy  Dockerfile  Jenkinsfile  LICENSE  pom.xml  README.md  sonar-project.properties  src
#pom.xml通常是开发写给运维的,运维直接跑就行

#当前还没有 .m2 目录(说明没有编译过)
[root@ubuntu ~]# ls .m2
ls: cannot access '.m2': No such file or directory

#开始编译,清理旧的编译内容,重新构建,并跳过测试(注意目录,要有pom.xml)
[root@ubuntu spring-boot-helloworld]# mvn clean package -Dmaven.test.skip=true
#clean曾经编译过就清理下  -Dmaven.test.skip=true跳过测试(默认会测),java有单元测试的习惯

#编译完出现.m2文件, 依赖包都下载到本地了
[root@ubuntu ~]# ls .m2
repository
[root@ubuntu ~]# du -sh .m2
52M .m2

#编译完原项目目录多target文件夹
[root@ubuntu spring-boot-helloworld]# ls
deploy Dockerfile Jenkinsfile LICENSE pom.xml README.md sonar-project.properties src target

##spring-boot-helloworld-0.9.0-SNAPSHOT.jar 就是构建好的目标(pom文件中定义了是jar包)
[root@ubuntu target]#ls
classes            maven-archiver  spring-boot-helloworld-0.3-SNAPSHOT.jar
generated-sources  maven-status    spring-boot-helloworld-0.3-SNAPSHOT.jar.original

#直接启动java项目即可
[root@ubuntu spring-boot-helloworld]#java -jar target/spring-boot-helloworld-0.3-SNAPSHOT.jar
#运行,如果需要修改端口,可加 --server.port=8888
[root@ubuntu spring-boot-helloworld]#java -jar target/spring-boot-helloworld-0.3-SNAPSHOT.jar --server.port=8888

# 在浏览器中测试
# http://10.0.0.208:8080/
# http://10.0.0.208:8080/version
# http://10.0.0.208:8080/hello

#在有依赖缓存的情况下再次编译
[root@ubuntu ~]# cd spring-boot-helloworld/
#打包成功,耗时 1-2秒
[root@ubuntu spring-boot-helloworld]# mvn clean package -Dmaven.test.skip=true
#如果把 .m2 文件删了,再次编译要重新下载,耗时和第一次一样比较久

项目编译范例

[root@ubuntu ~]# git clone https://gitee.com/JPressProjects/jpress.git
[root@ubuntu ~]# cd jpress/

#当前项目中有大量的 pom.xml,可以分开编译
[root@ubuntu jpress]# find -name "pom.xml"

#整体编译
[root@ubuntu jpress]# mvn clean package -Dmaven.test.skip=true

[root@ubuntu jpress]# find -name "*war"
./starter-tomcat/target/starter-tomcat-5.0.war
[root@ubuntu jpress]# ls starter-tomcat/target/
classes maven-archiver starter-tomcat-5.0 starter-tomcat-5.0-classes.jar 
starter-tomcat-5.0.war

#在tomcat 中部署
[root@ubuntu jpress]# cat /usr/local/tomcat/conf/server.xml
 <Host name="java.m99-magedu.com"  appBase="/data/webapps" unpackWARs="true"
autoDeploy="true">
 <Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
 prefix="java.m99-magedu.com_access_log" suffix=".txt" pattern="%h %l 
%u %t &quot;%r&quot; %s %b %{x-forwarded-for}i" />
 
   </Host> 
   
[root@ubuntu jpress]# cp starter-tomcat/target/starter-tomcat-5.0.war /data/webapps/jpress.war
#己经自动部署
[root@ubuntu jpress]# ls /data/webapps/
jpress jpress.war ROOT

#在浏览器中访问
# http://java.m99-magedu.com:8080/jpress

 

私有仓库 Nexus

Nexus 是一个强大的 Maven 和其它仓库的管理器,它极大地简化了自己内部仓库的维护和外部仓库的 访问。

Nexus 安装

#基于java开发,内存不得小于4g,否则Nexus Server起不来
Nexus Server 既是仓库又是代理,如果没有,会去阿里等仓库拉取

#安装 Nexus,并配置 Maven 仓库
[root@ubuntu ~]#apt install openjdk-11-jdk
#可能需要fanqiang下载
[root@ubuntu ~]# wget https://download.sonatype.com/nexus/3/nexus-3.70.1-02-java11-unix.tar.gz

[root@ubuntu1804 ~]#tar xf nexus-3.29.2-02-unix.tar.gz -C /usr/local/
[root@ubuntu1804 ~]#ln -s /usr/local/nexus-3.29.2-02/ /usr/local/nexus
[root@ubuntu1804 ~]#ln -s /usr/local/nexus/bin/nexus /usr/bin/
[root@ubuntu1804 ~]#file /usr/local/nexus/bin/nexus
bin/nexus: POSIX shell script, ASCII text executable, with very long lines
#指定运行身份
[root@ubuntu1804 ~]#vim /usr/local/nexus/bin/nexus.rc
run_as_user="root"

#查看配置文件,可以在此文件中修改端口等配置
[root@ubuntu1804 ~]#cat /usr/local/nexus/etc/nexus-default.properties
## DO NOT EDIT - CUSTOMIZATIONS BELONG IN $data-dir/etc/nexus.properties
##
# Jetty section
application-port=8081
application-host=0.0.0.0
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jettyhttp.xml,${jetty.etc}/jetty-requestlog.xml
nexus-context-path=/

# Nexus section
nexus-edition=nexus-pro-edition
nexus-features=\
 nexus-pro-feature
nexus.hazelcast.discovery.isEnabled=true

#查看JVM配置文件
[root@ubuntu1804 ~]#cat /usr/local/nexus/bin/nexus.vmoptions
-Xms2703m
-Xmx2703m
......
#前台运行
[root@ubuntu1804 ~]#nexus run
------------------------------------
#注意: 如果内存太小,可能会出现下面提示错误
[root@ubuntu1804 ~]#nexus run 
WARNING: ************************************************************
WARNING: Detected execution as "root" user. This is NOT recommended!
WARNING: ************************************************************
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000717000000, 
1890582528, 0) failed; error='Cannot allocate memory' (errno=12)

#后台运行
[root@ubuntu1804 ~]#nexus start
#查看状态
[root@ubuntu1804 ~]#nexus status
#停止服务
[root@ubuntu1804 ~]#nexus stop
#查看端口
[root@ubuntu1804 ~]#ss -ntlp|grep java
LISTEN   0  50     0.0.0.0:8081    0.0.0.0:*   users:(("java",pid=20564,fd=798)) 
       
LISTEN   0  1    127.0.0.1:38147   0.0.0.0:*   users:(("java",pid=20564,fd=125)) 
#创建service文件
#参考链接https://help.sonatype.com/repomanager3/installation/system-requirements
[root@ubuntu1804 ~]#cat /lib/systemd/system/nexus.service
[Unit]
Description=nexus service
After=network.target
[Service] Type
=forking LimitNOFILE=65536 ExecStart=/usr/local/nexus/bin/nexus start ExecStop=/usr/local/nexus/bin/nexus stop User=root #User=nexus Restart=on-abort
[Install] WantedBy
=multi-user.target [root@ubuntu1804 ~]#systemctl daemon-reload [root@ubuntu1804 ~]#systemctl enable --now nexus.service [root@ubuntu1804 ~]#tail /var/log/syslog

登录 Web 界面初始化

http://nexus主机:8081/

配置 Maven 仓库

#proxy模式  问Nexus要,如Nexus没有,就从其他地方下,自己保存下次就有了(指向设置国内源)
#hosted模式   问Nexus要,如果没有就没有了
#group模式  多个仓库的组合

 

posted @ 2024-09-03 11:20  战斗小人  阅读(7)  评论(0编辑  收藏  举报