Memorydoc
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
    • HTML
    • CSS
    • 前端拓展
  • 编程之道

    • 并发编程
    • 设计模式
    • 数据结构算法
    • 技术拓展
    • 技术陷阱
    • 面试宝典
  • 分布式

    • 微服务
    • 数据库
  • 项目优化实战

    • JVM 优化
    • 线程池优化
    • 模板引擎优化
    • 任务调度优化
    • 内存优化
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Memorydoc

术尚可求
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
    • HTML
    • CSS
    • 前端拓展
  • 编程之道

    • 并发编程
    • 设计模式
    • 数据结构算法
    • 技术拓展
    • 技术陷阱
    • 面试宝典
  • 分布式

    • 微服务
    • 数据库
  • 项目优化实战

    • JVM 优化
    • 线程池优化
    • 模板引擎优化
    • 任务调度优化
    • 内存优化
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 并发编程

  • 设计模式

  • 数据结构算法

  • 技术拓展

    • 服务器搭建https
    • Maven 知识拓展
    • 项目集成Mybatis
    • 添加多个Ssh Key到一台电脑
    • BIO、NIO、AIO、Netty
    • 类加解密 & 自定义类加载器
    • 优化web 项目性能
    • 提升万倍系统吞吐量
      • 普通接口编写方式
        • Controller 层
        • Service 层
      • 查看结果
      • 第一步优化, 使用 Future 和 线程池 ExecutorService
      • 查看执行结果
      • 提高系统吞吐量万倍
        • 执行结果(tomcat 线程会立即释放, 返回数据则有jvm线程异步返回接口,大大提高了系统吞吐量)
      • 通过配置实现 异常处理, 并设置线程池控制异步 返回无须每次都创建新线程
        • Controller 层可以直接这样写
      • 总结
    • 优雅写代码一
    • 优雅写代码二
    • 优雅写代码三
  • 技术陷阱

  • 面试宝典

  • 微服务

  • 数据库

  • 项目优化背景

  • JVM优化

  • 技术架构
  • 技术拓展
Memorydoc
2022-03-07
普通接口编写方式
Controller 层
Service 层
查看结果
第一步优化, 使用 Future 和 线程池 ExecutorService
查看执行结果
提高系统吞吐量万倍
执行结果(tomcat 线程会立即释放, 返回数据则有jvm线程异步返回接口,大大提高了系统吞吐量)
通过配置实现 异常处理, 并设置线程池控制异步 返回无须每次都创建新线程
Controller 层可以直接这样写
总结

提升万倍系统吞吐量原创

# 普通接口编写方式

# Controller 层

   @PostMapping(value = "/test1")
    public ServiceResult test1() {
        long start = System.currentTimeMillis();
        ServiceResult serviceResult = new ServiceResult();
        String kevin = userService.getUserInfo("kevin");
        serviceResult.setMessage("请求成功");
        serviceResult.setSuccess(true);
        serviceResult.setBody(kevin);
        System.out.println("消耗时间:" + (System.currentTimeMillis() - start));
        return serviceResult;
    }
1
2
3
4
5
6
7
8
9
10
11

# Service 层

    @Override
    public String getUserInfo(String username) {
        String firstName = thirdSupplierService.testCallAble();
        String lastName = thirdSupplierService.testCallAble2();

        return firstName + lastName;
    }
1
2
3
4
5
6
7

# 查看结果

消耗时间:4065
1

