基于springcloud異步線(xiàn)程池、高并發(fā)請(qǐng)求feign的解決方案
ScenTaskTestApplication.java
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author scen
* @version 2018年9月27日 上午11:51:04
*/
@EnableFeignClients
@SpringBootApplication
public class ScenTaskTestApplication {
public static void main(String[] args) {
SpringApplication.run(ScenTaskTestApplication.class, args);
}
}
application.properties
spring.application.name=scen-task-test
server.port=9009
feign.hystrix.enabled=true
#熔斷器失敗的個(gè)數(shù)==進(jìn)入熔斷器的請(qǐng)求達(dá)到1000時(shí)服務(wù)降級(jí)(之后的請(qǐng)求直接進(jìn)入熔斷器)
hystrix.command.default.circuitBreaker.requestVolumeThreshold=1000
#回退最大線(xiàn)程數(shù)
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=50
#核心線(xiàn)程池?cái)?shù)量
hystrix.threadpool.default.coreSize=130
#請(qǐng)求處理的超時(shí)時(shí)間
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
ribbon.ReadTimeout=120000
#請(qǐng)求連接的超時(shí)時(shí)間
ribbon.ConnectTimeout=130000
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${server.port}}
eureka.instance.preferIpAddress=true
eureka.client.service-url.defaultZone=http://127.0.0.1:9000/eureka
logging.level.com.test.user.service=debug
logging.level.org.springframework.boot=debug
logging.level.custom=info
AsyncConfig.java
package com.test;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* springboot異步線(xiàn)程池配置
* @author Scen
* @date 2018/11/7 18:28
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
//定義線(xiàn)程池
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//核心線(xiàn)程數(shù)
taskExecutor.setCorePoolSize(20);
//線(xiàn)程池最大線(xiàn)程數(shù)
taskExecutor.setMaxPoolSize(100);
//線(xiàn)程隊(duì)列最大線(xiàn)程數(shù)
taskExecutor.setQueueCapacity(10);
//初始化
taskExecutor.initialize();
return taskExecutor;
}
}
DoTaskClass.java
package com.test;
import com.test.pojo.User;
import com.test.pojo.UserEducation;
import com.test.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 任務(wù)類(lèi) 定義異步工作任務(wù)
* @author Scen
* @date 2018/11/7 18:40
*/
@Component
public class DoTaskClass {
/**
* 一個(gè)feign的客戶(hù)端
*/
private final UserService userService;
@Autowired
public DoTaskClass(UserService userService) {
this.userService = userService;
}
/**
* 核心任務(wù)
*
* @param uid
*/
@Async
public void dotask(String uid) {
/**
* 模擬復(fù)雜工作業(yè)務(wù)(109個(gè)線(xiàn)程同時(shí)通過(guò)feign請(qǐng)求微服務(wù)提供者)
*/
{
List<UserEducation> userEducationByUid = userService.findUserEducationByUid(uid);
List<String> blackList = userService.getBlackList();
String userSkilled = userService.getUserSkilled(uid);
String userFollow = userService.getUserFollow(uid);
User userById = userService.getUserById(uid);
List<String> followList = userService.getFollowList(uid);
int userActivityScore = userService.getUserActivityScore(uid);
}
// 打印線(xiàn)程名稱(chēng)分辨是否為多線(xiàn)程操作
System.out.println(Thread.currentThread().getName() + "===任務(wù)" + uid + "執(zhí)行完成===");
}
}
TestController.java
package com.test;
import com.test.pojo.User;
import com.test.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 測(cè)試案例
* @author Scen
* @date 2018/11/7 18:10
*/
@RestController
public class TestController {
/**
* 此處僅用此feign客戶(hù)端請(qǐng)求微服務(wù)獲取核心工作所需參數(shù)
*/
private final UserService userService;
/**
* 核心工作異步算法
*/
private final DoTaskClass doTaskClass;
@Autowired
public TestController(DoTaskClass doTaskClass, UserService userService) {
this.doTaskClass = doTaskClass;
this.userService = userService;
}
/**
* 手動(dòng)觸發(fā)工作
* @throws InterruptedException
*/
@RequestMapping("/test")
public void task() throws InterruptedException {
/*
取到1000個(gè)要執(zhí)行任務(wù)的必備參數(shù)
*/
List<User> userList = userService.findAllLite(1, 1000);
for (int i = 0; i < userList.size(); i++) {
try {
// 異步線(xiàn)程開(kāi)始工作
doTaskClass.dotask(userList.get(i).getId());
} catch (Exception e) {
/*
若并發(fā)線(xiàn)程數(shù)達(dá)到MaxPoolSize+QueueCapacity=110(參考AsyncConfig配置)會(huì)進(jìn)入catch代碼塊
i--休眠3秒后重試(嘗試進(jìn)入線(xiàn)程隊(duì)列:當(dāng)且僅當(dāng)109個(gè)線(xiàn)程有一個(gè)或多個(gè)線(xiàn)程完成異步任務(wù)時(shí)重試成功)
*/
i--;
Thread.sleep(3000*3);
}
System.out.println(i);
}
}
}
相關(guān)線(xiàn)程池、超時(shí)時(shí)間等數(shù)量和大小按實(shí)際業(yè)務(wù)配置
補(bǔ)充:SpringCloud關(guān)于@FeignClient和Hystrix集成對(duì)http線(xiàn)程池監(jiān)控問(wèn)題
@FeignClient可以作為Http代理訪(fǎng)問(wèn)其他微服務(wù)節(jié)點(diǎn),可以用apache的httpclient替換@FeignClient原生的URLConnection請(qǐng)求方式,以達(dá)到讓http請(qǐng)求走Http線(xiàn)程池的目的。
而@FeignClient和hystrix集成之后,在hystrix dashboard上可以監(jiān)控到 @FeignClient 中接口調(diào)用情況和 @FeignClient 中httpclient中線(xiàn)程池使用狀況。
下面是demo的示例:
1、@FeignClient的接口代碼如下:
@FeignClient(value="service-A", fallback=ServiceClientHystrix.class)
public interface ServiceClient {
@RequestMapping(method = RequestMethod.GET, value = "/add/{id}")
String add(@PathVariable("id") Integer id);
}
2、ServiceClientHystrix.java
@Component
public class ServiceClientHystrix implements ServiceClient{
@Override
public String add(Integer id) {
return "add value from ServiceClientHystrix";
}
}
3、關(guān)于@FeignClient和hystrix
集成后,Http線(xiàn)程池配置如下:
hystrix.threadpool.服務(wù)實(shí)例ID.參數(shù)
例如設(shè)置httpclient的線(xiàn)程池最大線(xiàn)程數(shù)量
hystrix.threadpool.service-A.coreSize=20//默認(rèn)是hystrix.threadpool.default.coreSize = 10 hystrix.threadpool.service-A.maximumSize=20//默認(rèn)是hystrix.threadpool.default.maximumSize = 10
啟動(dòng)服務(wù)后用測(cè)試用例連續(xù)調(diào)用接口測(cè)試,用hystrix dashboard
監(jiān)控得到下圖監(jiān)控效果:

