当前位置: 首页 > 编程笔记 >

Springboot实现高吞吐量异步处理详解(适用于高并发场景)

南宫俊喆
2023-03-14
本文向大家介绍Springboot实现高吞吐量异步处理详解(适用于高并发场景),包括了Springboot实现高吞吐量异步处理详解(适用于高并发场景)的使用技巧和注意事项,需要的朋友参考一下

技术要点

org.springframework.web.context.request.async.DeferredResult<T>

示例如下:

1.   新建Maven项目  async

2.   pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
    http://maven.apache.org/xsd/maven-4.0.0.xsd">


  <modelVersion>4.0.0</modelVersion>
  <groupId>com.java</groupId>
  <artifactId>async</artifactId>
  <version>1.0.0</version>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.5.RELEASE</version>
  </parent>


  <dependencies>

    <!-- Spring Boot -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <!-- 热部署 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>springloaded</artifactId>
      <version>1.2.8.RELEASE</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>provided</scope>
    </dependency>

  </dependencies>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

3.   AsyncStarter.java

package com.java;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AsyncStarter {

  public static void main(String[] args) {
    SpringApplication.run(AsyncStarter.class, args);
  }
}

4.   AsyncVo.java

package com.java.vo;

import org.springframework.web.context.request.async.DeferredResult;

/**
 * 存储异步处理信息
 * 
 * @author Logen
 *
 * @param <I> 接口输入参数
 * @param <O> 接口返回参数
 */
public class AsyncVo<I, O> {

  /**
   * 请求参数
   */
  private I params;

  /**
   * 响应结果
   */
  private DeferredResult<O> result;

  public I getParams() {
    return params;
  }

  public void setParams(I params) {
    this.params = params;
  }

  public DeferredResult<O> getResult() {
    return result;
  }

  public void setResult(DeferredResult<O> result) {
    this.result = result;
  }
}

5.   RequestQueue.java

package com.java.queue;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.springframework.stereotype.Component;

import com.java.vo.AsyncVo;

/**
 * 存放所有异步处理接口请求队列的对象,一个接口对应一个队列
 * 
 * @author Logen
 *
 */
@Component
public class RequestQueue {

  /**
   * 处理下订单接口的队列,设置缓冲容量为50
   */
  private BlockingQueue<AsyncVo<String, Object>> orderQueue = new LinkedBlockingQueue<>(50);

  public BlockingQueue<AsyncVo<String, Object>> getOrderQueue() {
    return orderQueue;
  }
}

6.   OrderTask.java

package com.java.task;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.java.queue.RequestQueue;
import com.java.vo.AsyncVo;

/**
 * 处理订单接口的任务,每个任务类处理一种接口
 * 
 * @author Logen
 *
 */
@Component
public class OrderTask extends Thread {

  @Autowired
  private RequestQueue queue;

  private boolean running = true;

  @Override
  public void run() {
    while (running) {
      try {
        AsyncVo<String, Object> vo = queue.getOrderQueue().take();
        System.out.println("[ OrderTask ]开始处理订单");

        String params = vo.getParams();
        Thread.sleep(3000);
        Map<String, Object> map = new HashMap<>();
        map.put("params", params);
        map.put("time", System.currentTimeMillis());

        vo.getResult().setResult(map);

        System.out.println("[ OrderTask ]订单处理完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
        running = false;
      }

    }
  }

  public void setRunning(boolean running) {
    this.running = running;
  }
}

7.   QueueListener.java

package com.java.listener;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.java.task.OrderTask;

/**
 * 队列监听器,初始化启动所有监听任务
 * 
 * @author Logen
 *
 */
@Component
public class QueueListener {

  @Autowired
  private OrderTask orderTask;

  /**
   * 初始化时启动监听请求队列
   */
  @PostConstruct
  public void init() {
    orderTask.start();
  }

  /**
   * 销毁容器时停止监听任务
   */
  @PreDestroy
  public void destory() {
    orderTask.setRunning(false);
  }

}

8.   OrderController.java

package com.java.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import com.java.queue.RequestQueue;
import com.java.vo.AsyncVo;

/**
 * <blockquote>
 * 
 * <pre>
 * 
 * 模拟下单处理,实现高吞吐量异步处理请求
 * 
 * 1、 Controller层接口只接收请求,不进行处理,而是把请求信息放入到对应该接口的请求队列中
 * 2、 该接口对应的任务类监听对应接口的请求队列,从队列中顺序取出请求信息并进行处理
 * 
 * 优点:接口几乎在收到请求的同时就已经返回,处理程序在后台异步进行处理,大大提高吞吐量
 * 
 * 
 * </pre>
 * 
 * </blockquote>
 * 
 * @author Logen
 *
 */
@RestController
public class OrderController {

