基于springcloud异步线程池、高并发请求feign的解决方案

时间:2022-08-25 00:01:47

ScenTaskTestApplication.java

  1. package com.test;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.openfeign.EnableFeignClients;
  5. /**
  6. * @author scen
  7. * @version 2018年9月27日 上午11:51:04
  8. */
  9. @EnableFeignClients
  10. @SpringBootApplication
  11. public class ScenTaskTestApplication {
  12. public static void main(String[] args) {
  13. SpringApplication.run(ScenTaskTestApplication.class, args);
  14. }
  15. }

application.properties

  1. spring.application.name=scen-task-test
  2. server.port=9009
  3. feign.hystrix.enabled=true
  4. #熔断器失败的个数==进入熔断器的请求达到1000时服务降级(之后的请求直接进入熔断器)
  5. hystrix.command.default.circuitBreaker.requestVolumeThreshold=1000
  6. #回退最大线程数
  7. hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=50
  8. #核心线程池数量
  9. hystrix.threadpool.default.coreSize=130
  10. #请求处理的超时时间
  11. hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
  12. ribbon.ReadTimeout=120000
  13. #请求连接的超时时间
  14. ribbon.ConnectTimeout=130000
  15. eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${server.port}}
  16. eureka.instance.preferIpAddress=true
  17. eureka.client.service-url.defaultZone=http://127.0.0.1:9000/eureka
  18. logging.level.com.test.user.service=debug
  19. logging.level.org.springframework.boot=debug
  20. logging.level.custom=info

AsyncConfig.java

  1. package com.test;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.scheduling.annotation.AsyncConfigurer;
  4. import org.springframework.scheduling.annotation.EnableAsync;
  5. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  6. import java.util.concurrent.Executor;
  7. /**
  8. * springboot异步线程池配置
  9. * @author Scen
  10. * @date 2018/11/7 18:28
  11. */
  12. @Configuration
  13. @EnableAsync
  14. public class AsyncConfig implements AsyncConfigurer {
  15.  
  16. @Override
  17. public Executor getAsyncExecutor() {
  18. //定义线程池
  19. ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
  20. //核心线程数
  21. taskExecutor.setCorePoolSize(20);
  22. //线程池最大线程数
  23. taskExecutor.setMaxPoolSize(100);
  24. //线程队列最大线程数
  25. taskExecutor.setQueueCapacity(10);
  26. //初始化
  27. taskExecutor.initialize();
  28. return taskExecutor;
  29. }
  30. }

DoTaskClass.java

  1. package com.test;
  2. import com.test.pojo.User;
  3. import com.test.pojo.UserEducation;
  4. import com.test.user.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.scheduling.annotation.Async;
  7. import org.springframework.stereotype.Component;
  8. import java.util.List;
  9. /**
  10. * 任务类 定义异步工作任务
  11. * @author Scen
  12. * @date 2018/11/7 18:40
  13. */
  14. @Component
  15. public class DoTaskClass {
  16. /**
  17. * 一个feign的客户端
  18. */
  19. private final UserService userService;
  20.  
  21. @Autowired
  22. public DoTaskClass(UserService userService) {
  23. this.userService = userService;
  24. }
  25.  
  26. /**
  27. * 核心任务
  28. *
  29. * @param uid
  30. */
  31. @Async
  32. public void dotask(String uid) {
  33. /**
  34. * 模拟复杂工作业务(109个线程同时通过feign请求微服务提供者)
  35. */
  36. {
  37. List<UserEducation> userEducationByUid = userService.findUserEducationByUid(uid);
  38. List<String> blackList = userService.getBlackList();
  39. String userSkilled = userService.getUserSkilled(uid);
  40. String userFollow = userService.getUserFollow(uid);
  41. User userById = userService.getUserById(uid);
  42. List<String> followList = userService.getFollowList(uid);
  43. int userActivityScore = userService.getUserActivityScore(uid);
  44. }
  45. // 打印线程名称分辨是否为多线程操作
  46. System.out.println(Thread.currentThread().getName() + "===任务" + uid + "执行完成===");
  47. }
  48. }

