java代码容器 同类产品:jetty (方便,功能少i)、weblogic(商业软件)
jvm:java虚拟机
jre:提供依赖和jvm
jdk:提供命令、开发工具和jre
- open jdk和oracle jkd
- yum 源的是openjdk
yum install -y java
使用流程
- 获取oracle jdk二进制安装包
- 从
/server/tools解压到/app/tools:tar xf jdk-8u60-linux-x64.tar.gz -C /app/toolsln -s /app/tools/jdk1.8.0_60/ /app/tools/jdk
- 配置环境变量 ```bash cat >>/etc/profile<<’EOF’ export JAVA_HOME=/app/tools/jdk export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar export TOMCAT_HOME=/app/tools/tomcat EOF
`source /etc/profile`<br />`java -version`4. 获取tomcat [二进制安装包](https://tomcat.apache.org/download-90.cgi#9.0.62)4. 从`/server/tools`解压到`/app/tools`:- `tar xf apache-tomcat-9.0.52.tar.gz -C /app/tools/`- `ln -s /app/tools/apache-tomcat-9.0.52/ /app/tools/tomcat`- `/app/tools/tomcat/bin/version.sh`6. 配置systemctl [介绍xxx.service](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/chap-managing_services_with_systemd#sect-Managing_Services_with_systemd-Resources)```bashvim /usr/lib/systemd/system/tomcat.service[Unit]Description= 超级无敌汤姆猫After=network.target[Service]Type=forking# yum 安装的jdk不需要这行EnvironmentFile=/etc/sysconfig/tomcatExecStart=/app/tools/tomcat/bin/startup.shExecStop=/app/tools/tomcat/bin/shutdown.shExecReload=/app/tools/tomcat/bin/shutdown.sh && sleep 3 && /app/tools/tomcat/bin/startup.sh[Install]WantedBy=multi-user.targetcat >>/etc/sysconfig/tomcat<<'EOF'JAVA_HOME=/app/tools/jdkPATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:/bin/:/sbin/:/usr/local/bin/:/usr/local/sbin/CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jarEOFsystemctl daemon-reload
- 启动并查看进程 ```bash systemctl start tomcat
ps -ef |grep java ss -lntup |grep java
<a name="PirGc"></a>
# 详细介绍
| 目录结构 | <br /> |
| --- | --- |
| bin <br />- startup.sh<br />- shutdown.sh<br />- catalina.sh<br /> | tomcat管理命令,jvm配置.<br />启动<br />关闭<br />1. startup.sh或shutdown.sh都会调用这个主脚本. <br />1. 修改jvm选项/参数。<br /> |
| conf<br />- server.xml 标记<br />- tomcat-users.xml<br />- logging.properties<br />- web.xml<br /> | tomcat配置文件, server.xml<br />主配置文件<br />管理端配置文件<br />日志功能<br />本身配置,web功能配置 |
| lib | 库文件, 一般以.jar结尾 |
| logs 标记<br />- localhost_access_log.2022- 05-11.txt <br />- catalina.out<br />- catalina.2022-05-11.log <br /> | 日志文件<br />tomcat访问日志<br />⚠应用日志,这个文件内容不会清空.使用log4j2,定任务,logrotate清空.<br />应用日志的切割日志,每天切割. |
| temp | 临时文件 |
| work | 临时文件 |
| webapps 标记<br />- ROOT<br /> | 站点目录<br />根目录 |
部署java代码的两种方式
1. `java -jar xxxx.jar`
1. war包放到webapps,或者在tomcat根目录创建目录
<a name="lQBpD"></a>
## server配置文件详解
```bash
vim /app/tools/tomcat/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN"> # 指定telnet关闭tomcat这种方式的端口号和指令,不常用
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
# golbal这块用来开启管理端认证功能
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina"> # 指定服务名,不用改
<Connector port="8080" protocol="HTTP/1.1" # 指定连接端口,连接协议!!!!!!
connectionTimeout="20000" # 指定超时时间
redirectPort="8443" /> # 指定https端口
<Engine name="Catalina" defaultHost="localhost"> # 用于指定默认虚拟主机!!!!!!
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps" # name指定虚拟主机域名 # appbase指定站点目录!!!!!
unpackWARs="true" autoDeploy="true"> # 自动解压war包 # 自动加载到jvm
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" # 指定属性信息,用于配置日志AccessLog # 指定tomcat访问日志目录/tomcat/logs/
prefix="localhost_access_log" suffix=".txt" # 指定访问日志前缀 # 指定访问日志后缀!!!!!
pattern="%h %l %u %t "%r" %s %b" /> # 指定访问日志格式!!!!!
# %h:客户端ip %t:时间 %r:请求首航 %s:状态码 %b:响应体大小 %{Referer}i:从哪跳转访问 %{User-Agent}i:代理 %{X-Forwarded-For}i:XFF头
</Host>
</Engine>
</Service>
</Server>
vim /app/tools/tomcat/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN"> # 指定telnet关闭tomcat这种方式的端口号和指令
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="zrlog.oldboylinux.cn">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="zrlog.oldboylinux.cn" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="zrlog.oldboylinux.cn_access_log" suffix=".log"
pattern="%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" "%{X-Forwarded-For}i" " />
</Host>
</Engine>
</Service>
</Server>
简单部署
zrlog.war.pdf
修改主配置文件,重启tomcat,然后访问即可
多实例介绍
- 准备多个tomcat目录,并以端口号命名。如tomcat-8081
- 修改server.xml中的访问端口和stop端口
- 创建并修改systemctl文件。例:
vim /usr/lib/systemd/system/tomcat-8081.service三种部署方式
一台机器tomcat同时处理动态和静态资源,nginx相当于一个代理,只用来提供80端口
不太实用, 已收缩
server {
listen 80;
server_name zrlog.oldboylinux.cn;
#默认扔给tomcat
location / {
proxy_pass http:Վˌ10.0.0.9:8080;
proxy_set_header Host $http_host;
}
#静态资源设置缓存
location ~* \.(html|css|js|png|jpg|jpeg)$ {
proxy_pass http:Վˌ10.0.0.9:8080;
proxy_set_header Host $http_host;
expires 30d;
}
}
只有一台机器,nginx用来处理静态资源,tomcat用来处理动态资源
需要做动静分离
mkdir -p /app/code/zrlog/static/
cp -r /app/tools/tomcat/webapps/ROOT/* /app/code/zrlog/static/
vim /etc/nginx/conf.d/zrlog.degnfeng.com.conf
server {
listen 80;
server_name zrlog.dengfeng.cn;
#默认扔给tomcat
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
}
#静态资源 ngx处理 缓存 开始
location ~* \.(html|css|js|png|jpg|jpeg)$ {
root /app/code/zrlog/static/;
expires 30d;
}
#静态资源 ngx处理 缓存 结束
}
# attached需要挂载到存储服务器
多台机器,一些用来处理静态,一些用来处理动态
tomcat和php-fpm不同,它本身就是一个web服务器,可以不经过nginx,在做动静分离的时候不能将思维固定在PHP上
tomcat机器的配置很简单,复制web01整个tomcat目录即可,但复制前记得先关闭java,否则有些复制不了
# 静态机器上只要放nginx,location只需要匹配静态资源地址
# 动态机器上只要有配置好的tomcat和java
# attached需要进行挂载到存储服务器
# 配置lb
vim /etc/nginx/conf.d/zrlog.oldboylinux.cn.conf
upstream default_pools {
server 10.0.0.10:8080;
}
upstream static_pools {
server 10.0.0.9:80;
}
server {
listen 80;
server_name zrlog.oldboylinux.cn;
location / {
proxy_pass http://default_pools;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-Real-Ip $remote_addr;
}
location ~* \.(html|js|css|jpg|png|jpeg|gif)$ {
proxy_pass http://static_pools;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-Real-Ip $remote_addr;
}
}
监控tomcat
- 命令监控
yum 安装的tomcat需要装上对应版本的-devel
jps -lvm等于 ps -ef | grep javajstack pid查看线程状态,进程信息- jmap
jmap -heap pid查看jvm使用情况jmap -dump:/tmp/zrlog.hprof,format=b pid导出jvm内存
- 脚本监控
```bash
!/bin/bash
@Function
Find out the highest cpu consumed threads of java, and print the stack of these threads.
#@Usage
$ ./show-busy-java-threads.sh
#@author Jerry Lee
readonly PROG=basename $0
readonly -a COMMAND_LINE=(“$0” “$@”)
usage() { cat <<EOF Usage: ${PROG} [OPTION]… Find out the highest cpu consumed threads of java, and print the stack of these threads. Example: ${PROG} -c 10
Options: -p, —pid find out the highest cpu consumed threads from the specifed java process, default from all java process. -c, —count set the thread count to show, default is 5 -h, —help display this help and exit EOF exit $1 }
readonly ARGS=getopt -n "$PROG" -a -o c:p:h -l count:,pid:,help -- "$@"
[ $? -ne 0 ] && usage 1
eval set — “${ARGS}”
while true; do case “$1” in -c|—count) count=”$2” shift 2 ;; -p|—pid) pid=”$2” shift 2 ;; -h|—help) usage ;; —) shift break ;; esac done count=${count:-5}
redEcho() { [ -c /dev/stdout ] && {
# if stdout is console, turn on color output.
echo -ne "\033[1;31m"
echo -n "$@"
echo -e "\033[0m"
} || echo "$@"
}
yellowEcho() { [ -c /dev/stdout ] && {
# if stdout is console, turn on color output.
echo -ne "\033[1;33m"
echo -n "$@"
echo -e "\033[0m"
} || echo "$@"
}
blueEcho() { [ -c /dev/stdout ] && {
# if stdout is console, turn on color output.
echo -ne "\033[1;36m"
echo -n "$@"
echo -e "\033[0m"
} || echo "$@"
}
Check the existence of jstack command!
if ! which jstack &> /dev/null; then [ -z “$JAVA_HOME” ] && { redEcho “Error: jstack not found on PATH!” exit 1 } ! [ -f “$JAVA_HOME/bin/jstack” ] && { redEcho “Error: jstack not found on PATH and $JAVA_HOME/bin/jstack file does NOT exists!” exit 1 } ! [ -x “$JAVA_HOME/bin/jstack” ] && { redEcho “Error: jstack not found on PATH and $JAVA_HOME/bin/jstack is NOT executalbe!” exit 1 } export PATH=”$JAVA_HOME/bin:$PATH” fi
readonly uuid=date +%s${RANDOM}$$
cleanupWhenExit() { rm /tmp/${uuid}_* &> /dev/null } trap “cleanupWhenExit” EXIT
printStackOfThread() {
local line
local count=1
while IFS=” “ read -a line ; do
local pid=${line[0]}
local threadId=${line[1]}
local threadId0x=printf %x ${threadId}
local user=${line[2]}
local pcpu=${line[4]}
local jstackFile=/tmp/${uuid}_${pid}
[ ! -f "${jstackFile}" ] && {
{
if [ "${user}" == "${USER}" ]; then
jstack ${pid} > ${jstackFile}
else
if [ $UID == 0 ]; then
sudo -u ${user} jstack ${pid} > ${jstackFile}
else
redEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."
redEcho "User of java process($user) is not current user($USER), need sudo to run again:"
yellowEcho " sudo ${COMMAND_LINE[@]}"
echo
continue
fi
fi
} || {
redEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."
echo
rm ${jstackFile}
continue
}
}
blueEcho "[$((count++))] Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user}):"
sed "/nid=0x${threadId0x} /,/^$/p" -n ${jstackFile}
done
}
ps -Leo pid,lwp,user,comm,pcpu —no-headers | { [ -z “${pid}” ] && awk ‘$4==”java”{print $0}’ || awk -v “pid=${pid}” ‘$1==pid,$4==”java”{print $0}’ } | sort -k5 -r -n | head —lines “${count}” | printStackOfThread
3. 远程监控 for zabbix(开启jmxremote功能
```bash
vim /app/tools/tomcat/bin/catalina.sh
# 在注释之后添加这五行,tomcat8.5之后需要加换行符
#开启监控 指定端口 关闭证书功能 开启关闭ssl证书 指定本机ip
CATALINA_OPTS="$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=10.0.0.9"
# zabbix服务端需要安装zabbix-java-gateway充当zabbix-server和jmxremote之间的中介
# 更建议使用自定义监控
java源码数据库配置文件介绍
# 如果web-inf目录存在就手动创建一下,不用去页面安装了
driverClass=com.mysql.cj.jdbc.Driver
# 数据库用户名
user=zrlog
# 数据库密码
password=lidao996
jdbcUrl=jdbc\:mysql\://数据库ip\:3306/数据库名字?characterEncoding\=UTF-8&allowPublicKeyRetrieval\=true&useSSL\=false&serverTimezone\=GMT
# 光这样还不够,得找到该目录下的install.lock一起传过去,貌似不太行,这一段了解就行
# zrlog的上传目录是attched
会话共享
- tomcat是自带session复制功能的,适用于集群节点<= 4 的情况
- 插件实现:放在redis中,jar包也是插件实现,开发做,运维不用管
- tomcat-session-manager
插件实现
```bash下载
cd /server/tools/ && wget https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/download/4.0/tomcat-cluster-redis-session-manager.zip && unzip tomcat-cluster-redis-session-manager.zip
- tomcat-session-manager
复制文件
cp tomcat-cluster-redis-session-manager/lib/*.jar /app/tools/tomcat/lib/ cp tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties /app/tools/tomcat/conf/
修改配置文件,输入redis地址,注意redis放行什么网卡写哪个网卡
vim /app/tools/tomcat/conf/redis-data-cache.properties redis.hosts=redis01:6379
vim /app/tools/tomcat/conf/context.xml
在最后一行前面粘贴
选做,增加会话保持时间
vim /app/tools/tomcat/conf/web.xml 修改30
<a name="UcmS1"></a>
## 测试
```bash
systemctl reload tomcat
vim /app/tools/tomcat/webapps/ROOT/session.jsp
<body>
<%
//HttpSession session = request.getSession(true);
System.out.println(session.getCreationTime());
out.println("<br> web03.oldboylinux.cn SESSION ID:" + session.getId() + "<br>");
out.println("Session created time is :" + session.getCreationTime()+ "<br>");
%>
</body>
# 访问ip:8080/session.jsp
排错
- redis的
/etc/redis.conf没有放行,或者vim /app/tools/tomcat/conf/redis-data-cache.properties的redis地址写错了https
```bash
优化
内存分析
- 监控/告警/巡检指标 显示负载过高
- top查看cpu用户使用率,wa || 或者vmstate 看r b
- 定位是cpu问题还是io问题
- cpu:ps -ef/aux
- io:iotop -o
- 发现是java问题,使用jstack或者脚本查看哪一个java进程有问题,获取pid
- jmap导出
- 开发使用使用MAT分析
