Part0 遇到了故障怎么办?

在生产上,我们会遇到各种各样的故障,遇到了故障怎么办?

不要慌,只有冷静才是解决故障的利器。

下面以一个例子为例,在生产中碰到了CPU 100%的问题怎么办?

在生产中真的碰到了CPU 100%的问题,再来看这篇文章已经迟了,还是先来模拟演练下吧。
怎么模拟演练?

(1)查找资料,选型排查CPU高负载问题的工具。

(2)安装一个高负载程序或手写个高负载应用部署。

(3)安装、执行分析工具,实战分析,找出故障原因。

(4)思考与总结。

Part1 工具选型

因为现在大部分的企业应用都是java编写的,所以我们本次排查的高负载应用也是针对java的,但是思路其实是相同的,如果也有php、python、go等语言写的程序,无非就是换个工具而已,排查的步骤都是类似的。

而top这个命令一定是Linux上不可动摇的资源监控工具。

以下三类工具从原生的top、jstack到功能强大的Arthas和一键式查找的show-busy-java-threads,它们都各有长处。在合适的环境选择合适的工具才是考验一个IT人员能力的时候。

运用之道,存乎一心。

1.1 原生方法

此方法无需额外安装工具,在没法连接互联网的情况下使用此方法排查效果较好。

top、printf都是Linux原生命令,jstack、jstat是jdk自带命令工具。

很多功能强大的Linux和java诊断工具也是以top、jstack、jstat为基础命令做的封装。

注意:jstack、jstat等命令需要jdk完整安装,linux自带的openJdk一般无此工具,可以在java的bin目录下查看是否有这些命令。

oracle jdk 1.8下载地址:
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html。

1.2 阿里开源:Arthas(阿尔萨斯)

Arthas(阿尔萨斯)是 阿里巴巴开源出来的一个针对 java 的线上诊断工具,功能非常强大。

Arthas的githup官网https://github.com/alibaba/arthas。

Arthas 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

1.3 淘宝开源:show-busy-java-threads

show-busy-java-threads.sh,其作者是淘宝同学【李鼎(哲良) oldratlee】,这个工具是useful-scripts工具集的其中一个工具。

useful-scripts的github网址:https://github.com/oldratlee/useful-scripts。

show-busy-java-threads用于快速排查Java的CPU性能问题(top us值过高),自动查出运行的Java进程中消耗CPU多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。

注意:此工具的核心还是使用jdk的jstack方法,只是在其上做了封装展示。

Part2 高负载代码创建

查看CPU负载的工具选好了,现在我们需要弄个程序来让CPU达到高负载运行。

以java代码为示例,写一个死循环程序,基本就会导致CPU使用率百分百。

2.1 新建springboot项目

开始动手,新建springboot的maven项目,创建web服务,引入SpringBoot内置web容器,pom.xml关键引用jar包如下:

<!-- 引入容器类 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

2.2 创建service:TestWhile

创建service类TestWhile,编写死循环代码。

package com.yao.service;  import org.springframework.stereotype.Service; import java.util.concurrent.ConcurrentHashMap;  /** * @author 姚毛毛 * @version V1.0 * @Package com.yao.yaojiaxiaoyuan * @Description: 死循环demo * @date 2019/11/19--16:55 */ @Service public class TestWhile {      /* 操作内存对象 */     ConcurrentHashMap map = new ConcurrentHashMap();          /**     * 死循环,生产中千万不要这么写,while(true)时一定要有退出条件     * @param threadName 指定线程名     */     private void whileTrue(String threadName) {     // 不设置退出条件,死循环     while (true) {          // 在死循环中不断的对map执行put操作,导致内存gc     for( int i = 0; i <= 100000; i ++) {     map.put(Thread.currentThread().getName() + i, i);     } // end for          }// end while }      /**     * 循环size,新建线程,调用whileTrue     * @param size 线程数     */     public void testWhile(int size) {          // 循环size,创建多线程,并发执行死循环         for (int i = 0; i < size; i++) {                      int finalI = i;                          // 新建并启动线程,调用whileTrue方法             new Thread(() -> {                 whileTrue("姚毛毛-" + finalI);              }).start();               }// end for     }//  end testWhile      }

2.3 创建Controller:TestWhile

创建rest服务,编写get方法testWhile,调用死循环服务testWhile。

package com.yao.controller;  import com.yao.service.TestWhile; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping;