Java 线上问题排查与持续优化实战指南

一、基础知识

(一)Java 线上问题分类

在 Java 应用程序的线上环境中,问题多种多样,但通常可以归纳为以下几类:

  1. 性能问题
    • 响应时间过长
      • 问题表现:用户操作后,系统响应缓慢,用户体验差。
      • 可能原因:代码逻辑复杂、数据库查询效率低下、网络延迟等。
      • 示例代码
        public List<User> getAllUsers() {
            List<User> users = new ArrayList<>();
            for (int i = 0; i < 1000000; i++) {
                User user = new User();
                user.setId(i);
                user.setName("User" + i);
                users.add(user);
            }
            return users;
        }
        
        上述代码中,getAllUsers 方法在循环中创建了大量对象,导致响应时间过长。
    • 吞吐量不足
      • 问题表现:系统无法在高并发场景下处理大量请求。
      • 可能原因:线程池配置不合理、资源瓶颈(如 CPU、内存、磁盘 I/O)或架构设计缺陷。
      • 示例代码
        public class FixedThreadPoolExample {
            public static void main(String[] args) {
                ExecutorService executor = Executors.newFixedThreadPool(10);
                for (int i = 0; i < 1000; i++) {
                    executor.submit(() -> {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    });
                }
                executor.shutdown();
            }
        }
        
        上述代码中,线程池大小固定为 10,当任务数量过多时,会导致吞吐量不足。
    • 资源利用率过高
      • 问题表现:CPU、内存、磁盘或网络资源使用率过高,可能导致系统性能下降甚至崩溃。
      • 可能原因:程序存在大量计算密集型或 I/O 密集型操作。
      • 示例代码
        public class CPUIntensiveTask {
            public static void main(String[] args) {
                while (true) {
                    // 模拟 CPU 密集型任务
                    for (int i = 0; i < 1000000000; i++) {
                        Math.sin(i);
                    }
                }
            }
        }
        
        上述代码中,CPUIntensiveTask 类中的 main 方法会持续占用 CPU 资源,导致 CPU 使用率过高。
  2. 异常问题
    • 运行时异常
      • 问题表现:程序运行过程中抛出异常,导致程序中断或行为异常。
      • 可能原因:代码逻辑错误或数据质量问题。
      • 示例代码
        public class NullPointerExample {
            public static void main(String[] args) {
                String str = null;
                System.out.println(str.length());
            }
        }
        
        上述代码中,strnull,调用 str.length() 时会抛出 NullPointerException
    • 业务逻辑异常
      • 问题表现:用户输入不符合预期或业务规则冲突,导致程序行为异常。
      • 可能原因:业务逻辑设计不合理或用户输入未进行严格校验。
      • 示例代码
        public class BusinessLogicExample {
            public static void main(String[] args) {
                int age = -1;
                if (age < 0) {
                    throw new IllegalArgumentException("年龄不能为负数");
                }
            }
        }
        
        上述代码中,age 为负数,不符合业务逻辑,抛出 IllegalArgumentException
    • 系统级异常
      • 问题表现:程序运行过程中抛出系统级异常,导致程序崩溃。
      • 可能原因:JVM 配置不合理或代码存在严重问题。
      • 示例代码
        public class OutOfMemoryExample {
            public static void main(String[] args) {
                List<Object> list = new ArrayList<>();
                while (true) {
                    list.add(new Object());
                }
            }
        }
        
        上述代码中,程序不断创建对象并添加到 list 中,最终导致 OutOfMemoryError
  3. 资源泄漏问题
    • 内存泄漏
      • 问题表现:程序运行过程中内存占用不断增加,最终可能引发 OutOfMemoryError
      • 可能原因:程序中存在未正确释放的内存对象。
      • 示例代码
        public class MemoryLeakExample {
            private static List<Object> list = new ArrayList<>();
            public static void main(String[] args) {
                while (true) {
                    list.add(new Object());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        上述代码中,list 不断添加对象,但从未释放,导致内存泄漏。
    • 文件句柄泄漏
      • 问题表现:程序运行过程中不断打开文件句柄,但未正确关闭,最终导致 Too many open files 错误。
      • 可能原因:程序中未正确关闭文件句柄。
      • 示例代码
        public class FileHandleLeakExample {
            public static void main(String[] args) {
                while (true) {
                    try (FileInputStream fis = new FileInputStream("example.txt")) {
                        fis.read();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        上述代码中,虽然使用了 try-with-resources 语句来自动关闭文件句柄,但如果文件不存在或其他异常发生,可能会导致文件句柄泄漏。
    • 数据库连接泄漏
      • 问题表现:程序运行过程中不断获取数据库连接,但未正确关闭,最终导致数据库连接池耗尽。
      • 可能原因:程序中未正确关闭数据库连接。
      • 示例代码
        public class DatabaseConnectionLeakExample {
            public static void main(String[] args) {
                while (true) {
                    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/example", "root", "password");
                    try {
                        Statement stmt = conn.createStatement();
                        ResultSet rs = stmt.executeQuery("SELECT * FROM users");
                        while (rs.next()) {
                            System.out.println(rs.getString("name"));
                        }
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        上述代码中,未正确关闭数据库连接 conn,导致数据库连接泄漏。

(二)监控与日志的重要性

监控与日志是 Java 线上问题排查的基石,它们提供了问题排查所需的线索和数据支持。

  1. 监控的作用
    • 实时性能监控
      • 工具:Prometheus、Grafana 等。
      • 示例
        • Prometheus 配置
          global:
            scrape_interval: 15s
          scrape_configs:
            - job_name: 'java_app'
              static_configs:
                - targets: ['localhost:8080']
          
        • Grafana 配置:在 Grafana 中创建数据源并导入 Prometheus 数据,创建仪表盘以实时监控 CPU、内存等指标。
    • 应用性能监控
      • 工具:Apache Skywalking、Pinpoint 等。
      • 示例
        • Skywalking 配置
          agent:
            collector:
              backend_service: "127.0.0.1:11800"
          
        • Pinpoint 配置
          pinpoint.agentId=java_app
          pinpoint.applicationName=java_app
          pinpoint.profiler.transport=GRPC
          pinpoint.collector.ip=127.0.0.1
          pinpoint.collector.port=9999
          
    • 告警与通知
      • 工具:Prometheus Alertmanager、Grafana Alerting 等。
      • 示例
        • Prometheus Alertmanager 配置
          global:
            resolve_timeout: 5m
          route:
            receiver: 'webhook'
          receivers:
            - name: 'webhook'
              webhook_configs:
                - url: 'http://localhost:9093/webhook'
          
        • Grafana Alerting 配置:在 Grafana 中创建告警规则,当 CPU 使用率超过 80% 时触发告警。
  2. 日志的作用
    • 记录问题线索
      • 工具:Log4j、SLF4J 等。
      • 示例
        • Log4j 配置
          <Configuration status="WARN">
            <Appenders>
              <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
              </Console>
            </Appenders>
            <Loggers>
              <Root level="debug">
                <AppenderRef ref="Console"/>
              </Root>
            </Loggers>
          </Configuration>
          
        • 日志记录
          private static final Logger logger = LogManager.getLogger(Example.class);
          public static void main(String[] args) {
              logger.info("Application started");
              try {
                  int result = 10 / 0;
              } catch (ArithmeticException e) {
                  logger.error("ArithmeticException occurred", e);
              }
          }
          
    • 定位问题根源
      • 工具:ELK 堆栈(Elasticsearch、Logstash、Kibana)。
      • 示例
        • Logstash 配置
          input {
            file {
              path => "/var/log/app.log"
              start_position => "beginning"
            }
          }
          output {
            elasticsearch {
              hosts => ["localhost:9200"]
              index => "app-logs"
            }
          }
          
        • Kibana 查询:在 Kibana 中使用查询语句 error 查找错误日志。
    • 分析问题趋势
      • 工具:Grafana Loki。
      • 示例
        • Loki 配置
          config:
            compactor:
              working_directory: /data/loki/boltdb-shipper-active
              shared_store: aws
              compaction_interval: 1h
              retention_enabled: true
              retention_delete_delay: 2h
              retention_delete_worker_count: 150
          
        • Grafana 查询:在 Grafana 中创建日志面板,分析日志趋势。

二、问题定位方法

(一)业务日志分析

业务日志是 Java 应用程序运行过程中记录的与业务逻辑相关的日志信息,通过分析业务日志,可以快速找到问题的具体位置和原因。

  1. 日志收集与存储
    • 日志收集工具:Logstash、Fluentd。
    • 示例
      • Logstash 配置
        input {
          file {
            path => "/var/log/app.log"
            start_position => "beginning"
          }
        }
        output {
          elasticsearch {
            hosts => ["localhost:9200"]
            index => "app-logs"
          }
        }
        
      • Fluentd 配置
        <source>
          @type tail
          path /var/log/app.log
          pos_file /var/log/app.log.pos
          tag app.log
        </source>
        <match app.log>
          @type elasticsearch
          host localhost
          port 9200
          logstash_format true
        </match>
        
  2. 日志分析工具
    • ELK 堆栈:Elasticsearch、Logstash、Kibana。
    • 示例
      • Kibana 查询:在 Kibana 中使用查询语句 error 查找错误日志。
      • Kibana 可视化:创建柱状图或折线图,分析错误日志的频率和趋势。
    • Splunk
      • 示例
        • 数据索引:将日志数据索引到 Splunk 中。
        • 查询语句:使用 Splunk 的查询语句 index=app error 查找错误日志。
    • 开源日志分析工具:Graylog、Loggly。
    • 示例
      • Graylog 配置
        input {
          file {
            path => "/var/log/app.log"
            start_position => "beginning"
          }
        }
        output {
          graylog {
            host => "localhost"
            port => 12201
          }
        }
        
  3. 日志分析方法
    • 关键字搜索
      • 示例
        • Elasticsearch 查询
          GET /app-logs/_search
          {
            "query": {
              "match": {
                "message": "error"
              }
            }
          }
          
    • 日志关联分析
      • 示例
        • Elasticsearch 查询
          GET /app-logs/_search
          {
            "query": {
              "bool": {
                "must": [
                  { "match": { "message": "error" }},
                  { "match": { "user_id": "12345" }}
                ]
              }
            }
          }
          
    • 日志统计分析
      • 示例
        • Elasticsearch 聚合查询
          GET /app-logs/_search
          {
            "size": 0,
            "aggs": {
              "error_count": {
                "terms": {
                  "field": "error_level.keyword"
                }
              }
            }
          }
          

(二)APM 分析

APM(Application Performance Management)工具通过监控应用程序的性能指标和调用链路,帮助快速定位分布式架构中的问题。

  1. APM 工具的选择
    • 开源 APM 工具:Apache Skywalking、Pinpoint。
    • 示例
      • Skywalking 配置
        agent:
          collector:
            backend_service: "127.0.0.1:11800"
        
      • Pinpoint 配置
        pinpoint.agentId=java_app
        pinpoint.applicationName=java_app
        pinpoint.profiler.transport=GRPC
        pinpoint.collector.ip=127.0.0.1
        pinpoint.collector.port=9999
        
  2. APM 工具的使用
    • 性能指标监控
      • 示例
        • Skywalking Dashboard:在 Skywalking 的 Dashboard 中查看服务的响应时间、吞吐量、错误率等性能指标。
        • Pinpoint Dashboard:在 Pinpoint 的 Dashboard 中查看服务的性能指标和调用链路。
    • 链路追踪
      • 示例
        • Skywalking 链路追踪:在 Skywalking 的 Dashboard 中查看某个请求的调用链路,分析每个服务的响应时间和调用顺序。
        • Pinpoint 链路追踪:在 Pinpoint 的 Dashboard 中查看某个请求的调用链路,分析每个服务的响应时间和调用顺序。
    • 分布式追踪
      • 示例
        • Skywalking 分布式追踪:在 Skywalking 的 Dashboard 中查看跨服务的分布式调用链路,分析服务之间的调用关系和性能瓶颈。
        • Pinpoint 分布式追踪:在 Pinpoint 的 Dashboard 中查看跨服务的分布式调用链路,分析服务之间的调用关系和性能瓶颈。

(三)外部环境排查

外部环境问题可能导致 Java 应用程序运行异常,因此需要对系统环境进行排查。

  1. CPU 分析
    • 工具使用tophtop
    • 示例
      • 命令
        top
        
        top 命令的输出中,查看 CPU 使用率较高的进程。
      • 线程分析
        jstack -l <pid> > thread_dump.txt
        
        使用 jstack 获取线程栈信息,分析是否存在死循环或热点代码。
  2. 内存分析
    • 工具使用free -mvmstat
    • 示例
      • 命令
        free -m
        
        查看系统的内存使用情况。
      • JVM 内存分析
        jmap -heap <pid>
        
        查看 JVM 的堆内存使用情况。
  3. 磁盘分析
    • 工具使用df -hiostat
    • 示例
      • 命令
        df -h
        
        查看磁盘的使用率。
      • 文件系统分析
        mount
        
        查看文件系统的挂载情况。
  4. 网络分析
    • 工具使用dstatnetstat
    • 示例
      • 命令
        netstat -an | grep :8080
        
        查看端口 8080 的网络连接情况。
      • 网络配置检查
        cat /etc/hosts
        
        查看主机名解析配置。

(四)应用服务排查

Java 应用服务的内部问题可能导致性能下降或运行异常,需要对应用服务进行详细排查。

  1. CPU 分析
    • 线程栈分析
      • 示例
        jstack -l <pid> > thread_dump.txt
        
        获取线程栈信息,分析是否存在死循环或热点代码。
    • 热点代码定位
      • 示例
        jstack -l <pid> | grep "java.lang.Thread.State: RUNNABLE"
        
        查找处于运行状态的线程,定位热点代码。
  2. 内存分析
    • 堆内存分析
      • 示例
        jmap -dump:format=b,file=heapdump.hprof <pid>
        
        导出 JVM 堆内存,使用工具(如 MAT)分析内存泄漏或对象分布情况。
    • 内存泄漏排查
      • 示例
        jmap -histo:live <pid>
        
        查看存活对象的统计信息,分析是否存在内存泄漏。
  3. 线程分析
    • 线程状态分析
      • 示例
        jstack -l <pid> | grep "java.lang.Thread.State: BLOCKED"
        
        查找处于阻塞状态的线程,分析是否存在线程阻塞问题。
    • 线程池配置优化
      • 示例
        public class ThreadPoolExample {
            public static void main(String[] args) {
                ExecutorService executor = Executors.newFixedThreadPool(20);
                for (int i = 0; i < 1000; i++) {
                    executor.submit(() -> {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    });
                }
                executor.shutdown();
            }
        }
        
        将线程池大小调整为 20,以优化线程池配置。
  4. 垃圾回收分析
    • 垃圾回收日志分析
      • 示例
        java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:LogFile=gc.log -jar yourapp.jar
        
        启用垃圾回收日志,分析垃圾回收的频率和耗时。
    • 垃圾回收调优
      • 示例
        java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=4M -jar yourapp.jar
        
        使用 G1 垃圾回收器,调整垃圾回收参数以优化性能。

(五)数据库分析

数据库是 Java 应用程序的重要组成部分,数据库性能问题可能导致应用程序响应缓慢或运行异常。

  1. 数据库性能监控
    • 性能指标监控
      • 示例
        • MySQL 监控
          SHOW GLOBAL STATUS LIKE 'Threads_running';
          SHOW GLOBAL STATUS LIKE 'Queries';
          
        • Oracle 监控
          SELECT COUNT(*) FROM v$session WHERE status = 'ACTIVE';
          
    • 慢查询日志分析
      • 示例
        • MySQL 慢查询日志
          SET GLOBAL slow_query_log = 'ON';
          SET GLOBAL long_query_time = 1;
          
          查看慢查询日志,分析执行时间较长的 SQL 语句。
  2. 数据库执行计划分析
    • 执行计划查看
      • 示例
        • MySQL 执行计划
          EXPLAIN SELECT * FROM users WHERE age > 30;
          
        • Oracle 执行计划
          EXPLAIN PLAN FOR SELECT * FROM users WHERE age > 30;
          SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
          
    • 执行计划优化
      • 示例
        • 优化 SQL 语句
          SELECT * FROM users WHERE age > 30 AND status = 'active';
          
          添加索引以优化查询性能。
  3. 数据库锁分析
    • 锁等待事件分析
      • 示例
        • MySQL 锁等待
          SHOW ENGINE INNODB STATUS;
          
          查看锁等待事件,分析是否存在锁冲突。
        • Oracle 锁等待
          SELECT * FROM v$lock WHERE type = 'TM';
          
    • 锁优化
      • 示例
        • 优化事务逻辑
          BEGIN TRANSACTION;
          UPDATE users SET status = 'active' WHERE age > 30;
          COMMIT;
          
          减少事务的持有时间,避免锁冲突。
  4. 数据库配置优化
    • 配置参数调整
      • 示例
        • MySQL 配置
          [mysqld]
          innodb_buffer_pool_size = 2G
          innodb_log_file_size = 512M
          
        • Oracle 配置
          ALTER SYSTEM SET DB_CACHE_SIZE = 2G;
          
    • 数据库升级与优化
      • 示例
        • 升级 MySQL
          sudo apt-get install mysql-server
          
        • 优化数据库架构
          ALTER TABLE users ADD INDEX idx_age_status (age, status);
          

(六)网络分析

网络问题是影响 Java 应用程序性能和稳定性的重要因素之一,需要对网络环境进行详细分析。

  1. 网络性能监控
    • 性能指标监控
      • 示例
        • 使用 iftop 监控网络带宽
          sudo apt-get install iftop
          iftop -i eth0
          
        • 使用 ping 测试网络延迟
          ping -c 10 google.com
          
    • 网络流量分析
      • 示例
        • 使用 tcpdump 捕获网络流量
          sudo tcpdump -i eth0 -w network_traffic.pcap
          
        • 使用 Wireshark 分析网络流量
          wireshark network_traffic.pcap
          
  2. 网络配置检查
    • 防火墙规则检查
      • 示例
        • 查看防火墙规则
          sudo iptables -L
          
        • 添加防火墙规则
          sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
          
    • 路由配置检查
      • 示例
        • 查看路由配置
          ip route show
          
        • 添加路由
          sudo ip route add 192.168.1.0/24 via 192.168.0.1
          
  3. 网络连通性测试
    • 连通性测试工具
      • 示例
        • 使用 ping 测试网络连通性
          ping -c 4 8.8.8.8
          
        • 使用 traceroute 测试网络路径
          traceroute 8.8.8.8
          
    • DNS 配置检查
      • 示例
        • 查看 DNS 配置
          cat /etc/resolv.conf
          
        • 测试 DNS 解析
          nslookup google.com
          

三、常用工具

在 Java 线上问题排查过程中,使用合适的工具可以大大提高排查效率。

(一)日志分析工具

  1. ELK 堆栈
    • Elasticsearch:用于存储和索引日志数据,支持高效的全文搜索和数据分析。
    • Logstash:用于日志收集和解析,支持多种日志格式和数据源。
    • Kibana:用于日志可视化和分析,提供丰富的可视化组件和查询功能。
    • 示例
      • Logstash 配置
        input {
          file {
            path => "/var/log/app.log"
            start_position => "beginning"
          }
        }
        output {
          elasticsearch {
            hosts => ["localhost:9200"]
            index => "app-logs"
          }
        }
        
      • Kibana 查询
        GET /app-logs/_search
        {
          "query": {
            "match": {
              "message": "error"
            }
          }
        }
        
  2. Splunk
    • 日志收集与索引:支持多种日志源的收集和索引,提供强大的日志处理能力。
    • 日志搜索与分析:支持复杂的日志搜索和分析功能,提供丰富的报表和可视化功能。
    • 告警与通知:支持根据预设的规则触发告警,及时通知相关人员。
    • 示例
      • 数据索引:将日志数据索引到 Splunk 中。
      • 查询语句
        index=app error
        
  3. 其他日志分析工具
    • Graylog:开源的日志分析工具,支持日志收集、索引、搜索和可视化功能。
    • Loggly:云原生的日志分析工具,支持日志收集、索引、搜索和可视化功能,适合中小规模的系统。
    • 示例
      • Graylog 配置
        input {
          file {
            path => "/var/log/app.log"
            start_position => "beginning"
          }
        }
        output {
          graylog {
            host => "localhost"
            port => 12201
          }
        }
        

(二)APM 工具

  1. Apache Skywalking
    • 性能监控:支持 Java、Node.js 等多种语言的性能监控,提供丰富的性能指标和链路追踪功能。
    • 链路追踪:支持分布式链路追踪,可以查看每个请求的调用链路和性能瓶颈。
    • 可视化界面:提供直观的可视化界面,方便用户查看性能指标和链路追踪信息。
    • 示例
      • Skywalking 配置
        agent:
          collector:
            backend_service: "127.0.0.1:11800"
        
      • 链路追踪查询:在 Skywalking 的 Dashboard 中查看某个请求的调用链路。
  2. Pinpoint
    • 性能监控:支持 Java 应用程序的性能监控,提供详细的性能指标和链路追踪功能。
    • 链路追踪:支持分布式链路追踪,可以查看每个请求的调用链路和性能瓶颈。
    • 实时监控:支持实时监控功能,可以实时查看应用程序的性能指标和链路追踪信息。
    • 示例
      • Pinpoint 配置
        pinpoint.agentId=java_app
        pinpoint.applicationName=java_app
        pinpoint.profiler.transport=GRPC
        pinpoint.collector.ip=127.0.0.1
        pinpoint.collector.port=9999
        
      • 链路追踪查询:在 Pinpoint 的 Dashboard 中查看某个请求的调用链路。
  3. 商业 APM 工具
    • New Relic:提供全面的性能监控和分析功能,支持多种语言和框架。
    • AppDynamics:提供强大的性能监控和分析功能,支持多种语言和框架。
    • 示例
      • New Relic 配置
        sudo apt-get install newrelic-daemon
        
      • AppDynamics 配置
        sudo apt-get install appdynamics-agent
        

(三)系统监控工具

  1. Prometheus
    • 指标收集:支持多种指标收集方式,可以收集系统性能指标、应用程序性能指标等。
    • 指标存储:支持高效的指标存储和查询功能,可以存储大量的性能指标数据。
    • 告警功能:支持根据预设的规则触发告警,及时通知相关人员。
    • 示例
      • Prometheus 配置
        global:
          scrape_interval: 15s
        scrape_configs:
          - job_name: 'java_app'
            static_configs:
              - targets: ['localhost:8080']
        
      • 告警规则
        groups:
          - name: example
            rules:
              - alert: HighCPUUsage
                expr: process_cpu_usage > 0.8
                for: 5m
                labels:
                  severity: critical
                annotations:
                  summary: "High CPU usage on {{ $labels.instance }}"
                  description: "CPU usage is above 80% (current value is: {{ $value }})"
        
  2. Grafana
    • 数据可视化:支持多种数据源的可视化,可以将 Prometheus 收集的指标数据进行可视化展示。
    • 仪表盘定制:支持用户自定义仪表盘,可以根据需求定制个性化的监控仪表盘。
    • 告警功能:支持告警功能,可以与 Prometheus 的告警规则结合,及时通知相关人员。
    • 示例
      • Grafana 配置:在 Grafana 中创建数据源并导入 Prometheus 数据,创建仪表盘以实时监控 CPU、内存等指标。
      • 告警规则:在 Grafana 中创建告警规则,当 CPU 使用率超过 80% 时触发告警。
  3. 其他系统监控工具
    • Zabbix:开源的系统监控工具,支持多种监控功能,包括性能监控、告警、报表等。
    • Nagios:开源的系统监控工具,支持多种监控功能,包括性能监控、告警、报表等。
    • 示例
      • Zabbix 配置
        sudo apt-get install zabbix-agent
        
      • Nagios 配置
        sudo apt-get install nagios-plugins
        

(四)JVM 工具

  1. jstack
    • 线程栈分析:用于获取 Java 应用程序的线程栈信息,分析线程状态和热点代码。
    • 示例
      jstack -l <pid> > thread_dump.txt
      
      获取线程栈信息,分析是否存在死循环或热点代码。
  2. jmap
    • 堆内存分析:用于导出 JVM 堆内存,结合工具(如 MAT、VisualVM)分析内存泄漏或对象分布情况。
    • 示例
      jmap -dump:format=b,file=heapdump.hprof <pid>
      
      导出 JVM 堆内存,使用工具(如 MAT)分析内存泄漏或对象分布情况。
  3. jstat
    • 垃圾回收分析:用于查看 JVM 的垃圾回收状态,分析垃圾回收的频率和耗时。
    • 示例
      jstat -gc <pid> 1000
      
      查看垃圾回收的状态,分析垃圾回收的频率和耗时。
  4. jcmd
    • JVM 操作:用于对 JVM 进行操作,如发送诊断命令、查看 JVM 的运行状态等。
    • 示例
      jcmd <pid> VM.info
      
      查看 JVM 的运行状态。

(五)其他工具

  1. Arthas
    • 实时诊断:支持实时诊断 Java 应用程序的运行状态,包括线程状态、内存使用情况、方法调用情况等。
    • 命令行工具:提供丰富的命令行工具,方便用户快速排查问题。
    • 可视化界面:支持可视化界面,方便用户查看诊断信息。
    • 示例
      java -jar arthas-boot.jar
      
      启动 Arthas,使用命令行工具进行实时诊断。
      thread
      
      查看线程状态。
      ognl "@java.lang.Runtime@getRuntime().availableProcessors()"
      
      查看可用处理器数量。

四、问题排查流程

在 Java 线上问题排查过程中,遵循一定的流程可以提高排查效率,确保问题能够快速定位和解决。

(一)确定问题

  1. 问题描述
    • 问题现象:详细描述问题的现象,如系统响应缓慢、用户报错、系统崩溃等。
    • 问题频率:记录问题出现的频率,如是否是偶现问题、是否是周期性问题等。
    • 问题范围:确定问题影响的范围,如是否影响所有用户、是否影响特定模块等。
    • 示例
      • 问题描述
        问题现象:用户在访问 /api/user 接口时,响应时间超过 10 秒。
        问题频率:每 10 分钟出现一次。
        问题范围:仅影响 /api/user 接口。
        
  2. 问题分类
    • 性能问题:根据问题现象,判断是否是性能问题,如响应时间过长、吞吐量不足等。
    • 异常问题:根据问题现象,判断是否是异常问题,如运行时异常、业务逻辑异常等。
    • 资源泄漏问题:根据问题现象,判断是否是资源泄漏问题,如内存泄漏、文件句柄泄漏等。
    • 示例
      • 问题分类
        问题分类:性能问题(响应时间过长)
        

(二)收集信息

  1. 监控数据收集
    • 系统性能监控数据:收集系统性能监控数据,如 CPU 使用率、内存使用率、磁盘 I/O、网络带宽等。
    • 应用性能监控数据:收集应用性能监控数据,如响应时间、吞吐量、错误率等。
    • 数据库性能监控数据:收集数据库性能监控数据,如查询响应时间、TPS、锁等待时间等。
    • 示例
      • Prometheus 查询
        curl 'http://localhost:9090/api/v1/query?query=process_cpu_usage'
        
      • Grafana 查询:在 Grafana 中查看 CPU 使用率的实时数据。
  2. 日志收集
    • 业务日志:收集业务日志,分析问题相关的日志记录。
    • 系统日志:收集系统日志,分析系统运行状态和异常信息。
    • 应用日志:收集应用日志,分析应用程序的运行状态和异常信息。
    • 示例
      • 日志收集
        tail -f /var/log/app.log
        
      • 日志分析
        grep "error" /var/log/app.log
        
  3. 其他信息收集
    • 配置信息:收集系统配置信息、应用程序配置信息、数据库配置信息等,分析是否存在配置问题。
    • 网络信息:收集网络配置信息、网络流量信息等,分析是否存在网络问题。
    • 示例
      • 配置信息收集
        cat /etc/app/config.properties
        
      • 网络信息收集
        netstat -an | grep :8080
        

(三)分析问题

  1. 业务日志分析
    • 关键字搜索:通过关键字搜索业务日志,快速定位问题相关的日志记录。
    • 日志关联分析:将不同模块或不同时间点的日志进行关联分析,找出问题的因果关系。
    • 日志统计分析:对业务日志中的错误信息、性能指标等进行统计分析,找出问题的频率和分布规律。
    • 示例
      • 关键字搜索
        grep "error" /var/log/app.log
        
      • 日志关联分析
        grep "user_id=12345" /var/log/app.log
        
      • 日志统计分析
        grep "error" /var/log/app.log | wc -l
        
  2. APM 分析
    • 性能指标分析:通过 APM 工具查看应用程序的性能指标,分析是否存在性能问题。
    • 链路追踪分析:通过 APM 工具查看请求的调用链路,分析是否存在性能瓶颈或异常调用。
    • 分布式追踪分析:在分布式系统中,通过 APM 工具进行分布式追踪,分析服务之间的调用关系和性能瓶颈。
    • 示例
      • 性能指标分析
        curl 'http://localhost:8080/metrics'
        
      • 链路追踪分析:在 Skywalking 的 Dashboard 中查看某个请求的调用链路。
  3. 监控数据分析
    • 系统性能指标分析
      • 示例
        • Prometheus 查询 CPU 使用率
          curl 'http://localhost:9090/api/v1/query?query=process_cpu_usage'
          
        • Prometheus 查询内存使用率
          curl 'http://localhost:9090/api/v1/query?query=process_memory_usage'
          
        • Grafana 查询:在 Grafana 中查看 CPU 和内存使用率的实时数据。
    • 应用性能指标分析
      • 示例
        • Prometheus 查询应用响应时间
          curl 'http://localhost:9090/api/v1/query?query=application_response_time'
          
        • Prometheus 查询应用吞吐量
          curl 'http://localhost:9090/api/v1/query?query=application_throughput'
          
        • Grafana 查询:在 Grafana 中查看应用响应时间和吞吐量的实时数据。
    • 数据库性能指标分析
      • 示例
        • Prometheus 查询数据库查询响应时间
          curl 'http://localhost:9090/api/v1/query?query=database_query_response_time'
          
        • Prometheus 查询数据库 TPS
          curl 'http://localhost:9090/api/v1/query?query=database_tps'
          
        • Grafana 查询:在 Grafana 中查看数据库查询响应时间和 TPS 的实时数据。

(四)解决问题

  1. 根据问题类型制定解决方案

    • 性能问题解决方案
      • 优化代码逻辑
        • 示例
          public List<User> getAllUsers() {
              List<User> users = new ArrayList<>();
              for (int i = 0; i < 1000000; i++) {
                  User user = new User();
                  user.setId(i);
                  user.setName("User" + i);
                  users.add(user);
              }
              return users; // 如果不需要全部用户,可以改为分页查询
          }
          
      • 优化数据库查询
        • 示例
          -- 原始查询
          SELECT * FROM users WHERE age > 30;
          -- 优化后的查询
          SELECT id, name FROM users WHERE age > 30 AND status = 'active';
          
      • 优化线程池配置
        • 示例
          public class ThreadPoolExample {
              public static void main(String[] args) {
                  ExecutorService executor = Executors.newFixedThreadPool(20); // 增加线程池大小
                  for (int i = 0; i < 1000; i++) {
                      executor.submit(() -> {
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      });
                  }
                  executor.shutdown();
              }
          }
          
    • 异常问题解决方案
      • 修复代码逻辑错误
        • 示例
          public class NullPointerExample {
              public static void main(String[] args) {
                  String str = "Hello"; // 修复 null 值
                  System.out.println(str.length());
              }
          }
          
      • 增加异常处理逻辑
        • 示例
          public class BusinessLogicExample {
              public static void main(String[] args) {
                  int age = -1;
                  if (age < 0) {
                      throw new IllegalArgumentException("年龄不能为负数");
                  }
                  System.out.println("年龄验证通过");
              }
          }
          
    • 资源泄漏问题解决方案
      • 修复内存泄漏
        • 示例
          public class MemoryLeakExample {
              private static List<Object> list = new ArrayList<>();
              public static void main(String[] args) {
                  while (true) {
                      list.add(new Object());
                      if (list.size() > 1000) { // 限制列表大小
                          list.clear();
                      }
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
          
      • 修复文件句柄泄漏
        • 示例
          public class FileHandleLeakExample {
              public static void main(String[] args) {
                  while (true) {
                      try (FileInputStream fis = new FileInputStream("example.txt")) {
                          fis.read();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                      break; // 避免无限循环
                  }
              }
          }
          
      • 修复数据库连接泄漏
        • 示例
          public class DatabaseConnectionLeakExample {
              public static void main(String[] args) {
                  while (true) {
                      Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/example", "root", "password");
                      try {
                          Statement stmt = conn.createStatement();
                          ResultSet rs = stmt.executeQuery("SELECT * FROM users");
                          while (rs.next()) {
                              System.out.println(rs.getString("name"));
                          }
                      } catch (SQLException e) {
                          e.printStackTrace();
                      } finally {
                          if (conn != null) {
                              try {
                                  conn.close(); // 确保关闭连接
                              } catch (SQLException e) {
                                  e.printStackTrace();
                              }
                          }
                      }
                      break; // 避免无限循环
                  }
              }
          }
          
  2. 验证解决方案的有效性

    • 验证性能问题解决方案
      • 示例
        • 验证优化后的代码逻辑
          public List<User> getAllUsers() {
              List<User> users = new ArrayList<>();
              for (int i = 0; i < 1000000; i++) {
                  User user = new User();
                  user.setId(i);
                  user.setName("User" + i);
                  users.add(user);
              }
              return users; // 如果不需要全部用户,可以改为分页查询
          }
          
          通过压力测试工具(如 JMeter)验证优化后的代码逻辑是否有效。
    • 验证异常问题解决方案
      • 示例
        • 验证修复后的代码逻辑
          public class NullPointerExample {
              public static void main(String[] args) {
                  String str = "Hello"; // 修复 null 值
                  System.out.println(str.length());
              }
          }
          
          运行程序,确保不再抛出 NullPointerException
    • 验证资源泄漏问题解决方案
      • 示例
        • 验证修复后的内存泄漏
          public class MemoryLeakExample {
              private static List<Object> list = new ArrayList<>();
              public static void main(String[] args) {
                  while (true) {
                      list.add(new Object());
                      if (list.size() > 1000) { // 限制列表大小
                          list.clear();
                      }
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
          
          使用工具(如 VisualVM 或 MAT)监控内存使用情况,确保内存泄漏问题已修复。

(五)验证效果

  1. 验证问题是否解决

    • 验证性能问题是否解决
      • 示例
        • 验证优化后的代码逻辑
          public List<User> getAllUsers() {
              List<User> users = new ArrayList<>();
              for (int i = 0; i < 1000000; i++) {
                  User user = new User();
                  user.setId(i);
                  user.setName("User" + i);
                  users.add(user);
              }
              return users; // 如果不需要全部用户,可以改为分页查询
          }
          
          通过压力测试工具(如 JMeter)验证优化后的代码逻辑是否有效。
    • 验证异常问题是否解决
      • 示例
        • 验证修复后的代码逻辑
          public class NullPointerExample {
              public static void main(String[] args) {
                  String str = "Hello"; // 修复 null 值
                  System.out.println(str.length());
              }
          }
          
          运行程序,确保不再抛出 NullPointerException
    • 验证资源泄漏问题是否解决
      • 示例
        • 验证修复后的内存泄漏
          public class MemoryLeakExample {
              private static List<Object> list = new ArrayList<>();
              public static void main(String[] args) {
                  while (true) {
                      list.add(new Object());
                      if (list.size() > 1000) { // 限制列表大小
                          list.clear();
                      }
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
          
          使用工具(如 VisualVM 或 MAT)监控内存使用情况,确保内存泄漏问题已修复。
  2. 验证系统稳定性

    • 验证系统是否恢复正常运行
      • 示例
        • 验证系统性能指标
          curl 'http://localhost:9090/api/v1/query?query=process_cpu_usage'
          curl 'http://localhost:9090/api/v1/query?query=process_memory_usage'
          
        • 验证应用性能指标
          curl 'http://localhost:9090/api/v1/query?query=application_response_time'
          curl 'http://localhost:9090/api/v1/query?query=application_throughput'
          
        • 验证数据库性能指标
          curl 'http://localhost:9090/api/v1/query?query=database_query_response_time'
          curl 'http://localhost:9090/api/v1/query?query=database_tps'
          
    • 验证系统是否稳定运行
      • 示例
        • 监控系统日志
          tail -f /var/log/app.log
          
        • 监控系统性能指标
          top
          free -m
          df -h
          netstat -an | grep :8080
          
  3. 验证用户反馈

    • 验证用户是否满意
      • 示例
        • 收集用户反馈
          echo "请用户反馈问题是否解决"
          
        • 根据用户反馈调整解决方案
          echo "根据用户反馈调整解决方案"
          

(六)持续优化

  1. 优化监控策略

    • 优化监控指标
      • 示例
        • 增加监控指标
          global:
            scrape_interval: 15s
          scrape_configs:
            - job_name: 'java_app'
              static_configs:
                - targets: ['localhost:8080']
          
        • 调整监控指标阈值
          groups:
            - name: example
              rules:
                - alert: HighCPUUsage
                  expr: process_cpu_usage > 0.8
                  for: 5m
                  labels:
                    severity: critical
                  annotations:
                    summary: "High CPU usage on {{ $labels.instance }}"
                    description: "CPU usage is above 80% (current value is: {{ $value }})"
          
    • 优化告警机制
      • 示例
        • 增加告警规则
          groups:
            - name: example
              rules:
                - alert: HighMemoryUsage
                  expr: process_memory_usage > 0.8
                  for: 5m
                  labels:
                    severity: critical
                  annotations:
                    summary: "High Memory usage on {{ $labels.instance }}"
                    description: "Memory usage is above 80% (current value is: {{ $value }})"
          
        • 调整告警通知方式
          global:
            resolve_timeout: 5m
          route:
            receiver: 'webhook'
          receivers:
            - name: 'webhook'
              webhook_configs:
                - url: 'http://localhost:9093/webhook'
          
  2. 改进告警机制

    • 优化告警规则
      • 示例
        • 增加告警规则
          groups:
            - name: example
              rules:
                - alert: HighCPUUsage
                  expr: process_cpu_usage > 0.8
                  for: 5m
                  labels:
                    severity: critical
                  annotations:
                    summary: "High CPU usage on {{ $labels.instance }}"
                    description: "CPU usage is above 80% (current value is: {{ $value }})"
          
        • 调整告警阈值
          groups:
            - name: example
              rules:
                - alert: HighMemoryUsage
                  expr: process_memory_usage > 0.8
                  for: 5m
                  labels:
                    severity: critical
                  annotations:
                    summary: "High Memory usage on {{ $labels.instance }}"
                    description: "Memory usage is above 80% (current value is: {{ $value }})"
          
    • 优化告警通知方式
      • 示例
        • 增加告警通知方式
          global:
            resolve_timeout: 5m
          route:
            receiver: 'webhook'
          receivers:
            - name: 'webhook'
              webhook_configs:
                - url: 'http://localhost:9093/webhook'
          
  3. 升级分析工具

    • 升级监控工具
      • 示例
        • 升级 Prometheus
          sudo apt-get install prometheus
          
        • 升级 Grafana
          sudo apt-get install grafana
          
    • 升级日志分析工具
      • 示例
        • 升级 ELK 堆栈
          sudo apt-get install elasticsearch logstash kibana
          
        • 升级 Splunk
          sudo apt-get install splunk
          
  4. 改进日志管理

    • 优化日志记录策略
      • 示例
        • 优化 Log4j 配置
          <Configuration status="WARN">
            <Appenders>
              <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
              </Console>
              <File name="ApplicationLog" fileName="logs/app.log">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
              </File>
            </Appenders>
            <Loggers>
              <Root level="info">
                <AppenderRef ref="Console"/>
                <AppenderRef ref="ApplicationLog"/>
              </Root>
            </Loggers>
          </Configuration>
          
        • 优化日志级别:根据需要调整日志级别,例如在生产环境中将日志级别设置为 INFOWARN,以减少日志文件的大小。
    • 优化日志存储策略
      • 示例
        • 配置日志轮转
          <RollingFile name="RollingFile" fileName="logs/app.log"
                       filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout>
              <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</Pattern>
            </PatternLayout>
            <Policies>
              <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
              <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
          </RollingFile>
          
        • 配置日志保留策略:设置日志文件的保留时间或数量,例如保留最近 30 天的日志文件。
    • 优化日志分析工具
      • 示例
        • 升级 ELK 堆栈
          sudo apt-get update
          sudo apt-get install elasticsearch logstash kibana
          
        • 优化 Kibana 索引模式:根据日志数据的特点,优化 Kibana 的索引模式,提高查询效率。
          PUT /_index_template/app-logs
          {
            "index_patterns": ["app-logs-*"],
            "settings": {
              "number_of_shards": 3,
              "number_of_replicas": 1
            },
            "mappings": {
              "properties": {
                "timestamp": { "type": "date" },
                "level": { "type": "keyword" },
                "message": { "type": "text" }
              }
            }
          }
          
  5. 制定标准化流程

    • 制定问题排查流程
      • 示例
        • 问题排查流程文档
          # Java 线上问题排查流程
          
          ## 1. 确定问题
          - 描述问题现象
          - 记录问题频率
          - 确定问题范围
          
          ## 2. 收集信息
          - 收集监控数据
          - 收集日志信息
          - 收集配置信息
          
          ## 3. 分析问题
          - 分析业务日志
          - 分析 APM 数据
          - 分析监控数据
          
          ## 4. 解决问题
          - 制定解决方案
          - 验证解决方案
          
          ## 5. 验证效果
          - 验证问题是否解决
          - 验证系统稳定性
          - 收集用户反馈
          
          ## 6. 持续优化
          - 优化监控策略
          - 改进告警机制
          - 升级分析工具
          - 改进日志管理
          
    • 制定监控与告警标准
      • 示例
        • 监控与告警标准文档
          # Java 应用监控与告警标准
          
          ## 1. 监控指标
          - CPU 使用率
          - 内存使用率
          - 磁盘 I/O
          - 网络带宽
          - 应用响应时间
          - 应用吞吐量
          - 数据库查询响应时间
          - 数据库 TPS
          
          ## 2. 告警规则
          - CPU 使用率 > 80% 持续 5 分钟
          - 内存使用率 > 80% 持续 5 分钟
          - 应用响应时间 > 2 秒 持续 5 分钟
          - 数据库查询响应时间 > 1 秒 持续 5 分钟
          
          ## 3. 告警通知方式
          - 邮件通知
          - 短信通知
          - Webhook 通知
          
          ## 4. 监控工具配置
          - Prometheus 配置
          - Grafana 配置
          - ELK 堆栈配置
          
    • 制定日志管理标准
      • 示例
        • 日志管理标准文档
          # Java 应用日志管理标准
          
          ## 1. 日志记录策略
          - 日志级别:INFO、WARN、ERROR
          - 日志格式:`%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n`
          - 日志存储位置:`/var/log/app.log`
          
          ## 2. 日志存储策略
          - 日志轮转:每天轮转一次,保留最近 30 天的日志
          - 日志压缩:使用 gzip 压缩旧日志文件
          
          ## 3. 日志分析工具
          - ELK 堆栈
          - Splunk
          - Graylog
          
          ## 4. 日志分析流程
          - 关键字搜索
          - 日志关联分析
          - 日志统计分析
          
posted @   软件职业规划  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 后端思维之高并发处理方案
· 千万级大表的优化技巧
· 在 VS Code 中,一键安装 MCP Server!
· 想让你多爱自己一些的开源计时器
· 10年+ .NET Coder 心语 ── 继承的思维:从思维模式到架构设计的深度解析
点击右上角即可分享
微信分享提示