java代码容器 同类产品:jetty (方便,功能少i)、weblogic(商业软件)

jvm:java虚拟机
jre:提供依赖和jvm
jdk:提供命令、开发工具和jre

  • open jdk和oracle jkd
  • yum 源的是openjdk
    • yum install -y java

使用流程

  1. 获取oracle jdk二进制安装包
  2. /server/tools解压到/app/tools:
    • tar xf jdk-8u60-linux-x64.tar.gz -C /app/tools
    • ln -s /app/tools/jdk1.8.0_60/ /app/tools/jdk
  3. 配置环境变量 ```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
  1. `source /etc/profile`<br />`java -version`
  2. 4. 获取tomcat [二进制安装包](https://tomcat.apache.org/download-90.cgi#9.0.62)
  3. 4. `/server/tools`解压到`/app/tools`:
  4. - `tar xf apache-tomcat-9.0.52.tar.gz -C /app/tools/`
  5. - `ln -s /app/tools/apache-tomcat-9.0.52/ /app/tools/tomcat`
  6. - `/app/tools/tomcat/bin/version.sh`
  7. 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)
  8. ```bash
  9. vim /usr/lib/systemd/system/tomcat.service
  10. [Unit]
  11. Description= 超级无敌汤姆猫
  12. After=network.target
  13. [Service]
  14. Type=forking
  15. # yum 安装的jdk不需要这行
  16. EnvironmentFile=/etc/sysconfig/tomcat
  17. ExecStart=/app/tools/tomcat/bin/startup.sh
  18. ExecStop=/app/tools/tomcat/bin/shutdown.sh
  19. ExecReload=/app/tools/tomcat/bin/shutdown.sh && sleep 3 && /app/tools/tomcat/bin/startup.sh
  20. [Install]
  21. WantedBy=multi-user.target
  22. cat >>/etc/sysconfig/tomcat<<'EOF'
  23. JAVA_HOME=/app/tools/jdk
  24. PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:/bin/:/sbin/:/usr/local/bin/:/usr/local/sbin/
  25. CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
  26. EOF
  27. systemctl daemon-reload
  1. 启动并查看进程 ```bash systemctl start tomcat

ps -ef |grep java ss -lntup |grep java

http://10.0.0.10:8080

<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 &quot;%r&quot; %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 &quot;%r&quot; %s %b &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; &quot;%{X-Forwarded-For}i&quot; " />
      </Host>
    </Engine>
  </Service>
</Server>

简单部署

zrlog.war.pdf
修改主配置文件,重启tomcat,然后访问即可

多实例介绍

  1. 准备多个tomcat目录,并以端口号命名。如tomcat-8081
  2. 修改server.xml中的访问端口和stop端口
  3. 创建并修改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

  1. 命令监控

    yum 安装的tomcat需要装上对应版本的-devel

  1. 脚本监控 ```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

会话共享

复制文件

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

\ ```

优化

p60

内存分析

  1. 监控/告警/巡检指标 显示负载过高
  2. top查看cpu用户使用率,wa || 或者vmstate 看r b
  3. 定位是cpu问题还是io问题
    • cpu:ps -ef/aux
    • io:iotop -o
  4. 发现是java问题,使用jstack或者脚本查看哪一个java进程有问题,获取pid
  5. jmap导出
  6. 开发使用使用MAT分析