Docker-maven-plugin + Dockerfile + Arthas实现应用诊断
一、前言
我们的微服务响应生产环境出现一个功能响应时间过慢,对Prometheus监控 Http Request进行分析发下该功能调用的后端接口响应时间平均在30秒以上,分析源码接口有mysql查询、MongoDB查询操作,对慢sql进行分析首先排除了慢sql问题,但是MongoDB作为高性能数据库几乎不会查询缓慢问题,由于没有一个即时的分析工具,无法判断程序在那块耗时较长,只有采取笨办法,在程序各个关键节点输出时间戳日志,最终排查到是MongoDB问题,线上MongoDB因为某种原因导致查询商品的数据到达百万级,而程序开发者在设计时未考虑到大数据情况,因为未设置索引。
1.1 为什么选择Arthas
Arthas是Alibaba开源Java应用诊断工具,具有
- 活跃成熟的社区,文档齐全
- arthas的定位是诊断问题排查,不会长时间attach在进程上,也不会作用在集群,不需要太多考虑对性能的开销
- 支持Docker镜像
- Dashboard实时查看系统的运行状况
- 查看入参/返回值/异常
- 性能热点
- 类冲突
- WebConsole
等特点和特性。更多细节参考 中文官网
二、使用Arthas
Arthas支持单独部署安装arthas-boot.jar和将Arthas安装到基础镜像里两种方式,我们的微服务是基于Dokcer镜像进行发布,因此我们选择将把Arthas安装到基础镜像里:
2.1 使用docker-maven-plugin + Dockerfile构建镜像
# 在pom.xml增加docker-maven-plugin配置
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<imageName>${project.artifactId}:${project.version}</imageName>
# dockerDirectory 参数表示使用Dockerfile构建镜像,${basedir}表示Dockerfile与pom.xml同级目录
<dockerDirectory>${basedir}</dockerDirectory>
<dockerHost>http://192.168.128.xxxx:2375</dockerHost>
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<forceTags>true</forceTags>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
2.2 修改Dockerfile 添加安装arthas代码
FROM java:8
ADD /app.jar //
# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev","/app.jar"]
注意Docker构建应该使用完整的JDK基础包,否则会出现Docker应用中arthas无法正常运行的问题,因为Arthas依赖JAVA的命令行工具和类库
2.3 使用公开的JDK基础镜像
FROM openjdk:8-jdk
FROM openjdk:8-jdk-alpine
FROM java:8
三 诊断工具使用案例
3.1 在线实时分析接口响应缓慢问题
生产环境出现接口响应缓慢,常想到分析手段是通过日志埋点来分析接口在那块处理耗费时间长,而通过集成arthas,使用trace命令可以渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
3.1.1 启动Docker 镜像进程中arthas
docker exec -it c86629fdc6cb /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
启动结果:
[root@localhost ~]# docker exec -it c86629fdc6cb /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
--2020-11-25 15:17:33-- https://arthas.aliyun.com/arthas-boot.jar
Resolving arthas.aliyun.com (arthas.aliyun.com)... 203.119.214.116
Connecting to arthas.aliyun.com (arthas.aliyun.com)|203.119.214.116|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 138711 (135K) [application/java-archive]
Saving to: ‘arthas-boot.jar’
arthas-boot.jar 100%[========================================================================================>] 135.46K 245KB/s in 0.6s
2020-11-25 15:17:34 (245 KB/s) - ‘arthas-boot.jar’ saved [138711/138711]
[INFO] arthas-boot version: 3.4.4
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 1 /app.jar
3.1.2 使用trace命令 侦听方法
trace com.myyshop.saas.dsuserserver.controller.TdDsShopController createShop
访问接口,查看侦听结果
`---ts=2020-11-25 07:32:47;thread_name=http-nio-7004-exec-5;id=4c;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@4ba534b0
`---[650.100619ms] com.myyshop.saas.dsuserserver.service.impl.TdDsShopServiceImpl$$EnhancerBySpringCGLIB$$3e545494:createShop()
`---[650.007439ms] org.springframework.cglib.proxy.MethodInterceptor:intercept()
`---[646.06381ms] com.myyshop.saas.dsuserserver.service.impl.TdDsShopServiceImpl:createShop()
+---[0.018917ms] com.myyshop.saas.dsuserserver.utils.LoginUtils:chkLogin() #110
+---[0.006053ms] com.dhgate.saas.common.core.model.LoginAppUser:getUserId() #111
+---[0.015575ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:<init>() #114
+---[0.027124ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:eq() #114
+---[5.757169ms] com.myyshop.saas.dsuserserver.mapper.TdDsShopMapper:selectCount() #114
+---[0.019784ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #121
+---[0.016377ms] com.dhgate.saas.common.core.utils.StringUtils:lowerCase() #121
+---[0.008651ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:setDomain() #121
+---[0.005473ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #124
+---[1.166932ms] com.myyshop.saas.dsuserserver.utils.DomainUtils:chkIsSensitiveWord() #124
+---[0.008751ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #131
+---[3.751548ms] com.myyshop.saas.dsuserserver.utils.DomainUtils:isRegisterDomains() #131
+---[0.008372ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #138
+---[0.012716ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getShopName() #138
+---[3.482077ms] com.myyshop.saas.dsuserserver.mapper.TdDsShopMapper:getcount() #138
+---[0.064746ms] com.myyshop.saas.dsuserserver.model.TdDsShop:<init>() #145
+---[0.007541ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #146
+---[0.012804ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setDomain() #146
+---[0.009306ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getShopName() #148
+---[0.00715ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #148
+---[0.009197ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setShopName() #148
+---[0.007298ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setUserId() #149
+---[0.011004ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setTemplateId() #150
+---[0.007945ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setCreatedAt() #151
+---[0.007562ms] com.myyshop.saas.dsuserserver.model.TdDsShop:setUpdatedAt() #152
+---[4.256693ms] com.myyshop.saas.dsuserserver.mapper.TdDsShopMapper:insert() #153
+---[0.01248ms] com.myyshop.saas.dsuserserver.model.TdDsShop:getShopId() #155
+---[0.018589ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:<init>() #160
+---[0.009691ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getCurrency() #162
+---[0.009491ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:currency() #162
+---[0.007937ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getLanguage() #163
+---[0.008896ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:language() #163
+---[0.007881ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getRefundPolicyUrl() #164
+---[0.009011ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:refundPolicyUrl() #164
+---[0.008243ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getPrivacyPolicyUrl() #165
+---[0.008377ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:privacyPolicyUrl() #165
+---[0.007477ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getShippingTermsUrl() #166
+---[0.013257ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:shippingTermsUrl() #166
+---[0.025617ms] com.myyshop.saas.dsuserserver.model.TdDsShopSetting$Builder:build() #167
+---[10.906103ms] com.myyshop.saas.dsuserserver.service.TdDsShopSettingService:save() #169
+---[609.588604ms] com.myyshop.saas.dsuserserver.feign.MyyshopOrderClient:fistTimeCreateShop() #173
+---[0.024436ms] com.myyshop.saas.dsuserserver.model.dto.TdDsShopParam:getDomain() #179
+---[5.150318ms] com.myyshop.saas.dsuserserver.utils.DomainUtils:setRegisterDomains() #179
+---[0.154152ms] com.dhgate.saas.common.core.utils.CopyUtils:copyObject() #181
+---[0.013183ms] com.myyshop.saas.dsuserserver.model.vo.DsShopVo:setShopId() #182
`---[0.02153ms] com.dhgate.saas.common.core.model.Result:succeed() #184
通过调用链分析,可以看出接口处理大量时间花费到一个feign调用上,可以考虑对该接口进行优化。
Docker-maven-plugin + Dockerfile + Arthas实现应用诊断的更多相关文章
- 实战docker,编写Dockerfile定制tomcat8镜像,实现web应用在线部署
最初在tomcat上部署web应用的方式,是通过maven的maven-compiler-plugin插件先打成war包,再将war包复制到tomcat的webapps目录下,后来用上了tomcat7 ...
- 使用Docker Maven 插件进行镜像的创建以及上传至私服
1.在进行服务容器化部署的时候,需要将服务以及其运行的环境整个打包做成一个镜像,打包的过程有两种办法,第一种是首选通过maven打成jar包,然后再编写dockerfile,执行docker buil ...
- 如何在Docker容器中使用Arthas
Arthas(阿尔萨斯) 能为你做什么? Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱. 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar ...
- 学习Maven之Cobertura Maven Plugin
cobertura-maven-plugin是个什么鬼? cobertura-maven-plugin是一个校验单元测试用例覆盖率的工具,可以生成一个测试覆盖率报告,可以给单元测试用例编写提供参考. ...
- Maven实现Web应用集成測试自己主动化 -- 部署自己主动化(WebTest Maven Plugin)
上篇:Maven实现Web应用集成測试自己主动化 -- 測试自己主动化(WebTest Maven Plugin) 之前介绍了怎样在maven中使用webtest插件实现web的集成測试,这里有个遗留 ...
- 解决Jetty Maven Plugin:Please initialize the log4j system properly(转)
解决Jetty Maven Plugin:Please initialize the log4j system properly.Jetty Maven Plugin环境: <plugin> ...
- Spring Boot Maven Plugin(二):run目标
简介 Spring Boot Maven Plugin插件提供spring boot在maven中的支持.允许你打包可运行的jar包或war包. 插件提供了几个maven目标和Spring Boot ...
- Spring Boot Maven Plugin(一):repackage目标
简介 Spring Boot Maven Plugin插件提供spring boot在maven中的支持.允许你打包可运行的jar包或war包. 插件提供了几个maven目标和Spring Boot ...
- Docker(二):Dockerfile 使用介绍
上一篇文章Docker(一):Docker入门教程介绍了 Docker 基本概念,其中镜像.容器和 Dockerfile .我们使用 Dockerfile 定义镜像,依赖镜像来运行容器,因此 Dock ...
随机推荐
- app反编译遇到360加固,傻瓜式脱壳
转载https://blog.kieng.cn/2051.html 第一步 电脑安装安卓模拟器,我使用的是雷电模拟器(推荐). 第二步 打开模拟器,准备安装软件: 1.需要脱壳的软件 2.XP 框架. ...
- Vue(学习第三部 自动化工具 [vue-cli])
目录 Vue自动化工具(Vue-cli) 安装nide.js npm 安装Vue-sli 使用Vue-处理初始化创建起那段项目 vue项目执行流程图 单文件组件的使用 template 编写HTML代 ...
- Distcp 跨集群同步
date: 2020-10-09 17:45:00 updated: 2020-10-10 17:45:00 Distcp 跨集群同步 1. 使用方法及原理 hadoop distcp srcPath ...
- pc和移动与ipad自适应布局的相关问题和解决
一.通过CSS检测本机设备屏幕大小分配样式 1.最小尺寸分辨率1024*768(传统17寸显示器),则可以采用940px.960px.或者常用的980px作为最小宽度. ---- 在可视区域的宽度小于 ...
- Setuptools 【Python工具包详解】
什么是setuptools setuptools是Python distutils增强版的集合,它可以帮助我们更简单的创建和分发Python包,尤其是拥有依赖关系的.用户在使用setuptools创建 ...
- 12 Servlet_04 Servlet增删改查 静态页面与动态页面 EL表达式 table表格的一些样式
今天学习了servlet的增删改查: 存储数据 setAttribute(String name,Object obj );获取数据 getAttribute(String name);删除数据 re ...
- Java中final修饰的方法是否可以被重写
这是一次阿里面试里被问到的题目,在我的印象中,final修饰的方法是不能被子类重写的.如果在子类中重写final修饰的方法,在编译阶段就会提示Error.但是回答的时候还是有点心虚的,因为final变 ...
- [Luogu P3203] [HNOI2010]弹飞绵羊 (LCT维护链的长度)
题面 传送门:洛谷 Solution 这题其实是有类似模型的. 我们先考虑不修改怎么写.考虑这样做:每个点向它跳到的点连一条边,最后肯定会连成一颗以n+1为根的树(我们拿n+1代表被弹出去了).题目所 ...
- python开发基础(二)运算符以及数据类型之float(浮点类型)
# encoding: utf-8 # module builtins # from (built-in) # by generator 1.147 """ Built- ...
- Java_基础(一)
注释 单行注释: // 多行注释: /*开头, */结尾, 可跨行, 可嵌入 public static void main(String[] args/* 哈哈 */) 文档注释: /** 开头, ...