无论面试还是平常的交流中,我们都会谈到垃圾收集器,JVM参数调优等等话题。由于之前的项目访问量,以及服务器资源不紧缺所以对该参数并没有太深的理解,最近一段时间再做电商相关的项目,两次线上事故让我意识到JVM调优的重要性
由于服务器相对紧缺,一台节点部署了多个服务,配置是4C16G150g的容量,上线一个月后发现服务器内存逐步增加,导致由此服务器告急,内存爆满,导致只能登陆阿里云控制台强制重启,第一次觉得是下项目过多,导致内存不足,所以向运维申请扩容服务器。但是因为其他项目的紧急处理,运维给忘记了,结果过了两个星期,线上又OOM了,同样的我们把原因归咎于项目多,运维延迟扩容背了锅。当内存增到24G的时候我们都觉得没问题了,但是我发现应该没那么快就内存不足,服务器重启后我时刻关注着服务器内存的消耗情况,并使用top命令追踪线程消耗内存的情况,突然发现,每隔一天内存消耗多一些。这个时候我的心里一阵发凉,突然意识到我们项目部署有问题。通过监控到商城的定时任务过多,内存消耗过大。
em。。。。不对呀,为什么没有发生GC回收,突然想到我们的部署没有设置JVM参数,-Xms默认占用物理内存1/64,-Xmx默认占用物理内存的1/4,我的妈呀,这还了得,五六个项目跑着,还没等到gc,就OOM了,赶紧等到晚上对项目项目进行了配置,设置了JVM参数如下:
-Xms1024M -Xmx1024M -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/data/logs/gc.log
设置后重启通过top命令,监控发现线程并没有占用过高的内存,并且gc日志也出现了回收的情况。又根据full gc的情况对大小对了调整。这才稳定了下来。
列名 |
含义 |
PID |
进程id |
PPID |
父进程id |
RUSER |
Real user name |
UID |
进程所有者的用户id |
USER |
进程所有者的用户名 |
GROUP |
进程所有者的组名 |
TTY |
启动进程的终端名。不是从终端启动的进程则显示为 ? |
PR |
优先级 |
NI |
nice值。负值表示高优先级,正值表示低优先级 |
P |
最后使用的CPU,仅在多CPU环境下有意义 |
%CPU |
上次更新到现在的CPU时间占用百分比 |
TIME |
进程使用的CPU时间总计,单位秒 |
TIME+ |
进程使用的CPU时间总计,单位1/100秒 |
%MEM |
进程使用的物理内存百分比 |
VIRT |
进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES |
SWAP |
进程使用的虚拟内存中,被换出的大小,单位kb。 |
RES |
进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA |
CODE |
可执行代码占用的物理内存大小,单位kb |
DATA |
可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb |
SHR |
共享内存大小,单位kb |
nFLT |
页面错误次数 |
nDRT |
最后一次写入到现在,被修改过的页面数。 |
S |
进程状态。 D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 |
COMMAND |
命令名/命令行 |
WCHAN |
若该进程在睡眠,则显示睡眠中的系统函数名 |
Flags |
任务标志,参考 sched.h |
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况。
前五行是当前系统情况整体的统计信息区。下面我们看每一行信息的具体意义。
第一行,任务队列信息,同 uptime 命令的执行结果,具体参数说明情况如下:
14:06:23 — 当前系统时间
up 70 days, 16:44 — 系统已经运行了70天16小时44分钟(在这期间系统没有重启过的吆!)
2 users — 当前有2个用户登录系统
load average: 1.15, 1.42, 1.44 — load average后面的三个数分别是1分钟、5分钟、15分钟的负载情况。
load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了。
第二行,Tasks — 任务(进程),具体信息说明如下:
系统现在共有206个进程,其中处于运行中的有1个,205个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个。
第三行,cpu状态信息,具体属性说明如下:
5.9%us — 用户空间占用CPU的百分比。
3.4% sy — 内核空间占用CPU的百分比。
0.0% ni — 改变过优先级的进程占用CPU的百分比
90.4% id — 空闲CPU百分比
0.0% wa — IO等待占用CPU的百分比
0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比
0.2% si — 软中断(Software Interrupts)占用CPU的百分比
备注:在这里CPU的使用比率和windows概念不同,需要理解linux系统用户空间和内核空间的相关知识!
第四行,内存状态,具体信息如下:
32949016k total — 物理内存总量(32GB)
14411180k used — 使用中的内存总量(14GB)
18537836k free — 空闲内存总量(18GB)
169884k buffers — 缓存的内存量 (169M)
第五行,swap交换分区信息,具体信息说明如下:
32764556k total — 交换区总量(32GB)
0k used — 使用的交换区总量(0K)
32764556k free — 空闲交换区总量(32GB)
3612636k cached — 缓冲的交换区总量(3.6GB)
备注:
第四行中使用中的内存总量(used)指的是现在系统内核控制的内存数,空闲内存总量(free)是内核还未纳入其管控范围的数量。纳入内核管理的内存不见得都在使用中,还包括过去使用过的现在可以被重复利用的内存,内核并不把这些可被重新使用的内存交还到free中去,因此在linux上free内存会越来越少,但不用为此担心。
如果出于习惯去计算可用内存数,这里有个近似的计算公式:第四行的free + 第四行的buffers + 第五行的cached,按这个公式此台服务器的可用内存:18537836k +169884k +3612636k = 22GB左右。
对于内存监控,在top里我们要时刻监控第五行swap交换分区的used,如果这个数值在不断的变化,说明内核在不断进行内存和swap的数据交换,这是真正的内存不够用了。
第六行,空行。
第七行以下:各进程(任务)的状态监控,项目列信息说明如下:
PID — 进程id
USER — 进程所有者
PR — 进程优先级
NI — nice值。负值表示高优先级,正值表示低优先级
VIRT — 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES — 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
SHR — 共享内存大小,单位kb
S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
%CPU — 上次更新到现在的CPU时间占用百分比
%MEM — 进程使用的物理内存百分比
TIME+ — 进程使用的CPU时间总计,单位1/100秒
COMMAND — 进程名称(命令名/命令行)
常用操作:
top //每隔5秒显式所有进程的资源占用情况
top -d 2 //每隔2秒显式所有进程的资源占用情况
top -c //每隔5秒显式进程的资源占用情况,并显示进程的命令行参数(默认只有进程名)
top -p 12345 -p 6789//每隔5秒显示pid是12345和pid是6789的两个进程的资源占用情况
top -d 2 -c -p 123456 //每隔2秒显示pid是12345的进程的资源使用情况,并显式该进程启动的命令行参数
该内容转自:http://www.cnblogs.com/peida/archive/2012/12/24/2831353.html
http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316399.html
参考博文,博文写得很详细
https://blog.csdn.net/baidu_35140444/article/details/82980139?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
package com.platform.annotation;
import lombok.Data;
/**
* @auth lipf
* @date 2020/6/3 16:22
*/
@Data
public class BaseShell {
//项目类型
String PROJECT_TYPE="SHOP";
//项目类型
String PROJECT_CHINESE="商城";
//jar包地址
String PATH_JARS="/opt/deploy/xunxj_shop/platofrm-admin/";
//项目jar名
String NAME="platform-admin.jar";
//jvm
String JVM="256";
//port
String PORT="13080";
//LOG
String GC_LOG="logs/gc.log";
//类型: 1ADMIN 2 API
String TYPE="1";
}
package com.vpclub.test;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
/**
* @auth lipf
* @date 2020/6/3 16:14
*/
public class GenerateShell {
public static void main(String[] args) {
BaseShell baseShell = new BaseShell();
//农场小程序
//farm_dev(baseShell);
farm_prod(baseShell);
//农场后台
//farm_admin_dev(baseShell);
//采购前端
//farm_buyer_dev(baseShell);
//商城后台
//shop_admin_dev(baseShell);
//shop_admin_prod(baseShell);
shop_admin_prod_120(baseShell);
//商城小程序
//shop_api_dev(baseShell);
//shop_api_prod(baseShell);
//团购小程序
//group_api_dev(baseShell);
//清远门户后台
// qingyuan_admin_dev(baseShell);
//清远门户前端
//qingyuan_api_dev(baseShell);
String active="prod120\\";
// String active="dev\\";
StringBuffer result = new StringBuffer("#!/bin/bash").append("\n");
//生成提示参数说明
result.append(generatePrams(baseShell));
result.append("\n").append("\n");
//生成常量
result.append(generateConstant(baseShell));
result.append("\n").append("\n");
//生成检查服务程序是否在运行
result.append(generateIsExist(baseShell));
result.append("\n").append("\n");
//生成启动服务
result.append(generateStart(baseShell));
result.append("\n").append("\n");
//生成停止服务
result.append(generateStop(baseShell));
result.append("\n").append("\n");
//生成状态服务
result.append(generateStatus(baseShell));
result.append("\n").append("\n");
//生成入口判断
result.append(generateInDoor(baseShell));
result.append("\n").append("\n");
System.out.println(result);
//生成文件
// 生成的文件路径
String path = "F:\\工作文档\\服务器部署\\shell脚本\\"+active;
if("1".equals(baseShell.getTYPE())){
path=path+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin_opration.sh";
}else if ("2".equals(baseShell.getTYPE())){
path=path+baseShell.getPROJECT_TYPE().toLowerCase()+"_api_opration.sh";
}
File file = new File(path);
if (!file.exists()) {
file.getParentFile().mkdirs();
}
try {
file.createNewFile();
// write 解决中文乱码问题
OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
BufferedWriter bw = new BufferedWriter(fw);
bw.write(result.toString());
bw.flush();
bw.close();
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
清远门户后台测试环境请求
*/
private static void qingyuan_admin_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("QINGYUAN");
//项目类型
baseShell.setPROJECT_CHINESE("清远门户");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/qingyuan_agricultural_portal/agricultural_manager/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("256");
//port
baseShell.setPORT("14081");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
清远门户前台测试环境请求
*/
private static void qingyuan_api_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("QINGYUAN");
//项目类型
baseShell.setPROJECT_CHINESE("清远门户");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/qingyuan_agricultural_portal/agricultural_portal/");
//项目jar名
baseShell.setNAME("platform-portal-api.jar");
//jvm
baseShell.setJVM("256");
//port
baseShell.setPORT("14082");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
团购小程序测试环境请求
*/
private static void group_api_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("GROUP");
//项目类型
baseShell.setPROJECT_CHINESE("团购小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_shop/platofrm-groupbuy/");
//项目jar名
baseShell.setNAME("platform-groupbuy.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("15070");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
商城小程序测试环境请求
*/
private static void shop_api_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("SHOP");
//项目类型
baseShell.setPROJECT_CHINESE("商城小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_shop/platofrm-shop/");
//项目jar名
baseShell.setNAME("platform-shop.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("19080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
商城小程序测试环境请求
*/
private static void shop_api_prod(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("SHOP");
//项目类型
baseShell.setPROJECT_CHINESE("商城小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xxj_shop/");
//项目jar名
baseShell.setNAME("platform-shop.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("19080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
商城后端测试环境请求
*/
private static void shop_admin_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("SHOP");
//项目类型
baseShell.setPROJECT_CHINESE("商城后台");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_shop/platofrm-admin/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("13080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
商城后端测试环境请求
*/
private static void shop_admin_prod(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("SHOP");
//项目类型
baseShell.setPROJECT_CHINESE("商城后台");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xxj_shop_manage/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("1024");
//port
baseShell.setPORT("13080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
120服务器商城后端测试环境请求
*/
private static void shop_admin_prod_120(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("SHOP");
//项目类型
baseShell.setPROJECT_CHINESE("商城后台");
//jar包地址
baseShell.setPATH_JARS("/data/xxj_projects/xxj_shop/xxj_shop_admin/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("1024");
//port
baseShell.setPORT("13080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
采购前端测试环境请求
*/
private static void farm_buyer_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("BUYER");
//项目类型
baseShell.setPROJECT_CHINESE("采购前台");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_purchase_platform/platform-api/");
//项目jar名
baseShell.setNAME("platform-api.jar");
//jvm
baseShell.setJVM("256");
//port
baseShell.setPORT("16080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
农场后台测试环境请求
*/
private static void farm_admin_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("FARM");
//项目类型
baseShell.setPROJECT_CHINESE("农场小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_purchase_platform/platform-admin/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("14080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
农场后台正式环境请求
*/
private static void farm_admin_prod(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("FARM");
//项目类型
baseShell.setPROJECT_CHINESE("农场小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xxj_buyer_manage/");
//项目jar名
baseShell.setNAME("platform-admin.jar");
//jvm
baseShell.setJVM("512");
//port
baseShell.setPORT("17080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("1");
}
/*
农场小程序正式环境请求
*/
private static void farm_prod(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("FARM");
//项目类型
baseShell.setPROJECT_CHINESE("农场小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xxj_farm/");
//项目jar名
baseShell.setNAME("platform-farm.jar");
//jvm
baseShell.setJVM("256");
//port
baseShell.setPORT("11080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
/*
农场小程序测试环境请求
*/
private static void farm_dev(BaseShell baseShell) {
//项目类型
baseShell.setPROJECT_TYPE("FARM");
//项目类型
baseShell.setPROJECT_CHINESE("农场小程序");
//jar包地址
baseShell.setPATH_JARS("/opt/deploy/xunxj_purchase_platform/platform-farm/");
//项目jar名
baseShell.setNAME("platform-farm.jar");
//jvm
baseShell.setJVM("256");
//port
baseShell.setPORT("11080");
//LOG
baseShell.setGC_LOG("logs/gc.log");
//1 admin 2 api
baseShell.setTYPE("2");
}
//生成参数判断
private static String generatePrams(BaseShell baseShell) {
StringBuffer data = new StringBuffer();
data.append("#使用说明,用来提示输入参数").append("\n");
data.append("usage() {").append("\n");
//1 admin 2 api
if (baseShell.getTYPE().equals("1")){
data.append(" ").append("echo \"Usage: ./opration.sh [start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin ")
.append(" | stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin")
.append(" | status")
.append("]\"").append("\n");
}else{
data.append(" ").append("echo \"Usage: ./opration.sh [start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api ")
.append(" | stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api")
.append(" | status")
.append("]\"").append("\n");
}
data.append(" ").append("exit 1").append("\n");
data.append("}").append("\n");
return data.toString();
}
//生成入口判断
private static String generateInDoor(BaseShell baseShell) {
StringBuffer data = new StringBuffer();
data.append("#根据输入参数,选择执行对应方法,不输入则执行使用说明").append("\n");
data.append("case \"$1\" in").append("\n");
data.append(" ").append("#"+baseShell.getPROJECT_CHINESE()+"入口").append("\n");
//1 admin 2 api
if (baseShell.getTYPE().equals("1")){
data.append(" ").append("\"start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin\")").append("\n");
data.append(" ").append("start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
data.append(" ").append(";;").append("\n");
data.append(" ").append("\"stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin\")").append("\n");
data.append(" ").append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
data.append(" ").append(";;").append("\n");
}else{
data.append(" ").append("\"start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api\")").append("\n");
data.append(" ").append("start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
data.append(" ").append(";;").append("\n");
data.append(" ").append("\"stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api\")").append("\n");
data.append(" ").append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
data.append(" ").append(";;").append("\n");
}
data.append(" ").append("\"status\")").append("\n");
data.append(" ").append("status").append("\n");
data.append(" ").append(";;").append("\n");
data.append(" *)").append("\n");
data.append(" usage").append("\n");
data.append(" ;;").append("\n");
data.append("esac").append("\n");
return data.toString();
}
//生成状态服务
private static String generateStatus(BaseShell baseShell) {
StringBuffer data = new StringBuffer();
data.append("#状态").append("\n");
data.append("status(){").append("\n");
//1 admin 2 api
if (baseShell.getTYPE().equals("1")){
data.append(" ").append("#"+baseShell.getPROJECT_CHINESE()+"后台状态").append("\n");
data.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
data.append(" ").append("if [ $? -eq \"0\" ]; then").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/${NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN} is running. Pid is ${pid}\"").append("\n");
data.append(" ").append("else").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/${NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN} is not running\"").append("\n");
}else{
data.append(" ").append("#"+baseShell.getPROJECT_CHINESE().toLowerCase()+"前台api状态").append("\n");
data.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
data.append(" ").append("if [ $? -eq \"0\" ]; then").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/${NAME_"+baseShell.getPROJECT_TYPE()+"_API} is running. Pid is ${pid}\"").append("\n");
data.append(" ").append("else").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/${NAME_"+baseShell.getPROJECT_TYPE()+"_API} is not running\"").append("\n");
}
data.append(" ").append("fi").append("\n");
data.append("}").append("\n");
return data.toString();
}
//生成停止服务
private static String generateStop(BaseShell baseShell) {
/**
#启动商城后台服务
*/
StringBuffer data = new StringBuffer();
//1 admin 2 api
if (baseShell.getTYPE().equals("1")){
data.append("#停止"+baseShell.getPROJECT_CHINESE()+"后台服务").append("\n");
data.append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("(){").append("\n");
data.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
data.append(" ").append("if [ $? -eq \"0\" ]; then").append("\n");
data.append(" ").append("kill -9 $pid").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/${NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN} is stoped...\"").append("\n");
data.append(" ").append("else").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/${NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN} is not running\"").append("\n");
}else{
data.append("#停止"+baseShell.getPROJECT_CHINESE().toLowerCase()+"前台api服务").append("\n");
data.append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("(){").append("\n");
data.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
data.append(" ").append("if [ $? -eq \"0\" ]; then").append("\n");
data.append(" ").append("kill -9 $pid").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/${NAME_"+baseShell.getPROJECT_TYPE()+"_API} is stoped..\"").append("\n");
data.append(" ").append("else").append("\n");
data.append(" ").append("echo \"${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/${NAME_"+baseShell.getPROJECT_TYPE()+"_API} is not running\"").append("\n");
}
data.append(" ").append("fi").append("\n");
data.append("}").append("\n");
return data.toString();
}
//生成启动服务
private static String generateStart(BaseShell baseShell) {
/**
#启动商城后台服务
*/
StringBuffer data = new StringBuffer();
//1 admin 2 api
if (baseShell.getTYPE().equals("1")){
data.append("#启动"+baseShell.getPROJECT_CHINESE()+"后台服务").append("\n");
data.append("start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("(){").append("\n");
//data.append(" ").append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
data.append(" ").append("nohup java -Xms").append("${JVM_"+baseShell.getPROJECT_TYPE()+"_ADMIN}").append("M ")
.append("-Xmx").append("${JVM_"+baseShell.getPROJECT_TYPE()+"_ADMIN}").append("M ")
.append(" -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:").append("${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/").append("${LOG_"+baseShell.getPROJECT_TYPE()+"_ADMIN}")
.append(" -jar ").append("${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN}/$NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN")
.append(" --server.port=").append("${PORT_"+baseShell.getPROJECT_TYPE()+"_ADMIN} >"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin.out 2>&1 &")
.append("\n")
.append(" ").append("sleep 2").append("\n")
.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("\n");
}else{
data.append("#启动"+baseShell.getPROJECT_CHINESE()+"前台api服务").append("\n");
data.append("start_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("(){").append("\n");
//data.append(" ").append("stop_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
data.append(" ").append("nohup java -Xms").append("${JVM_"+baseShell.getPROJECT_TYPE()+"_API}").append("M ")
.append("-Xmx").append("${JVM_"+baseShell.getPROJECT_TYPE()+"_API}").append("M ")
.append(" -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:").append("${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/").append("${LOG_"+baseShell.getPROJECT_TYPE()+"_API}")
.append(" -jar ").append("${PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API}/$NAME_"+baseShell.getPROJECT_TYPE()+"_API")
.append(" --server.port=").append("${PORT_"+baseShell.getPROJECT_TYPE()+"_API} >"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api.out 2>&1 &")
.append("\n")
.append(" ").append("sleep 2").append("\n")
.append(" ").append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("\n");
}
data.append("}").append("\n");
return data.toString();
}
//生成检查服务程序是否在运行
private static String generateIsExist(BaseShell baseShell) {
/**
#检查服务程序是否在运行
is_exist_shop_admin(){
pid=`ps -ef|grep $PATH_JARS_SHOP_ADMIN/$NAME_SHOP_ADMIN |grep -v grep|awk '{print $2}'`
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
*/
StringBuffer data = new StringBuffer();
data.append("#检查"+baseShell.getPROJECT_CHINESE()+"服务程序是否在运行").append("\n");
//1 admin 2 api
if ("1".equals(baseShell.getTYPE())){
data.append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_admin").append("(){").append("\n");
data.append(" ").append("pid=`ps -ef|grep $PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN/$NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN |grep -v grep|awk '{print $2}'`").append("\n");
}else{
data.append("is_exist_"+baseShell.getPROJECT_TYPE().toLowerCase()+"_api").append("(){").append("\n");
data.append(" ").append("pid=`ps -ef|grep $PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API/$NAME_"+baseShell.getPROJECT_TYPE()+"_API |grep -v grep|awk '{print $2}'`").append("\n");
}
data.append(" ").append("echo $pid").append("\n");
data.append(" ").append("#如果不存在返回1,存在返回0").append("\n");
data.append(" ").append("if [ -z \"${pid}\" ]; then").append("\n");
data.append(" ").append("return 1").append("\n");
data.append(" ").append("else").append("\n");
data.append(" ").append("return 0").append("\n");
data.append(" ").append("fi").append("\n");
data.append("}").append("\n");
return data.toString();
}
//生成常量
private static String generateConstant(BaseShell baseShell) {
/**
* #商城(团购)后台
* PATH_JARS_SHOP_ADMIN=/opt/deploy/xunxj_shop/platofrm-admin/
* NAME_SHOP_ADMIN=platform-admin.jar
* JVM_SHOP_ADMIN=256
* PORT_SHOP_ADMIN=13080
* LOG_SHOP_ADMIN=${PATH_JARS_SHOP_ADMIN}/logs/gc.log
*
* #商城前台api
* PATH_JARS_SHOP_API=/opt/deploy/xunxj_shop/platofrm-shop/
* NAME_SHOP_API=platform-shop.jar
* JVM_SHOP_API=256
* PORT_SHOP_API=19080
* LOG_SHOP_API=${PATH_JARS_SHOP_API}/logs/gc.log
*/
StringBuffer data = new StringBuffer();
//1 admin 2 api
if ("1".equals(baseShell.getTYPE())){
data.append("#"+baseShell.getPROJECT_CHINESE()+"后台").append("\n");
data.append("PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_ADMIN").append("=").append(baseShell.getPATH_JARS()).append("\n");
data.append("NAME_"+baseShell.getPROJECT_TYPE()+"_ADMIN").append("=").append(baseShell.getNAME()).append("\n");
data.append("JVM_"+baseShell.getPROJECT_TYPE()+"_ADMIN").append("=").append(baseShell.getJVM()).append("\n");
data.append("PORT_"+baseShell.getPROJECT_TYPE()+"_ADMIN").append("=").append(baseShell.getPORT()).append("\n");
data.append("LOG_"+baseShell.getPROJECT_TYPE()+"_ADMIN").append("=").append(baseShell.getGC_LOG()).append("\n");
}else if ("2".equals(baseShell.getTYPE())){
data.append("#"+baseShell.getPROJECT_CHINESE()+"前台api").append("\n");
data.append("PATH_JARS_"+baseShell.getPROJECT_TYPE()+"_API").append("=").append(baseShell.getPATH_JARS()).append("\n");
data.append("NAME_"+baseShell.getPROJECT_TYPE()+"_API").append("=").append(baseShell.getNAME()).append("\n");
data.append("JVM_"+baseShell.getPROJECT_TYPE()+"_API").append("=").append(baseShell.getJVM()).append("\n");
data.append("PORT_"+baseShell.getPROJECT_TYPE()+"_API").append("=").append(baseShell.getPORT()).append("\n");
data.append("LOG_"+baseShell.getPROJECT_TYPE()+"_API").append("=").append(baseShell.getGC_LOG()).append("\n");
}
return data.toString();
}
}
生成后的shell脚本如下:
#!/bin/bash
#使用说明,用来提示输入参数
usage() {
echo "Usage: ./opration.sh [start_shop_api | stop_shop_api | status]"
exit 1
}
#商城小程序前台api
PATH_JARS_SHOP_API=/opt/deploy/xunxj_shop/platofrm-shop/
NAME_SHOP_API=platform-shop.jar
JVM_SHOP_API=512
PORT_SHOP_API=19080
LOG_SHOP_API=logs/gc.log
#检查商城小程序服务程序是否在运行
is_exist_shop_api(){
pid=`ps -ef|grep $PATH_JARS_SHOP_API/$NAME_SHOP_API |grep -v grep|awk '{print $2}'`
echo $pid
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
#启动商城小程序前台api服务
start_shop_api(){
nohup java -Xms${JVM_SHOP_API}M -Xmx${JVM_SHOP_API}M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGC -Xloggc:./${LOG_SHOP_API} -jar ${PATH_JARS_SHOP_API}/$NAME_SHOP_API --server.port=${PORT_SHOP_API} >shop_api.out 2>&1 &
sleep 2
is_exist_shop_api
}
#停止商城小程序前台api服务
stop_shop_api(){
is_exist_shop_api
if [ $? -eq "0" ]; then
kill -9 $pid
echo "${PATH_JARS_SHOP_API}/${NAME_SHOP_API} is stoped.."
else
echo "${PATH_JARS_SHOP_API}/${NAME_SHOP_API} is not running"
fi
}
#状态
status(){
#商城小程序前台api状态
is_exist_shop_api
if [ $? -eq "0" ]; then
echo "${PATH_JARS_SHOP_API}/${NAME_SHOP_API} is running. Pid is ${pid}"
else
echo "${PATH_JARS_SHOP_API}/${NAME_SHOP_API} is not running"
fi
}
#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
#商城小程序入口
"start_shop_api")
start_shop_api
;;
"stop_shop_api")
stop_shop_api
;;
"status")
status
;;
*)
usage
;;
esac
五、手动内存释放
有的会后内存还是会持续飙升,这个时候可以手动处理下:
echo 3 > /proc/sys/vm/drop_caches
这个文件可以设置的值分别为1、2、3。它们所表示的含义为:
echo 1 > /proc/sys/vm/drop_caches:表示清除 page cache。
echo 2 > /proc/sys/vm/drop_caches:表示清除回收 slab 分配器中的对象(包括目录项缓存和 inode 缓存)。slab 分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的 page cache
echo 3 > /proc/sys/vm/drop_caches:表示清除 page cache 和 slab 分配器中的缓存对象
处理前后:
执行前最好sync
手动执行sync命令(描述:sync 命令运行 sync 子例程。如果必须停止系统,则运行sync 命令以确保文件系统的完整性。sync 命令将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-node、已延迟的块 I/O 和读写映射文件)
参考博文:
https://blog.csdn.net/lqglqglqg/article/details/82313966
https://www.jianshu.com/p/016f7cf0380d
https://blog.csdn.net/wyzxg/article/details/7279986/(AAA)