在微服务场景中,多个微服务关系错综复杂,一旦报错就难以查找,下面我将以项目中的某个报错为例,来逐步定位微服务中的报错位置。
1. 方案一:本地调试
该方法使用于绝大多数微服务的场景,也是项目中最好用的一个方案。
1.1 查看后端报错信息
后端微服务报错:
1.2 在前端定位报错接口,查看url路径
通过查找,该异常来自于 http://api.tianji.com/ts/orders/1589930049848053761 网址,请求方式为Delete ,该网址为默认端口 80。
1.3 定位占 80 端口的服务
通过下面这条命令,定位Linux系统中占 80 端口的进程
netstat -nap | grep 80
通过查找,占 80 端口的为 docker-proxy ,即 docker 容器占了 80 端口
1.4 查看docker中运行的容器
通过下面这条命令,定位Linux系统中正在运行的容器
docker ps
通过查找,占 80 端口的为 nginx
1.5 查找nginx的配置文件位置
将目录切到 docker-compose.yml 文件所在的目录下(该目录并非每个人统一,故根据实际情况而定),我存放在 /usr/local/src 目录下
cd /usr/local/src
浏览 docker-compose.yml 文件,查找 nginx 数据卷挂载的位置
more docker-compose.yml
通过查找,配置文件挂载到 ./nginx/conf/nginx.conf
1.6 定位 api.tianji.com 反向代理到哪个端口
more ./nginx/conf/nginx.conf
通过查找,api.tianji.com 反向代理到 http://192.168.150.101:10010 。
到现在,浏览器的接口网址 http://api.tianji.com/ts/orders/1589930049848053761 可替换为 http://192.168.150.101:10010/ts/orders/1589930049848053761
1.7 查找 10010 端口的微服务
通过配置文件等方式定位,10010 端口为网关 getway 的微服务。
1.8 查看网关 getway 配置文件
该配置文件将/ts 截取掉,192.168.150.101:10010 转到 trade-service 服务名中。
目前为止由最初浏览器网址 http://api.tianji.com/ts/orders/1589930049848053761 可替换为 http://trade-service/orders/1589930049848053761
1.9 定位服务名为 trade-service 的微服务,在 web 层找到接口
找到服务名为 trade-service 的微服务后,根据现有信息可知,该接口为 /orders/{某个id},方法为Delete方法,最终定位该接口
1.10 在该接口打断点测试,定位错误并修改
2. 方案二:远程调试
注意事项:
1. 生产场景禁止使用;
2. 需要停止Linux端和本地要debug的微服务;
3. 本地代码要和远端代码要一致。
2.1 对本地启动项做一些配置
2.2 然后添加一个新的启动项:
2.3 在新建的Configuration中填写信息
2.4 在jenkins新建一个debug的模块,在原模块基础上新增以下命令开启测试,启动debug模块
2.5 此时,就可以在启动项中看到我们配置的远程调试项目了
在 jenkins 如何写 debug 模式的 shell 脚本:
1. 将原shell 脚本拷贝;
2. 设置 debug 的端口号,该端口号和本地配置的端口号对应;
3. docker run 命令中新增以下参数:
-e JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
例:
原 shell 脚本:
pipeline { agent any environment { S_NAME = 'tj-trade' S_PORT = '8088' } stages { stage('Build') { steps { sh "cp ../tjxt-dev-build/${S_NAME}/target/${S_NAME}.jar ./app.jar" sh "cp ../tjxt-dev-build/Dockerfile ./Dockerfile" sh '[ -n "`docker ps -a | grep ${S_NAME}`" ] && docker rm -f ${S_NAME} || echo 1' sh '[ -n "`docker images | grep ${S_NAME}`" ] && docker rmi ${S_NAME} || echo 1' sh 'docker build -t ${S_NAME} --build-arg JAVA_OPTS="-Xms128m -Xmx128m" .' } } stage('deploy') { steps { sh 'docker run --name ${S_NAME} -e JAVA_OPTS="-Xms256m -Xmx256m" --memory 256m --memory-swap -1 --network tjxt -p ${S_PORT}:${S_PORT} -d ${S_NAME}' } } } }
bedug 模式的 shell 脚本:
pipeline { agent any environment { S_NAME = 'tj-trade' S_PORT = '8088' S_DEBUG_PORT = '5005' } stages { stage('Build') { steps { sh "cp ../tjxt-dev-build/${S_NAME}/target/${S_NAME}.jar ./app.jar" sh "cp ../tjxt-dev-build/Dockerfile ./Dockerfile" sh '[ -n "`docker ps -a | grep ${S_NAME}`" ] && docker rm -f ${S_NAME} || echo 1' sh '[ -n "`docker images | grep ${S_NAME}`" ] && docker rmi ${S_NAME} || echo 1' sh 'docker build -t ${S_NAME} --build-arg JAVA_OPTS="-Xms300m -Xmx300m" .' } } stage('deploy') { steps { sh 'docker run --name ${S_NAME} -e JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" --network tjxt -p ${S_DEBUG_PORT}:5005 -p ${S_PORT}:${S_PORT} -d ${S_NAME}' } } } }