高并发接口调试过程及技巧

1、把代码部署到现网后,厂商进行数据推送测试。
发现一个问题,就是EOF问题。

百度后,从问题表现看,是文件流不完整。

但是,为什么文件流会不完整了。
于是,进行了一系列的排查工作。

首先想到的就是,并发量太大,导致,接口响应不过来,服务主动断开请求,导致流损坏。

于是,我把接口里面的MySQL写入逻辑给注释掉,这样,从而提升接口性能
再次测试
发现,还是有EOF问题。

于是,开始排查性能瓶颈


第1步,在报错的时候,打印CPU、内存、磁盘IO速率
但是,发现,这三者都没达到瓶颈,就是IO的写速度还剩67MB/s的速度

第2步,是调整tomcat连接数配置。依然报错

所以,我继续简化接口,把接口改成,最简单流字节数计算
并获取Content Length参数,进行比对。
这样应该不会在发生这个问题了吧

结果,还是存在断流问题

于是,厂商建议他们的demo程序部署到我们的服务器,进行测试。
结果,他们的程序没有断流现象。

显然,是我这边程序问题
但是,我已经是最基本的流字节遍历了。

最后,我想到,是否是springboot版本的bug				-----这里,至于我为什么会这么想,我也不知道,就是没确定原因前,习惯性的根据经验猜测吧。

于是,我把 2.1.13.RELEASE 版本,换成 2.7.2版本,这个断流问题,没有了。
但是,后来发现也不是这个原因。

因为,我重新整理了一个工程,springboot版本用的就是  2.1.13.RELEASE  版本		----这里为什么做这个测试,出于就是职业习惯,用控制变量法查找原因。
也没有出现断流问题

最后判定,应该是原工程包做的什么切面配置,导致每个请求前后都要处理一下逻辑
但是,这个无法验证,因为,我本地用同样的文件进行提交,并没有出现问题。
所以,一直没找到问题的原因。

最终,因为客户要求,需要https协议报送数据,于是我整合了https协议功能,出现了断流问题。		---确定了断流原因

整理了新的工程包后,出现另外一个问题,厂家对接时,偶尔收不到body里面的json
我经过多番测试,没有问题。
后来厂家自己修改了读取body内容的方式,问题得以解决。

最终实现效果:
1900份数据,2000多次请求,每次50条左右,1分钟内刷完
估算一天可以刷1.4亿数据。

tomcat线程配置:
server:
  port: 8080
  tomcat:
    ## 等待队列长度,默认100。
    accept-count: 65535
    ## 最大可被连接数,默认10000
    max-connections: 65535
    ## 最大工作线程数,默认200。(4核8g内存,线程数经验值800,操作系统做线程之间的切换调度是有系统开销的,所以不是越多越好。)
    max-threads: 2000
    ## 最小工作空闲线程数,默认10。
    min-spare-threads: 500

以上整个过程,大概持续了1周时间,搞的我几天没睡好觉。

工具类(只能在Linux环境使用):


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class SystemMonitor {

    public static String getSystemParams(){
        final long GB = 1024 * 1024 * 1024;
        OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
        String osJson = JSON.toJSONString(operatingSystemMXBean);
//            System.out.println("osJson is " + osJson);
        JSONObject jsonObject = JSON.parseObject(osJson);
        double processCpuLoad = jsonObject.getDouble("processCpuLoad") * 100;
        double systemCpuLoad = jsonObject.getDouble("systemCpuLoad") * 100;
        Long totalPhysicalMemorySize = jsonObject.getLong("totalPhysicalMemorySize");
        Long freePhysicalMemorySize = jsonObject.getLong("freePhysicalMemorySize");
        double totalMemory = 1.0 * totalPhysicalMemorySize / GB;
        double freeMemory = 1.0 * freePhysicalMemorySize / GB;
        double memoryUseRatio = 1.0 * (totalPhysicalMemorySize - freePhysicalMemorySize) / totalPhysicalMemorySize * 100;

        Runtime run = Runtime.getRuntime();
        long max = run.maxMemory();
        long total = run.totalMemory();
        long free = run.freeMemory();
        long usable = max - total + free;

        StringBuilder result = new StringBuilder();
        result.append("系统CPU占用率: ")
                .append(twoDecimal(systemCpuLoad))
                .append("%,系统内存占用率:")
                .append(twoDecimal(memoryUseRatio))
                .append("%,系统系统总内存:")
                .append(twoDecimal(totalMemory))
                .append("GB,系统剩余内存:")
                .append(twoDecimal(freeMemory))
                .append("GB,该进程占用CPU:")
                .append(twoDecimal(processCpuLoad))
                .append("%");
        StringBuilder jvmResult = new StringBuilder();
        jvmResult.append("最大JVM内存 = ").append(max/(1024 * 1024))
                .append("MB,已分配的JVM内存 = ").append(total/(1024 * 1024))
                .append("MB,剩余JVM内存 = ").append(free/(1024 * 1024))
                .append("MB,最大可用JVM内存 = ").append(usable/(1024 * 1024))
                .append("MB");
        return result.toString() + "    \n" + jvmResult.toString();
    }

    public static double twoDecimal(double doubleValue) {
        BigDecimal bigDecimal = new BigDecimal(doubleValue).setScale(2, RoundingMode.HALF_UP);
        return bigDecimal.doubleValue();
    }


    public static String executeNewFlow(List<String> commands) {
        Runtime run = Runtime.getRuntime();
        String rspLine = "";
        StringBuilder builder = new StringBuilder();
        try {
            Process proc = run.exec("/bin/bash", null, null);
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
            for (String line : commands) {
                out.println(line);
            }
            // 这个命令必须执行,否则in流不结束。
            out.println("exit");
            builder.append("\n");
            while ((rspLine = in.readLine()) != null) {
                builder.append(rspLine+"\n");
            }
            proc.waitFor();
            in.close();
            out.close();
            proc.destroy();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return builder.toString();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值