  @Autowired
  private RequestQueue queue;

  @GetMapping("/order")
  public DeferredResult<Object> order(String number) throws InterruptedException {
    System.out.println("[ OrderController ] 接到下单请求");
    System.out.println("当前待处理订单数: " + queue.getOrderQueue().size());

    AsyncVo<String, Object> vo = new AsyncVo<>();
    DeferredResult<Object> result = new DeferredResult<>();

    vo.setParams(number);
    vo.setResult(result);

    queue.getOrderQueue().put(vo);
    System.out.println("[ OrderController ] 返回下单结果");
    return result;
  }
}

 9.   运行 AsyncStarter.java ,启动测试

浏览器输入 http://localhost:8080/order?number=10001

正常情况处理3秒返回,返回结果如下

{"time":1548241500718,"params":"10001"}

观察控制台打印日志,如下所示:

[ OrderController ] 接到下单请求
当前待处理订单数: 0
[ OrderController ] 返回下单结果
[ OrderTask ]开始处理订单
[ OrderTask ]订单处理完成

结论:Controller层几乎在接收到请求的同时就已经返回,处理程序在后台异步处理任务。 

快速多次刷新浏览器,目的为了高并发测试,观察控制台打印信息

现象:Controller层快速返回,待处理请求在队列中开始增加,异步处理程序在按顺序处理请求。

优点:对客户端响应时间不变,但提高了服务端的吞吐量。大大提升高并发处理性能!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍springboot高并发下提高吞吐量的实现,包括了springboot高并发下提高吞吐量的实现的使用技巧和注意事项,需要的朋友参考一下 公司让做一个全文检索的项目,我使用的是elasticsearch。但是对性能有很高的要求,为了解决性能问题,我简直是寝食难安。 es(elasticsearch)没有使用分布式,单台的。 开发完测试的时候,查询慢,吞吐量低。 网友们建议用异步--使

  • 我正在对ElasticSearch进行基准测试,以实现非常高的索引吞吐量。 我目前的目标是能够在几个小时内索引30亿(3,000,000,000)文档。为此,我目前有3台windows服务器机器,每台16GB内存和8个处理器。插入的文档有一个非常简单的映射,只包含少数数字非分析字段(被禁用)。 使用这个相对适中的钻机,我能够达到每秒大约120,000个索引请求(使用大桌子监控),我相信吞吐量可以进

  • null 基本上,具有内存缓存和可以响应命令的服务器的机器的普通香草实现和Redis盒子之间有什么区别?我也明白答案需要非常庞大,并且应该包括非常复杂的细节来完成。但是,我要找的是一些通用的技术,而不是所有的细微差别。

  • 问题内容: 我知道这是一个非常笼统的问题。但是,我想了解使Redis(或诸如MemCached,Cassandra之类的缓存)在惊人的性能极限下工作的主要架构决策是什么。 如何维护连接? 连接是TCP还是HTTP? 我知道它完全用C编写。如何管理内存? 尽管存在竞争的读/写,但用于实现高吞吐量的同步技术有哪些? 基本上,具有内存高速缓存的计算机和可以响应命令的服务器的普通香草实现和Redis框之间

  • 我需要从很多客户端通过网络套接字连接到java服务器来提取数据。 有很多web套接字实现,我选择了vert。x、 我做了一个简单的演示,在那里我听json的文本帧,用jackson解析它们,然后返回响应。Json解析器对吞吐量没有显著影响。 我的总速度是每秒2.5公里,有2到10个客户。 然后我尝试使用缓冲,客户端不会等待每个响应,而是在服务器确认后发送一批消息(30k-90k),速度提高到每秒8

  • 本文向大家介绍Kafka 是如何实现高吞吐率的?相关面试题,主要包含被问及Kafka 是如何实现高吞吐率的?时的应答技巧和注意事项,需要的朋友参考一下 Kafka是分布式消息系统,需要处理海量的消息,Kafka的设计是把所有的消息都写入速度低容量大的硬盘,以此来换取更强的存储能力,但实际上,使用硬盘并没有带来过多的性能损失。kafka主要使用了以下几个方式实现了超高的吞吐率: 顺序读写; 零拷贝