微服务项目运维管理
作者 |
刘畅 |
时间 |
2020-12-13 |
目录
4.6 根据pipeline语法生成器生成需要的pipeline脚本 20
1 从运维角度看微服务
1.1 单体应用vs微服务
1 单体架构优势
(1) 易于部署
(2) 易于测试
2 单体架构不足
(1) 代码膨胀、难以维护
(2) 构建、部署成本大
(3) 新人上手难
1.2 微服务特点
1、服务组件化
每个服务独立开发、部署、有效避免一个服务的修改引起整个系统重新部署。
2 技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么的敏感。
3 独立部署
每个微服务独立部署,加快部署速度,方便扩展。
4 扩展性强
每个微服务可以部署多个,并且有负载均衡能力。
5 独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。
1.3 微服务不足
1 沟通成本
2 数据一致性
3 运维成本
4 内部架构复杂性
5 大量服务如何治理
6 如何部署
7 如何监控
8 内部数据流复杂,事务不易管理
1.4 java微服务框架
1、java在开发语言排行榜第一,在微服务实现这块也是最为成熟的、应用广泛。
2、java微服务框架介绍
(1) Spring Boot
快速开发微服务的框架。
(2) Spring Cloud
基于Spring Boot实现的一个完整的微服务解决方案。
(3) Dubbo
阿里巴巴开源的微服务治理框架。
2 部署微服务考虑的问题
2.1 微服务架构图
(1) 微服务间如何通信
(2) 微服务如何发现彼此
(3) 组件之间怎么调用关系
注册中心
(4) 哪个服务作为整个网站入口
(5) 哪些微服务需要对外访问
portal
(6) 微服务怎么部署?更新?扩容?
jenkins ansiable
2.2 为什么要用注册中心
1 微服务面向的问题
(1) 怎么记录一个微服务多个副本接口地址
(2) 怎么实现一个微服务多个副本负载均衡
(3) 怎么判断一个微服务副本是否可用
(4) 主流注册中心Eureka、Nacos、Consul
3 部署SpringCloud微服务项目
3.1 熟悉SpringCloud微服务项目
1 项目架构图
2 项目信息表
服务器IP |
主机名 |
端口 |
服务 |
用途 |
172.16.1.61 172.16.1.62 172.16.1.63 |
eureka01 eureka02 eureka03 |
8888 |
eureka |
注册中心 |
172.16.1.64 |
mariadb |
3306 |
mariadb |
数据库 |
172.16.1.65 172.16.1.66 |
ms01 ms02 |
8010 |
product |
商品服务 |
8020 |
order |
订单服务 |
||
8030 |
stock |
库存服务 |
||
8080 |
portal |
前端 |
||
9999 |
gateway |
网关 |
||
172.16.1.67 |
nginx |
80 |
nginx |
负载均衡器 |
172.16.1.68 |
msjenkins |
8080 |
jenkins |
微服务发布平台 |
172.16.1.69 |
msgitlab |
80 |
gitlab |
代码仓库 |
172.16.1.70 |
pinpoint |
8079 |
pinpoint相关组件 |
微服务监控系统 |
3 环境准备
(1) 在172.16.1.61机器上安装maven和jdk环境
1) 配置环境变量
# tar -xzf jdk-8u45-linux-x64.tar.gz
# tar -xzf apache-maven-3.5.0-bin.tar.gz
# mv jdk1.8.0_45/ /usr/local/jdk
# mv apache-maven-3.5.0/ /usr/local/maven
# cat >>/etc/profile<< EOF
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=\$JAVA_HOME/lib/tools.jar:\$JAVA_HOME/jre/lib/rt.jar
export PATH=\$JAVA_HOME/bin:/usr/local/maven/bin:\$PATH
EOF
# source /etc/profile
2) 修改maven仓库地址
参考网址:https://maven.aliyun.com/mvn/guide
打开maven的配置文件,一般在maven安装目录的conf/settings.xml,在<mirrors></mirrors>标签中添加如下mirror子节点。
# vim /usr/local/maven/conf/settings.xml
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
(2) 在172.16.1.62、172.16.1.63、172.16.1.65、172.16.1.66机器上安装jdk环境
# tar -xzf jdk-8u45-linux-x64.tar.gz
# mv jdk1.8.0_45/ /usr/local/jdk
# cat >>/etc/profile<< EOF
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=\$JAVA_HOME/lib/tools.jar:\$JAVA_HOME/jre/lib/rt.jar
export PATH=\$JAVA_HOME/bin:\$PATH
EOF
# source /etc/profile
3.2 源代码编译构建
在172.16.1.61节点上操作
1 编译
# unzip simple-microservice.zip
# cd simple-microservice/
# mvn clean package -Dmaven.test.skip=true
2 编译后jar包所在位置
(1) 服务目录
(2) 配置目录
3.3 部署Eureka集群
在172.16.1.61、62、63节点上操作
1 修改源代码中eureka配置文件并编译
在172.16.1.61节点上操作
# vim eureka-service/src/main/resources/application-fat.yml
eureka:
server:
renewal-percent-threshold: 0.9
enable-self-preservation: false
eviction-interval-timer-in-ms: 40000
instance:
hostname: 127.0.0.1
prefer-ip-address: true
client:
register-with-eureka: true
serviceUrl:
defaultZone: http://172.16.1.61:${server.port}/eureka/,http://172.16.1.62:${server.port}/eureka/,http://172.16.1.63:${server.port}/eureka/
fetch-registry: true
编译eureka
# mvn clean package -Dmaven.test.skip=true
2 将编译好的jar包放到指定目录下
# mkdir -p /data/ms/eureka
# cp -a eureka-service/target/eureka-service.jar /data/ms/eureka/
3 使用systemd管理eureka
# vim /usr/lib/systemd/system/eureka.service
[Unit]
Description=Eureka
Documentation=eureka
[Service]
ExecStart=/usr/local/jdk/bin/java -jar /data/ms/eureka/eureka-service.jar
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
# systemctl daemon-reload
# systemctl start eureka.service
# systemctl enable eureka.service
# netstat -tunlp | grep 8888
tcp6 0 0 :::8888 :::* LISTEN 2734/java
# jps -l
2865 sun.tools.jps.Jps
2734 /data/ms/eureka/eureka-service.jar
4 在浏览器中访问
3.4 部署mysql数据库
在172.16.1.64节点上操作
1 安装Mariadb数据库
# yum install mariadb-server -y
# systemctl start mariadb
# systemctl enable mariadb
# mysqladmin -uroot password '123456'
# mysql -uroot -p123456
2 创建一个账号并授权,该账户用于微服务连接
MariaDB [(none)]> grant all on *.* to 'ms'@'%' identified by '123456';
MariaDB [(none)]> flush privileges;
3 将源代码目录里sql文件拷贝到数据库服务器上
在172.16.1.61节点上操作
# scp -r db/ root@172.16.1.64:~
4 创建数据库并导入表
MariaDB [(none)]> create database tb_product;
MariaDB [(none)]> create database tb_stock;
MariaDB [(none)]> create database tb_order;
MariaDB [(none)]> use tb_product;
MariaDB [tb_product]> source /root/db/product.sql
MariaDB [tb_product]> use tb_stock;
MariaDB [tb_stock]> source /root/db/stock.sql
MariaDB [tb_stock]> use tb_order;
MariaDB [tb_order]> source /root/db/order.sql
MariaDB [tb_order]> exit;
3.5 部署业务程序、网关、前端
1 在172.16.1.65、66节点上创建微服务目录
# mkdir -p /data/ms/{product,stock,order,portal,gateway}
2 修改源码配置文件并编译
在172.16.1.61节点上操作
(1) 业务程序
修改商品服务配置文件如下,库存服务、订单服务配置修改同理
# cat product-service/product-service-biz/src/main/resources/application-fat.yml
spring:
datasource:
url: jdbc:mysql://172.16.1.64:3306/tb_product?characterEncoding=utf-8
username: ms
password: 123456
driver-class-name: com.mysql.jdbc.Driver
eureka:
instance:
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://172.16.1.61:8888/eureka/,http://172.16.1.62:8888/eureka/,http://172.16.1.63:8888/eureka/
(2) 前端、网关
修改前端服务配置文件如下、网关服务修改配置文件同理
# cat portal-service/src/main/resources/application-fat.yml
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://172.16.1.61:8888/eureka/,http://172.16.1.62:8888/eureka/,http://172.16.1.63:8888/eureka/
register-with-eureka: true
fetch-registry: true
spring:
freemarker:
allow-request-override: false
allow-session-override: false
cache: true
charset: UTF-8
check-template-location: true
content-type: text/html
enabled: true
expose-request-attributes: false
expose-session-attributes: false
expose-spring-macro-helpers: true
prefer-file-system-access: true
suffix: .ftl
template-loader-path: classpath:/templates/
(3) 编译
# mvn clean package -Dmaven.test.skip=true
3 编写脚本拷贝编译好的jar包到172.16.1.65、66机器上
在172.16.1.61节点上操作
(1) 创建172.16.1.61节点和172.16.1.65、66节点的免交互
# ssh-keygen
# ssh-copy-id root@172.16.1.65
# ssh-copy-id root@172.16.1.66
(2) 业务程序
for ip in 172.16.1.65 172.16.1.66; do
for name in product order stock; do
scp $name-service/$name-service-biz/target/$name-service-biz.jar root@$ip:/data/ms/$name
done
done
(3) 前端、网关
for ip in 172.16.1.65 172.16.1.66; do
for name in portal gateway; do
scp $name-service/target/$name-service.jar root@$ip:/data/ms/$name
done
done
4 生成systemd service配置文件并启动服务
在172.16.1.65、66节点上操作
(1) 生成业务程序的systemd service
for name in product order stock; do
cat > /usr/lib/systemd/system/$name.service << EOF
[Unit]
Description=$name
Documentation=$name
[Service]
ExecStart=/usr/local/jdk/bin/java -jar /data/ms/$name/$name-service-biz.jar
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
done
(2) 生成前端、网关的systemd service
for name in portal gateway; do
cat > /usr/lib/systemd/system/$name.service << EOF
[Unit]
Description=$name
Documentation=$name
[Service]
ExecStart=/usr/local/jdk/bin/java -jar /data/ms/$name/$name-service.jar
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
done
(3) 启动业务程序、前端、网关,并加入到开机自启
for name in product order stock portal gateway; do
systemctl restart $name
systemctl enable $name
done
说明:如果服务没有起来,可以使用journalctl -u $name -f持续查看服务的日志信息。
(4) 查看java进程
# jps -l
3216 /data/ms/gateway/gateway-service.jar
3106 /data/ms/order/order-service-biz.jar
3076 /data/ms/product/product-service-biz.jar
3176 /data/ms/portal/portal-service.jar
3146 /data/ms/stock/stock-service-biz.jar
3434 sun.tools.jps.Jps
5 在浏览器中查看注册的业务程序、前端、网关
url: http://172.16.1.61:8888/
3.6 使用Nginx负载均衡对外访问
在172.16.1.67节点上操作
1 安装nginx
# yum install nginx -y
2 配置nginx负载均衡文件
(1) 配置文件
# cat /etc/nginx/conf.d/ms.conf
upstream gateway {
server 172.16.1.65:9999;
server 172.16.1.66:9999;
}
server {
listen 80;
server_name gateway.ctnrs.com;
access_log /var/log/nginx/gateway-access.log main;
location / {
proxy_pass http://gateway;
}
}
upstream portal {
server 172.16.1.65:8080;
server 172.16.1.66:8080;
}
server {
listen 80;
server_name portal.ctnrs.com;
access_log /var/log/nginx/portal-access.log main;
location / {
proxy_pass http://portal;
}
}
# 说明
# gateway 包含在 portal中
# ls portal-service/src/main/resources/static/js/
# index.js jquery-1.8.2.min.js layui orderList.js productList.js
# portal 调用
# http://gateway.ctnrs.com/product/queryAllProduct
# http://gateway.ctnrs.com/order/queryAllOrder
(2) 检查配置文件
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
(3) 启动nginx并加入开机自启动
# systemctl restart nginx
# systemctl enable nginx
3 修改本地hosts解析
C:\Windows\System32\drivers\etc\hosts
172.16.1.67 portal.ctnrs.com gateway.ctnrs.com
4 在浏览其中访问
URL地址:http://portal.ctnrs.com/
4 基于jenkins构建微服务发布平台
在172.16.1.78节点上操作。
4.1 安装gitlab和jenkins
1 使用docker方式在172.16.1.68节点上安装jenkins,具体安装请参考jenkins安装文档,这里安装步骤省略。
2 使用docker方式在172.16.1.69节点上安装gitlab,具体安装请参考gitlab安装文档,这里安装步骤省略。
将修改好配置文件的微服务项目上传到gitlab的自建仓库project/microserver.git中,需要将已经编译好的target目录jar文件删除,否则会导致微服务无法在eureka集群中注册(这里省略步骤)。
4.2 安装ansiable
# yum install ansible -y # ssh-keygen
# ssh-copy-id root@172.16.1.65
# ssh-copy-id root@172.16.1.66
测试ansiable
# vim /etc/ansible/hosts
[webservers]
172.16.1.65
172.16.1.66
# ansible webservers -m ping
4.3 安装jenkins分布式节点
1 创建从节点的工作目录
# mkdir -p /jenkins_home
2 创建从节点
3 上线从节点
# cd /jenkins_home/
# wget http://172.16.1.68:8080/jnlpJars/agent.jar
# nohup /usr/local/jdk/bin/java -jar agent.jar -jnlpUrl http://172.16.1.68:8080/computer/localhost/slave-agent.jnlp -s
ecret 3def841847662ecd2ed43460f671b59ac112189107b952bf3ab3832b48d2fe01 -workDir "/jenkins_home" &>agent.log &
4 上线完成
4.4 安装jenkins插件
1 发布流程
(1) 自动拉取代码
(2) 代码编译
(3) 推送构建文件
(4) 部署构建文件,并重启服务
(5) 测试访问
2 安装插件如下
pipeline(pipeline脚本)、git(git命令,用于拉取git仓库)、git parameter(获取git仓库标签)、extended choice parameter(多选框)、ansible(批量化处理)
4.5 创建pipeline项目
4.6 根据pipeline语法生成器生成需要的pipeline脚本
1 获取git仓库标签脚本
parameters {
gitParameter branch: '', branchFilter: '.*', defaultValue: '', description: '请选择要发布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_TAG'
}
2 生成要发布的微服务多选框的脚本
parameters {
extendedChoice description: '请选择要发布的微服务', multiSelectDelimiter: ',', name: 'Service', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'portal,gateway,product,stock,order', visibleItemCount: 5
}
3 生成要发布服务器组的脚本
parameters {
choice choices: ['webservers1', 'webservers2'], description: '请选择要发布的服务器组', name: 'Servers'
}
4 生成拉取gitlab代码仓库的脚本
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'a0c7bec9-230b-4b86-995b-ef162b4d5f42', url: 'http://172.16.1.69/project/microserver.git']]])
4.7 创建pipeline脚本
pipeline {
agent {
label "localhost"
}
parameters {
gitParameter branch: '', branchFilter: '.*', defaultValue: 'master', description: '请选择要发布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'
extendedChoice description: '请选择要发布的微服务', multiSelectDelimiter: ',', name: 'Service', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'portal,gateway,product,stock,order', visibleItemCount: 5
choice choices: ['webservers1', 'webservers2'], description: '请选择要发布的服务器组', name: 'Servers'
}
stages {
stage('拉取代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '$Branch']], extensions: [], userRemoteConfigs: [[credentialsId: 'a0c7bec9-230b-4b86-995b-ef162b4d5f42', url: 'http://172.16.1.69/project/microserver.git']]])
}
}
stage('代码编译') {
steps {
sh '''
JAVA_HOME=/usr/local/jdk
PATH=$JAVA_HOME/bin:/usr/local/maven/bin:$PATH
mvn clean package -Dmaven.test.skip=true
'''
}
}
stage('部署') {
steps {
// 将用户选择的微服务的构建文件拷贝到临时目录,以便ansible统一推送
// Service=portal,gateway,product,stock,order
script {
def tmp_dir = "$WORKSPACE/tmp"
def services = "$Service".split(",")
sh """
[ -d $tmp_dir ] && rm -rf $tmp_dir
mkdir -p $tmp_dir
"""
for(name in services) {
sh """
echo $name
pwd
ls
cd $name-service
if ls |grep biz &>/dev/null;then
cd $name-service-biz
fi
mv target/*.jar $tmp_dir
ls $tmp_dir
"""
}
}
// 生成主机清单文件和playbook
sh """
cat > /jenkins_home/.hosts << EOF
[webservers1]
172.16.1.65
[webservers2]
172.16.1.66
EOF
cat > /jenkins_home/.playbook <<EOF
- hosts: $Servers
gather_facts: no
vars:
workspace: $WORKSPACE
work_dir: "/data/ms"
service_name: $Service # Service=portal,gateway,product,stock,order
tasks:
- name: 推送构建文件
copy:
src={{ item }}
dest={{ work_dir }}/{{ item.split("/")[-1].split("-")[0] }}
with_fileglob:
- "{{ workspace }}/tmp/*.jar"
- name: 重启服务
systemd: name={{ item }} state=restarted
loop: "{{ service_name.split(',') }}"
EOF
"""
ansiblePlaybook(
playbook: "/jenkins_home/.playbook",
inventory: "/jenkins_home/.hosts",
credentialsId: ""
)
}
}
}
}
4.8 构建成功
# 所有服务在eureak集群中正常注册
4.9 测试
1 在gitlab中修改portal-service前端数据
2 重新部署portal服务到172.16.1.66(webservers2)节点
3 在浏览器中循环刷新微服务项目,会发现标题循环发生改变
http://portal.ctnrs.com/
# 出现添加的内容
# 没有出现添加的内容
5 微服务全链路监控
5.1 说明
1 全链路监控是什么
随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。这些服务可能不同编程语言开发,不同团队开发,可能部署很多副本。因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。全链路监控组件就在这样的问题背景下产生了。全链路性能监控从整体维度到局部维度展示各项指标,将跨应用的所有调用链性能信息集中展现,可方便度量整体和局部性能,并且方便找到故障产生的源头,生产上可极大缩短故障排除时间。
2 全链路监控解决什么问题
(1) 请求链路追踪:通过分析服务调用关系,绘制运行时拓扑信息,可视化展示
(2) 调用情况衡量:各个调用环节的性能分析,例如吞吐量、响应时间、错误次数
(3) 容器规划参考:扩容/缩容、服务降级、流量控制
(4) 运行情况反馈:告警,通过调用链结合业务日志快速定位错误信息
3 全链路监控系统选择依据
全链路监控系统有很多,应从这几方面选择:
(1) 探针的性能消耗
APM组件服务的影响应该做到足够小,数据分析要快,性能占用小。
(2) 代码的侵入性
即也作为业务组件,应当尽可能少入侵或者无入侵其他业务系统,对于使用方透明,减少开发人员的负担。
(3) 监控维度
分析的维度尽可能多。
(4) 可扩展性
一个优秀的调用跟踪系统必须支持分布式部署,具备良好的可扩展性。能够支持的组件越多当然越好。
主流系统:skywalking、pinpoint、zipkin
4 Pinpoint介绍
Pinpoint是一个APM(应用程序性能管理)工具,适用于用Java/PHP编写的中大型分布式系统。
特性:
(1) 服务器地图(ServerMap)
通过可视化分布式系统的模块和他们之间的相互联系来理解系统拓扑。点击某个节点会展示这个模块的详情,比如它当前的状态和请求数量。
(2) 实时活动线程图(Realtime Active Thread Chart)
实时监控应用内部的活动线程。
(3) 请求/响应分布图(Request/Response Scatter Chart)
长期可视化请求数量和应答模式来定位潜在问题。通过在图表上拉拽可以选择请求查看更多的详细信息。
(4) 调用栈(CallStack)
在分布式环境中为每个调用生成代码级别的可视图,在单个视图中定位瓶颈和失败点。
(5) 检查器(Inspector)
查看应用上的其他详细信息,比如CPU使用率,内存/垃圾回收,TPS,和JVM参数。
5.2 Pinpoint部署
在172.16.1.70节点上操作
1 环境准备
(1) 安装docker环境(省略步骤)
(2) 安装docker-compose
1) 下载二进制文件
# curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-Linux-x86_64 -o /usr/bin/docker-compose
2) 添加可执行权限
# chmod +x /usr/bin/docker-compose
2 部署
# git clone https://github.com/pinpoint-apm/pinpoint-docker.git
# cd pinpoint-docker
# docker-compose pull
# docker-compose up -d
# docker-compose ps
访问url地址:http://172.16.1.70:8079
5.3 Pinpoint Agent部署
1 下载pinpoint agent jar包
-javaagent:${pinpointPath}/pinpoint-bootstrap-1.8.5.jar
-Dpinpoint.applicationName=
-Dpinpoint.agentId=
https://github.com/pinpoint-apm/pinpoint/releases/download/1.8.5/pinpoint-agent-1.8.5.tar.gz
TomCat:
# catalina.sh
CATALINA_OPTS="$CATALINA_OPTS -javaagent:${pinpointPath}/pinpoint-bootstrap-1.8.5.jar"
CATALINA_OPTS="$CATALINA_OPTS -Dpinpoint.applicationName=portal"
CATALINA_OPTS="$CATALINA_OPTS -Dpinpoint.agentId=172.16.1.65"
2 部署
以portal服务为例,在172.16.1.65节点上操作
(1) 配置pinpoint agent连接pinpoint服务端
# mkdir -p /data/ms/portal/pinpoint-agent/
# cd /data/ms/portal/pinpoint-agent/
# tar -xzf pinpoint-bootstrap-1.8.5.jar
# vim pinpoint.config
profiler.collector.ip=172.16.1.70
(2) 将pinpoint agent加入到portal前端服务中
# vim /usr/lib/systemd/system/portal.service
[Unit]
Description=portal
Documentation=portal
[Service]
ExecStart=/usr/local/jdk/bin/java -jar -javaagent:/data/ms/portal/pinpoint-agent/pinpoint-bootstrap-1.8.5.jar -Dpinpoint.applicationName=portal -Dpinpoint.agentId=172.16.1.65 /data/ms/port
al/portal-service.jarExecReload=/bin/kill -HUP
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
(3) 重启portal服务
# systemctl daemon-reload
# systemctl restart portal.service
3 在浏览器中多次访问http://portal.ctnrs.com/,然后在pinpoint中查看调用关系图
5.4 重点关注的监控指标
1 堆内存
2 GCC
3 CPU使用率
4 堆栈跟踪
5 接口状态
6 吞吐量、相应时间
6 Java程序调用与故障排查工具
6.1 java常用工具
1 jps # 显示JVM进程状态
2 jstack # 打印Java进程的线程堆栈信息
3 jmap # 打印共享对象内存映射或堆内存详细信息
4 jstat # 监控JVM的统计数
6.2 程序调优参数
以portal服务为例
1 配置调优参数
# vim /usr/lib/systemd/system/portal.service
[Unit]
Description=portal
Documentation=portal
[Service]
ExecStart=/usr/local/jdk/bin/java -Xms512m -Xmx2g -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:/data/ms/portal/gc.log -jar /data/ms/portal/portal-
service.jarExecReload=/bin/kill -HUP
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
2 重启portal服务
# systemctl daemon-reload
# systemctl restart portal.service
3 查看堆栈信息
# jps -l
2066 sun.tools.jps.Jps
1960 /data/ms/portal/portal-service.jar
# jmap -heap 1960
6.3 故障排查
1 堆内存溢出
(1) 可能原因
1) 堆内存不足,设置容量较小
2) 代码Bug,对象不释放
(2) 堆内存内存溢出日志错误
老年代内存不足
java.lang.OutOfMemoryError:Javaheapspace
2 Java进程CPU利用率占用很高
(1) 可能原因
1) 频繁GC
2) 代码Bug
(2) 定位占用CPU高的代码
1) 查看占用资源最多的Java进程的PID
# top
2) 查看进程下占用CPU使用率最多的线程PID
# top -Hp 2268
3) 将线程PID转换为十六进制
# printf "%x\n" 2279
8e7
4) jstack获取进程堆栈信息,过滤出这个线程的
格式:jstack <进程PID> |grep <十六进制> -A 30
# jstack 2268 | grep 8e7 -A 30