29

springboot~高并发下耗时操作的实现

 4 years ago
source link: http://www.cnblogs.com/lori/p/11877556.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

高并发下的耗时操作

高并发下,就是请求在一个时间点比较多时,很多写的请求打过来时,你的服务器承受很大的压力,当你的一个请求处理时间长时,这些请求将会把你的服务器线程耗尽,即你的主线程池里的线程将不会再有空闲状态的,再打过来的请求,将会是502了。

请求流程图

http1        http2                http3
thread1    thread2            thread3

解决方案

使用 DeferredResult 来实现异步的操作,当一个请求打过来时,先把它放到一个队列时,然后在后台有一个订阅者,有相关主题的消息发过来时,这个订阅者就去消费它,这一步可以是分布式的,比如一个秒杀场景,当N多的请求打过来时,有一些请求命中后,它们进行写操作,这时写操作压力很大,1个请求可以要处理3秒,对于高并发场景这是不能容许的,因为你这样占用的服务器线程资源太长了,很快你的服务器就没有可用的线程资源了,这时就可以用到DeferredResult这处理。

代码实现

建立订单的接口,只负责简单的校验和事件的发布

/**
     * 异步建立高并发的订单.
     *
     * @return
     */
    @GetMapping("/create-order")
    public DeferredResult<Object> createOrder() {
        DeferredResult<Object> deferredResult = new DeferredResult<>((long) 3000, "error order");
        logger.info("发布建立订单的事件");
        applicationEventPublisher.publishEvent(deferredResult);
        return deferredResult;
    }

异步的订单处理核心逻辑,也是耗时的操作

@Component
@EnableAsync
public class OrderListener {

    static Logger logger = LoggerFactory.getLogger(OrderListener.class);

    /**
     * 事实上它是一个订单队列的消费者,在后台写订单,本例使用简单的事件监听器实现异步处理的功能.
     *
     * @return
     */
    @EventListener
    @Async
    public String processOrder(DeferredResult<Object> deferredResult) throws InterruptedException {
        logger.info("处理订单并返回到对应的Http上下文");
        String order = UUID.randomUUID().toString();
        Thread.sleep(2000);//假设处理数据需要5秒,前端需要阻塞5秒,但http主线程已经释放了,比较适合IO密集型场合
        //当设置之后,create-order将成功响应
        deferredResult.setResult(order);
        return order;
    }
}

测试结果

当请求/create-order后,服务器在处理2秒后,返回结果,而spring后台真正做的是,线程1在事件发布后,它成为空闲状态,其它请求可以复用它,当processOrder后台处理结果后,spring又会用线程池中拿一个新的线程处理剩下的逻辑!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK