有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在spring Mvc中使用多线程提高性能

我在我的项目中使用SpringMVC模型。其中控制器从某个第三方应用程序获取请求。 控制器每秒收到20个请求。代码是这样的

@Controller
@RequestMapping("/action")
public class FrontController{

@AutoWired
private CommonService commonService;

(First Code)
@RequestMappint("/save")
public String saveData(@PathParam("id")String did){

    List<String, Object> map = commonService.getVmn(did);
    CallReporting callReporting = new CallReporting();
    callReporting.setName(map.get("name"));
    so---on (have 15 field)
    commonService.save(callReporting);
    }

    return "1";
}

这段代码工作正常,但如果mysql很忙,则需要一段时间才能将值返回给调用应用程序。 所以我放弃了这个想法,开始异步通信

(Second Code)
@RequestMappint("/save")
public String saveData(@PathParam("id")String did){

    Thread thread = new Thread(new Runnable(){
        List<String, Object> map = commonService.getVmn(did);
        CallReporting callReporting = new CallReporting();
        callReporting.setName(map.get("name"));
        so---on (have 15 field)
        commonService.save(callReporting);
    });
    }

    return "1";
}

我开始使用类似这样的代码。这样调用方可以立即得到响应(减少响应时间),然后我的应用程序继续工作。但在第一个代码中,我用JMeter(20 req/sec)测试了负载,发现它在cpu负载(3%)下运行良好。但在第二个代码中,相同负载的cpu负载将超过100%。然后我开始使用以下配置的ThreadPoolTaskExecutor

@AutoWired
private ThreadPoolTaskExecutor executor;

@RequestMappint("/save")
public String saveData(@PathParam("id")String did){

//Assume this code is in MyRunnableWorker Class
        List<String, Object> map = commonService.getVmn(did);
        CallReporting callReporting = new CallReporting();
        callReporting.setName(map.get("name"));
        so---on (have 15 field)
        commonService.save(callReporting);

    MyRunnableWorker worker = new MyRunnableWorker();
    executor.execute(worker)

    return "1";
}

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="50" />
    <property name="maxPoolSize" value="100" />
    <property name="keep-alive" value="10" />
    <property name="queueCapacity" value="200" />
</bean>

但是发现了同样的结果。有人能告诉我代码有什么问题吗。当我在阶段环境中使用Jmeter进行测试时,一件重要的事情是负载在30%到70%之间移动。。但在生产服务器中,它始终在100%左右。这是因为java消耗了100%的资源,而其他进程的消耗非常低。 具有linux操作系统的生产机器。具有128 GB RAM的六核处理器。 谁能告诉我该怎么办


共 (3) 个答案

  1. # 1 楼答案

    看起来你拧错旋钮了

    在你的第一个版本中,你有多达N个线程冲击你的数据库。在servlet容器中的某个地方配置了N。还有做servlet之类的事情,接受连接等等

    现在,您又创建了200个线程,这些线程基本上什么都不做,只是访问数据库。在前面的线程进行连接处理时,请求解析是最重要的。因此,您增加了数据库的负载,并将负载添加到上下文切换中(除非您有几百个内核)。 出于某种奇怪的原因,你的数据库没有变得更快

    为了提高性能,减少线程池中访问数据库的线程数。在性能下降之前,测量数据库可以处理多少线程

    使队列容量足够大,以覆盖需要处理的请求峰值

    当这还不够的时候,实现一些能给用户一个有意义的完整答案的东西。比如“对不起……”

    然后考虑真正的问题:如何让数据库足够快地处理请求

    可能是某些数据库调整已经到位,或者您需要切换到另一个数据库系统,或者save方法的实现需要一些调整

    但这一切都是为了一个不同的问题

  2. # 2 楼答案

    你的ThreadPoolTaskExecutor线程太多。CPU花费大量时间在THRED之间切换上下文。在测试中,您只运行控制器,这样生产环境中就没有其他线程(调用)。核心问题是等待DB,因为它阻塞了线程

    解决方案

    • 设置较小的池大小(进行一些实验)
    • 删除executor并使用像Akka这样的actor系统进行save操作
    • 最重要的是使用批处理将对象保存到数据库中。每1000个对象只有一次呼叫,而不是1k对象的1k呼叫>JPA/Hibernate improve batch insert performance
  3. # 3 楼答案

    在您的案例中,瓶颈是交易(DB)

    以下是一些建议:

    1. 如果不需要立即保存数据,只需使用异步作业(JMS、内存队列等)

    2. > p>您可以考虑将DB加载到RAM