去掉hystrix.threadpool.服務(wù)實(shí)例ID.參數(shù)配置后,再次用測(cè)試用例調(diào)用接口得到監(jiān)控如下圖:

PoolSize的大小取決于hystrix.threadpool.服務(wù)實(shí)例ID.coreSize大小設(shè)置
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
java實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
SpringBoot+slf4j實(shí)現(xiàn)全鏈路調(diào)用日志跟蹤的方法(一)
本文重點(diǎn)給大家介紹Tracer集成的slf4j MDC功能,方便用戶(hù)在只簡(jiǎn)單修改日志配置文件的前提下輸出當(dāng)前 Tracer 上下文 TraceId,文章通過(guò)代碼給大家講解了在springboot中使用的技巧,感興趣的朋友跟隨小編一起看看吧2021-05-05
Java?深入探究講解簡(jiǎn)單工廠(chǎng)模式
簡(jiǎn)單工廠(chǎng)模式是屬于創(chuàng)建型模式,又叫做靜態(tài)工廠(chǎng)方法(Static Factory Method)模式,但不屬于23種GOF設(shè)計(jì)模式之一。簡(jiǎn)單工廠(chǎng)模式是由一個(gè)工廠(chǎng)對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類(lèi)的實(shí)例。簡(jiǎn)單工廠(chǎng)模式是工廠(chǎng)模式家族中最簡(jiǎn)單實(shí)用的模式,可以理解為是不同工廠(chǎng)模式的一個(gè)特殊實(shí)現(xiàn)2022-04-04
SpringBoot對(duì)Filter過(guò)濾器中的異常進(jìn)行全局處理方案詳解
這篇文章主要介紹了SpringBoot對(duì)Filter過(guò)濾器中的異常進(jìn)行全局處理,在SpringBoot中我們通過(guò) @ControllerAdvice 注解和 @ExceptionHandler注解注冊(cè)了全局異常處理器,需要的朋友可以參考下2023-09-09
微信開(kāi)發(fā)準(zhǔn)備第二步 springmvc mybatis項(xiàng)目結(jié)構(gòu)搭建
這篇文章主要為大家詳細(xì)介紹了微信開(kāi)發(fā)準(zhǔn)備第二步,springmvc和mybatis項(xiàng)目結(jié)構(gòu)的搭建,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
SpringBoot+MySQL實(shí)現(xiàn)讀寫(xiě)分離的多種具體方案
在高并發(fā)和大數(shù)據(jù)量的場(chǎng)景下,數(shù)據(jù)庫(kù)成為了系統(tǒng)的瓶頸。為了提高數(shù)據(jù)庫(kù)的處理能力和性能,讀寫(xiě)分離成為了一種常用的解決方案,本文將介紹在Spring?Boot項(xiàng)目中實(shí)現(xiàn)MySQL數(shù)據(jù)庫(kù)讀寫(xiě)分離的多種具體方案,需要的朋友可以參考下2023-06-06
SpringAnimation 實(shí)現(xiàn)菜單從頂部彈出從底部消失動(dòng)畫(huà)效果
最近做項(xiàng)目遇到這樣一個(gè)需求,要求實(shí)現(xiàn)一種菜單,菜單從頂部彈入,然后從底部消失,頂部彈入時(shí),有一個(gè)上下抖動(dòng)的過(guò)程,底部消失時(shí),先向上滑動(dòng),然后再向下滑動(dòng)消失。下面給大家?guī)?lái)了實(shí)現(xiàn)代碼,感興趣的朋友一起看看吧2018-05-05