TestController.java

  1. package com.test;
  2. import com.test.pojo.User;
  3. import com.test.user.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import java.util.List;
  8. /**
  9. * 测试案例
  10. * @author Scen
  11. * @date 2018/11/7 18:10
  12. */
  13. @RestController
  14. public class TestController {
  15.  
  16. /**
  17. * 此处仅用此feign客户端请求微服务获取核心工作所需参数
  18. */
  19. private final UserService userService;
  20.  
  21. /**
  22. * 核心工作异步算法
  23. */
  24. private final DoTaskClass doTaskClass;
  25.  
  26. @Autowired
  27. public TestController(DoTaskClass doTaskClass, UserService userService) {
  28. this.doTaskClass = doTaskClass;
  29. this.userService = userService;
  30. }
  31.  
  32. /**
  33. * 手动触发工作
  34. * @throws InterruptedException
  35. */
  36. @RequestMapping("/test")
  37. public void task() throws InterruptedException {
  38. /*
  39. 取到1000个要执行任务的必备参数
  40. */
  41. List<User> userList = userService.findAllLite(1, 1000);
  42. for (int i = 0; i < userList.size(); i++) {
  43. try {
  44. // 异步线程开始工作
  45. doTaskClass.dotask(userList.get(i).getId());
  46. } catch (Exception e) {
  47. /*
  48. 若并发线程数达到MaxPoolSize+QueueCapacity=110(参考AsyncConfig配置)会进入catch代码块
  49. i--休眠3秒后重试(尝试进入线程队列:当且仅当109个线程有一个或多个线程完成异步任务时重试成功)
  50. */
  51. i--;
  52. Thread.sleep(3000*3);
  53. }
  54. System.out.println(i);
  55. }
  56. }
  57. }

相关线程池、超时时间等数量和大小按实际业务配置

补充:SpringCloud关于@FeignClient和Hystrix集成对http线程池监控问题

@FeignClient可以作为Http代理访问其他微服务节点,可以用apache的httpclient替换@FeignClient原生的URLConnection请求方式,以达到让http请求走Http线程池的目的。

而@FeignClient和hystrix集成之后,在hystrix dashboard上可以监控到 @FeignClient 中接口调用情况和 @FeignClient 中httpclient中线程池使用状况。

下面是demo的示例:

1、@FeignClient的接口代码如下:

  1. @FeignClient(value="service-A", fallback=ServiceClientHystrix.class)
  2. public interface ServiceClient {
  3. @RequestMapping(method = RequestMethod.GET, value = "/add/{id}")
  4. String add(@PathVariable("id") Integer id);
  5. }

2、ServiceClientHystrix.java

  1. @Component
  2. public class ServiceClientHystrix implements ServiceClient{
  3. @Override
  4. public String add(Integer id) {
  5. return "add value from ServiceClientHystrix";
  6. }
  7. }

3、关于@FeignClient和hystrix

集成后,Http线程池配置如下:

hystrix.threadpool.服务实例ID.参数

例如设置httpclient的线程池最大线程数量

  1. hystrix.threadpool.service-A.coreSize=20//默认是hystrix.threadpool.default.coreSize = 10
  2. hystrix.threadpool.service-A.maximumSize=20//默认是hystrix.threadpool.default.maximumSize = 10

启动服务后用测试用例连续调用接口测试,用hystrix dashboard

监控得到下图监控效果:

基于springcloud异步线程池、高并发请求feign的解决方案

去掉hystrix.threadpool.服务实例ID.参数配置后,再次用测试用例调用接口得到监控如下图:

基于springcloud异步线程池、高并发请求feign的解决方案

PoolSize的大小取决于hystrix.threadpool.服务实例ID.coreSize大小设置

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

原文链接:https://blog.csdn.net/weixin_43504713/article/details/83859014