简体   繁体   English

如何在Spring Mvc中使用多线程来提高性能

[英]How to improve performance using multithreading in spring Mvc

I am using spring MVC model in my project. 我在项目中使用spring MVC模型。 In which controller get request from some some thired party application. 哪个控制器从某个第三方应用程序获取请求。 Controller get 20 request per sec. 控制器每秒获得20个请求。 Code look like this 代码看起来像这样

@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";
}

This code is working fine but some time if mysql is busy then it takes time to return the value to calling application. 这段代码可以正常工作,但是如果mysql很忙,则需要一段时间才能将值返回给调用应用程序。 So I droped the idea and start Async communication. 因此,我放弃了主意,开始进行异步通信。

(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";
}

I started using the code something like this. 我开始使用类似这样的代码。 So that calling party can get the response immediately(reduce the response time) and later on my application continue to work. 这样主叫方可以立即获得响应(减少响应时间),然后在我的应用程序上继续工作。 But in First code i test the load with JMeter(20 req/sec ) and found it is working fine with cpu load(3%). 但是在第一个代码中,我用JMeter(20 req / sec)测试了负载,发现它在cpu load(3%)下工作正常。 But in second code with same load cpu load is going to more than 100%.Than i started using the ThreadPoolTaskExecutor with below configuration. 但是在具有相同负载的第二个代码中,CPU负载将超过100%。然后我开始使用具有以下配置的ThreadPoolTask​​Executor。

@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>

but found the same result. 但发现相同的结果。 Whats wrong with code can somebody suggest me. 代码有什么问题可以有人建议我。 One important thing when i test with Jmeter in stage envorment then load is moving between 30% to 70%.. But in production server it is always around 100%. 当我在阶段测试中使用Jmeter进行测试时,一件重要的事情是负载在30%到70%之间移动。但是在生产服务器中,负载总是在100%左右。 It is java consuming 100% other process is quite low. 它消耗了100%其他进程的Java相当低。 Production machine haveing linux OS. 生产机器具有linux OS。 hexacore processer having 128 GB RAM. 具有128 GB RAM的六核处理器。 Can some one tell me what to do. 有人可以告诉我该怎么做。

Your ThreadPoolTaskExecutor has too many threads. 您的ThreadPoolTaskExecutor过多。 CPU spend lot of time to switch context between threds. CPU花大量时间在thred之间切换上下文。 On test you run just your controller so there are no other threads (calls) that exist on production. 在测试中,您仅运行控制器,因此生产环境中不存在其他线程(调用)。 Core problem is waiting for DB, because it is blocking thread 核心问题是等待数据库,因为它阻塞了线程

Solutions 解决方案

  • set pool size smaller (make some experiment) 设置较小的池(进行一些实验)
  • remove executor and use actor system like Akka for save operation. 删除执行程序,并使用Akka之类的actor系统进行save操作。
  • Most important use batch to save objects in DB . 最重要的是使用批处理将对象保存在DB中 There will be only one call per eg 1000 objects not 1k calls for 1k objects > JPA/Hibernate improve batch insert performance 每1000个对象只有一个调用,而不是1k对象的1k调用> JPA / Hibernate提高了批处理插入性能

It looks like you are turning the wrong knob. 看来您在转动错误的旋钮。

In your first version you had up to N threads banging your database. 在第一个版本中,最多有N个线程在破坏数据库。 With N being configured somewhere in your servlet container. 使用N在您的servlet容器中的某个位置配置。 And also doing the servlet thingy, accepting connections and stuff. 还要做一些servlet,接受连接和填充。

Now you created 200 additional threads, which do basically nothing but hitting the database. 现在,您创建了200个其他线程,这些线程除了访问数据库外基本上不执行任何操作。 While the previous threads do their connection handling, request parsing thing. 当先前的线程进行连接处理时,请求进行解析。 So you increased the load on the database and you added the load do to context switching (except when you have multiple hundred cores). 因此,您增加了数据库的负载,并且将负载do添加到上下文切换中(除非您有数百个内核)。 And for some weird reason, your database didn't get any faster. 出于某些奇怪的原因,您的数据库并没有获得更快的速度。

In order to improve, reduce the number of threads in your thread pool which hits the database. 为了提高性能,请减少影响数据库的线程池中的线程数。 Measure how many threads the database can handle before performance degrades. 测量性能降低之前数据库可以处理多少个线程。

Make the queueCapacity large enough to cover the request spikes you need to handle. 使queueCapacity足够大以覆盖您需要处理的请求峰值。

Implement something that gets a meaningfull answer to the user when this isn't sufficient. 当这还不够时,实施一些能够给用户有意义的答案的事情。 Something like "Sorry ..." 诸如“对不起...”之类的东西

And then take care of the real issue: How to make your database handle the requests fast enough. 然后处理一个真正的问题:如何使数据库足够快地处理请求。

It might be that some db tuning is in place, or you need to switch to a different database system, or maybe the implementation of the save method needs some tuning ... 可能是某些数据库调整已经到位,或者您需要切换到其他数据库系统,或者也许save方法的实现需要一些调整...

But all this is for a different question. 但这一切是一个不同的问题。

the bottle neck in your case are transactions (DB) 您遇到的瓶颈是交易(DB)

here's some proposals : 这是一些建议:

  1. if it's not necessary that data has to be instantly saved just use an asynchronous job to do it (JMS, In Memory Queue, etc) 如果不需要立即保存数据,则只需使用异步作业即可完成(JMS,内存队列等)

  2. You may consider to load DB into RAM 您可以考虑将DB加载到RAM中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM