千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:重庆千锋IT培训  >  技术干货  >  线上问题的解决与思路——如何对自己遇到的故障进行定位与解决?

线上问题的解决与思路——如何对自己遇到的故障进行定位与解决?

来源:千锋教育
发布人:lxl
时间: 2023-05-25 10:09:46

  一. 问题复现

  今天我会结合自己的授信中心这个金融项目,继续给大家分析如何对自己遇到的故障进行定位与解决,希望本文可以对缺乏实际开发经验的小白有所帮助。

  其实要想解决开发故障,通常的解决思路大致如下:

  分析问题,根据理论知识+经验分析问题所在,并将错误锁定在一定的范围内;

  通过错误日志,快速定位问题。线上定位问题时,主要是依靠监控和日志。

  比如百泽老师遇到过这样一个问题:

  线上的金融项目启动后,运行速度越来越慢,一段时间后直接无法访问,但此时的内存使用率正常,而CPU使用率几乎满负荷。在重启项目后,又运行了一段时间,项目重复出现该问题。

  二. 解决思路

  对于这种线上的故障,我们该怎么解决呢?其解决思路可以按照以下几个步骤来实现。

  其实,大多数情况下,只要出问题,我们都可以利用 df(查看磁盘)、free(查看内存)、top(查看CPU) 来个素质三连,然后再通过jstack(Java堆栈跟踪工具)、jmap(Java堆和方法区的详细信息)等工具排查。这些工具的具体使用命令,大家可以自行查阅。

  top命令

  top命令或者其他监控数据,用于查看服务器的内存、cpu的使用情况。

  jps命令

  查看当前java程序的进程号,假如为:17357,

  jstat命令

  jstat -gc 17357 2000,可以查看jvm的内存分配情况,如图:

如何对自己遇到的故障进行定位与解决

  接着我们再通过查看EU和OU、YGC、FGC的变化,来调整jvm的内存、young区(edge,s1,s2)、old区内存大小。

  可靠建议:

  修改JAVA_OPTS='-Xms1024m -Xmx1024m' ,将jvm的最大、最小内存设为系统内存的3/4。根据ygc,调整young区中s与edge比例,根据fgc的频率调整young区和old区的大小(或比例)。

  然后通过jstack 进程id,来查看线程的死锁,例如: jstack -l 21733 | more,若出现下图所示,则是出现了线程死锁。

如何对自己遇到的故障进行定位与解决

  tomcat优化

  我们也可以在yml文件中tomcat的配置进行优化。

  server:

  port: 9105

  tomcat:

  threads:

  处理请求的最大线程数

  max: 350

  最小的工作线程数

  min-spare: 100

  等待队列的最大队列长度

  accept-count: 500

  设置数据库连接池

  对于数据库服务(如mysql),dba在部署的时候,都会设置db的最大内存和最大链接数,开发人员可以暂时忽略。

  另外,数据库连接池请尽量别用dbch、c3p0等已经过时的连接池技术,推荐使用阿里巴巴的druid,其相关的链接配置,请参照其github的官网。

  三. 具体解决过程

  结合以上解决思路,接下来百泽给大家说一下我的具体解决过程。

  top定位

  由于cpu满负荷,所以我先通过top定位到出现问题的线程。发现确实是我们的java项目所在进程吃掉了所有的cpu资源,这时可通过jps+jstat来查看java的gc状态,进一步发现young gc几乎是一秒一次,fullgc没有。所以接着我又查看了jvm的设置,young内存才设为512m,我先去掉了这个配置,而是采用默认配置(young:old =1:2)。

  在重启项目之后,young gc基本到了10多秒一次,可项目运行一段时间还是会卡死。然后我又看了下tomcat的连接池,发现全部都是默认配置(默认最大连接数为50),故先将最大链接设为500,等待队列设为1000,重启项目,还是出现cpu满负荷,系统卡死。

  排查数据库服务的内存

  接着我查看了输出的最新日志文件,发现日志输出到一个dao方法之后,在输出响应的sql后就卡住了。接着我通过mysql链接工具直接执行,sql却很快输出,因此排除数据库服务的内存不足等硬件问题。

  调整日志输出级别

  通过查看项目的框架,发现日志用的log4j(同步日志输出),日志输出级别是:INFO,这会导致项目里面的log输出非常多,所以我先将log的输出级别设为warn,重新启动项目,项目正常运行。

  优化数据表

  修改日志输出级别为warn之后,运行了一段时间发现系统又卡死了。这时还是两个表的查询卡死(通讯录和通话记录),这两个表的存储量级都是上亿级别的,项目原有的逻辑是这样的,用户上传通讯录,需要删除原来的通讯录,再批量插入。这样一个大表频繁的进行删除与批量插入,很容易导致IO响应慢。第一步,我先通过建立唯一索引,利用insert ignore into来减少该表的IO操作,接着重新启动项目,系统正常运行。

  添加索引

  加好索引优化了sql语句之后,系统还是偶尔会出现卡死状态。这时,我通过dba搜索慢查询,发现通话记录和通讯录表中有一个排序查询,该sql的末尾使用了order by update_time desc,但update_time没有添加索引,这就导致该表的查询至少要2秒以上。所以我将sql改为了order by id,查询就正常了,重启项目,系统正常运行。

  解决线程死锁

  至此,系统还是偶尔出现卡死现象(cpu爆表),只是频率小了很多。这时我怀疑是有线程死锁了,从而导致cpu爆表。我通过运维查找linux线程,终于发现确实有一个线程出现了死锁,里面的信息显示是c3p0的连接池线程。我又通过查找资料,发现使用c3p0作为数据库连接池,经常会出现链接池卡死的问题,所以我赶紧将项目的连接池切换为durid,然后重启项目,项目运行正常。

  新增服务器节点

  但系统在进件量较大时,依然有一定的几率出现卡死现象,最好考虑是当时的项目环境采用的是单机部署,所以最后协调运维新增了两个服务器节点,至此项目运行完全正常。

  四. 总结

  针对线上服务器故障的解决思路和过程,百泽老师给大家提供了以下几个可靠建议:

  系统框架太过于老旧时,可能会引发一系列的项目问题,所以适当升级项目的技术是有必要的。

  一些大表一定要进行拆分,否则在高并发的环境中,数据库的IO会遇到瓶颈。

  减少一些不必要的日志输出,日志输出组件尽量是异步输出的。

  一些高频率查询的字段,尽量加上索引、组合索引,一些慢查询的sql优化也很重要。

  服务尽量单独部署。

  对于线上服务器的问题解决和优化思路,现在你掌握了吗?

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

如何进行mysql数据备份?

2023-05-30

从零开始学Java之Java中的内部类是怎么回事?

2023-05-29

什么是事件流以及事件流的传播机制 ?

2023-05-29

最新文章NEW

什么是servlet的生命周期?servlet请求处理流程是怎样的?

2023-05-30

在java中,super关键字怎样使用

2023-05-29

什么是JavaScript伪数组?

2023-05-25

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>