# 第一步优化, 使用 Future 和 线程池 ExecutorService

ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Override
    public String getUserInfo(String username) {

        Callable<String> callable1 = new Callable() {
            @Override
            public Object call() throws Exception {
                return thirdSupplierService.testCallAble(); 该方法大约会调用消耗1s
            }
        };

        Callable<String> callable2 = new Callable() {
            @Override
            public Object call() throws Exception {
                return thirdSupplierService.testCallAble2(); // 该方法大约会调用消耗3s
            }
        };

        Future submit1 = executorService.submit(callable1); 
        Future submit2 = executorService.submit(callable2);

        String result = null;
        try {
            String ob1 = submit1.get().toString();
            String ob2 = submit2.get().toString();
            result = ob1 + ob2;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return result;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 查看执行结果

消耗时间:3059
1

提示

有没有发现,异步调用接口, 消耗时间会接近远程消耗最长时间的接口所用的时间

# 提高系统吞吐量万倍

修改上面Controller中的接口方法


    /**
     * 使用WebAsyncTask 异步返回结果,可以实现提高 tomcat 吞吐量万倍以上
     * todo 该方法可以进一步统一封装
     *
     * @return
     */
    @PostMapping(value = "/throughput")
    public WebAsyncTask<ServiceResult> throughput() {
        System.out.println("吞吐量方法被调用开始;tomcat线程" + Thread.currentThread().getName());
        Callable<ServiceResult> callable = new Callable() {
            @Override
            public Object call() throws Exception {
                ServiceResult serviceResult = new ServiceResult();
                serviceResult.setBody(userService.getUserInfo("kevin"));
                serviceResult.setMessage("请求成功");
                serviceResult.setSuccess(true);
                System.out.println("获取到执行结果,当前线程为" + Thread.currentThread().getName());
                return serviceResult;
            }
        };
        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
        executor.setThreadNamePrefix("MeiCai-");
        // 这里可以使用下面默认配置的方式, 只返回 WebAsyncTask 对象, 这里是为了灵活,所以全都写出来 
        WebAsyncTask<ServiceResult> webAsyncTask = new WebAsyncTask<>(60 * 1000L, executor, callable);

        webAsyncTask.onCompletion(new Runnable() {
            @Override
            public void run() {
                System.out.println("Completion");
            }
        });

        webAsyncTask.onTimeout(new Callable<ServiceResult>() {
            @Override
            public ServiceResult call() throws Exception {
                ServiceResult serviceResult = new ServiceResult();
                System.out.println("Request TimeOut");
                serviceResult.setErrorCode(0);
                serviceResult.setSuccess(false);
                serviceResult.setBody(null);
                serviceResult.setMessage("Request TimeOut");
                return serviceResult;
            }
        });

        System.out.println("吞吐量方法被调用结束;tomcat线程" + Thread.currentThread().getName());
        return webAsyncTask;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 执行结果(tomcat 线程会立即释放, 返回数据则有jvm线程异步返回接口,大大提高了系统吞吐量)

吞吐量方法被调用开始;tomcat线程http-nio-9401-exec-6
吞吐量方法被调用结束;tomcat线程http-nio-9401-exec-6
获取到执行结果,当前线程为MeiCai-1
Completion

1
2
3
4
5

# 通过配置实现WebAsyncTask 异常处理, 并设置线程池控制异步 返回无须每次都创建新线程

 /**
     * 下面是为了提高系统吞吐量 使用WebAsyncTask 异步返回结果,可以实现提高tomcat 吞吐量万倍以上
     * @param configurer
     */
    @Override
    public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
        configurer.setDefaultTimeout(60 * 1000L);
        configurer.registerCallableInterceptors(timeoutInterceptor());
        configurer.setTaskExecutor(threadPoolTaskExecutor());
    }

    @Bean
    public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
        return new TimeoutCallableProcessingInterceptor();
    }

    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();
        t.setCorePoolSize(10);
        t.setMaxPoolSize(50);
        t.setThreadNamePrefix("MeiCai");
        return t;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Controller 层可以直接这样写

注意, 这样写之前要配置上面的配置,不然会每次异步返回都会创建新的线程

 @PostMapping(value = "/throughput")
    public WebAsyncTask<ServiceResult> throughput() {
        System.out.println("吞吐量方法被调用开始;tomcat线程" + Thread.currentThread().getName());
        Callable<ServiceResult> callable = new Callable() {
            @Override
            public Object call() throws Exception {
                ServiceResult serviceResult = new ServiceResult();
                serviceResult.setBody(userService.getUserInfo("kevin"));
                serviceResult.setMessage("请求成功");
                serviceResult.setSuccess(true);
                System.out.println("获取到执行结果,当前线程为" + Thread.currentThread().getName());
                return serviceResult;
            }
        };
        System.out.println("吞吐量方法被调用结束;tomcat线程" + Thread.currentThread().getName());
        return new WebAsyncTask<>(callable);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 总结

是Tomcat的线程 在执行Controller层的代码, Tomcat服务器最大可以创建的线程数是750个线程, 如果太多的线程阻塞在Controller层不释放的话,那么会大大降低系统的吞吐量。 这样就可以使用上面 WebAsyncTask 的方式, 异步返回结果,这样就可以释放tomcat 线程去接收别的用户的请求,就会大大提高系统吞吐量

编辑 (opens new window)
上次更新: 2022/03/13, 21:24:24
优化web 项目性能
优雅写代码一

← 优化web 项目性能 优雅写代码一→

最近更新
01
命令模式 原创
05-03
02
桥接模式 原创
05-02
03
优雅写代码三 原创
04-29
更多文章>
Theme by Memorydoc | Copyright © 2021-2025 Memorydoc | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式