openfeginrestemplate微服务调⽤最佳实践总结
微服务间接⼝调⽤常⽤openfeign或restemplate,两者底层都是通过ribbon+http发起远程调⽤并⽆⼤的区别,主要区别是openfeign较restTemplate功能⽐较齐全
restTemplate微服务调⽤
1 请求增强:增加超时设置,请求拦截增加请求头,响应增加报警
@Bean
@LoadBalanced
RestTemplate getRestTemplate() {
//配置超时必须同时设置连接池,否则调⽤⽅⽤不主动超时,只能⼀直等待服务⽅
RequestConfig requestConfig = RequestConfig.custom()
.tConnectTimeout(connectionRequestTimeout)
.tConnectionRequestTimeout(connectTimeout)
.tSocketTimeout(readTimeout).build();
CloableHttpClient httpClient = ate()
.tMaxConnTotal(maxConnTotal)
.tMaxConnPerRoute(maxConnPerRoute)
.tRetryHandler(new DefaultHttpRequestRetryHandler(retryCount,true))//⼀般配置为微服务部署实例数
.tDefaultRequestConfig(requestConfig)
.build();
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
UTF-8")));
restTemplate.wArrayList(new CommonRestTemplateInterceptor()));//设置⽤户信息请求头
return restTemplate;
}
@Slf4j
public class CommonRestTemplateInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpRespon intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestAttributes();
市级三好学生
if (attributes != null) {//微信等回调该对象为null
HttpServletRequest req = Request();
HttpHeaders headers = Headers();
headers.add("zuul_ur_id", Header("zuul_ur_id")); //拦截restTemplate,请求前设置请求头zuul_ur_id等⽤户信息
headers.add("x_forwarded_ip", Header("x_forwarded_ip"));
}
ClientHttpRespon respon = ute(request, body);
if (!StatusCode().equals(HttpStatus.OK)) {
<("restTemplate服务调⽤异常",StatusText());
MonitorUtils.ndDingdingMsg("restTemplate服务调⽤异常,"+StatusText());
}
return respon;
}
}
2.接⼝管理: 远程调⽤接⼝URL抽取到常量类或枚举统⼀管理,并放置到common通⽤依赖,⽅便重复使⽤,全局修改等
ResultEntity entity = ForObject("ur/version/latest?apkType=1, ResultEntity.class);
public class XXApplicationServiceUrl {
public String getLatestVersionUrl="ur/version/latest";
public String getLatestVersionUrl2="ur/version/latest2";
public String getLatestVersionUrl3="ur/version/latest3";
}
大学计划书
openfeign微服务调⽤
1.N多的feature
①请求超时,注意restTemplate不识别该配置项,是在配置类中设置
ribbon:
ReadTimeout: 2000 #⽆效,通过adTimeout⾃定义配置项控制
ConnectTimeout: 1000 #⽆效,通过tTimeout⾃定义配置项控制
②请求拦截增加请求头,注意@FeignClient注解指定⾃定义拦截器
//实现feign的请求拦截器并在feign调⽤配置,@FeignClient(name = "capability-register", fallback = ApiServiceClientFallBack.class ,configuration = XXXXConfigurat
@Configuration
public class XXXXConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestAttributes();
HttpServletRequest request = Request();
requestTemplate.header("Token", Header("Token"));
}
}
③请求与响应压缩,数据较⼤,压缩率⾼数据建议开启
#feign 请求与响应的压缩
④feign调⽤http⽇志,注意设置feignclient配置⽇志级别为debug
@Configuration
public class FeignLogConfig {
/**
* ⽇志level有4个级别
* 1.NONE,不记录任何⽇志
* 2.BASIC,仅记录请求⽅法、URL以及响应状态码和执⾏时间
* 3.HEADRES,除了BASIC以外的还会记录请求和响应的头信息
* 4.FULL,所有
* @return
*/
@Bean
Logger.Level feignLogger(){
return Logger.Level.FULL;
}
}
logging.level:
root: info
⑤降级-退⽽求其次,编写接⼝实现类,@FeignClient指定该降级实现 ,需要abled=true开启降级
@Component
@FeignClient(value = "ur",fallback = XXApplicationFallbackFeginService.class)
public interface XXApplicationFeginService {
@GetMapping("/version/latest")
ResultEntity getLatestVersion(@RequestParam(defaultValue = "1") String apkType);
@GetMapping("/version/latest2")
ResultEntity getLatestVersion2(@RequestParam(defaultValue = "1") String apkType);
@GetMapping("/version/latest3")
ResultEntity getLatestVersion3(@RequestParam(defaultValue = "1") String apkType);
}
@Service
public class XXApplicationFallbackFeginService implements XXApplicationFeginService{
@Override
public ResultEntity getLatestVersion(@RequestParam(defaultValue = "1") String apkType){
return ResultEntity.fail("降级返回");
}
@Override
public ResultEntity getLatestVersion2(String apkType) {
return null;
}
@Override
public ResultEntity getLatestVersion3(String apkType) {
return null;
}
;
}
⑥熔断测试,abled=true开启熔断,降级,熔断都会进⼊fallback实现,100请求达到50%超时10ms或服务不可达即开启熔断,5s⼀次探测请求,测试⼯具:ab秦始皇女儿
#熔断器配置
hystrix:
command:
default: #default指路由的所有下级服务都使⽤相同默认的熔断配置,可指定具体服务具体配置如payment,defulat=>payment
execution:
isolation:
strategy: SEMAPHORE #默认THREAD,⽹关⾼扇出适合信号量
thread:
timeoutInMilliconds: 10 #实现HystrixComand即的run(..业务代码..)⽅法的超时时间
maphore:
maxConcurrentRequests: 200 #允许信号量1000并发-压测
circuitBreaker:
errorThresholdPercentage: 50 #错误或超时50%时开启熔断器
sleepWindowInMilliconds: 5000 #//熔断器中断请求5秒后会进⼊半打开状态,放部分流量去正常请求,成功则关闭熔断器
requestVolumeThreshold: 100 #⾄少有100个请求并且达到错误阈值才会判断是否打开熔断器
ab -c 311 -n 511 -H "JhY2Nlc3NUeXBlIjoiMSIsImlzQWRtaW4iOiIxIiwidXNlcklkIjoiN2RhMDUxMWUwZWI4⑦修改feingClient 默认httpClient,修改为okHttp进⾏并发测试
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>11.0</version>
</dependency>
abled=fal
abled=true
/**
* 配置okhttp与连接池
* ConnectionPool默认创建5个线程,保持5分钟长连接
*/
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class OkHttpConfig {
@Bean
pbso4public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
//设置连接超时雨的声音作文
.connectTimeout(10 , TimeUnit.SECONDS)
以私废公/
/设置读超时
.readTimeout(10 , TimeUnit.SECONDS)
//设置写超时
.writeTimeout(10 , TimeUnit.SECONDS)
//是否⾃动重连
家庭披萨.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool(10 , 5L, TimeUnit.MINUTES))
.build();
}
}
测试结论:okhttp有连接池,⾼并发时,okHttp多次测试均优于httpClient,符合预期
httpClient
________________________________________
50% 965
66% 1316
75% 1444
80% 1598
90% 1994
95% 2425
98% 2805
哑鼓
99% 3214
100% 4711 (longest request)
okHttp
___________________________________________
50% 1002
66% 1290
75% 1403
80% 1525
90% 1847
95% 2223
98% 2726
99% 3163
100% 3703 (longest request)
2.接⼝管理:同样放置common通⽤依赖,但注意开启时指定扫描路径 @EnableFeignClients(baPackages = "com.")