今天 在开发的时候,开发环境都 注册到服务中心,但是有些开发同事服务是不可用的,但是又设置了服务保护机制,实例仍然是up 的,在本地进行开发的时候,可以使用eureka.server.enable-self-preservation=false参数来关闭保护机制,以确保注册中心可以将不可用的实例正确剔除,因为有同事不关心这个,直接默认配置都是true,导致线上问题,就需要改变一下,如果发现服务实例不可用,或者异常自动转发其它实例上再执行,
首生要加包 springooot 依赖的其它包就不贴出来了,主要容断器的包要添加上去
org.springframework.cloud
spring-cloud-starter-hystrix
在启动服务类里面,需要加些参数 SpringApplication.run(YitaiTMSApplication.class, args);
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
@Import(FdfsClientConfig.class)//可以拥有带有连接池的FastDFS Java客户端
@EnableTransactionManagement
@ServletComponentScan
@MapperScan("com.yitai.tms.*.dao")
@SpringBootApplication
@EnableEurekaClient
@EnableScheduling
@EnableDiscoveryClient
@EnableHystrix
public class YitaiTMSApplication {
public static void main(String[] args) {
SpringApplication.run(YitaiTMSApplication.class, args);
}
//@EnableHystrix 这个是必须的, 开户容断器
// @Primary 这个不是必须的,这个注入是如果注入相同实例,有这个关键字就优先注入
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setReadTimeout(4000);
httpRequestFactory.setConnectTimeout(4000);
return new RestTemplate(httpRequestFactory);
}
// 设置访问时间和连接超时时间,默认的时间太长,配置后可以有效时间内转发服务注册实例请求
接下来是配置文件 application.yml
#开启hystrix功能 这个功能是 feign方式调用秘,ribbon的配置与feign整合后配置设置参数一样
feign:
hystrix:
enabled: true
#tms-mrg: 如果加上这个配置,说明指定的微服务开启重试功能,不是自己的微服务名称,相当如局部服务重试
ribbon:
# 同一实例最大重试次数,不包括首次调用,配置后本实例至少会执行两次
MaxAutoRetries: 1
# 重试其他实例的最大重试次数,不包括首次所选的server,配置后本实例和其它服务注册实例至少会执行两次
MaxAutoRetriesNextServer: 2
# 是否所有操作都进行重试
OkToRetryOnAllOperations: false #默认为false,则只允许GET请求被重试
#如果此设置关闭, 所有重试机制都失效,注意:全局重试如局部重试开启,是本服务调用的所有微服务都开启重试,配置局部微服务名称才启作用此称为局部重试机制
#下面两个时间我是指定在服务启动时设置的,如果不指定就在这里设置
ReadTimeout: 5000 #请求时间,这个配置容断器的时间,必须小于容断器设置的时间才能触发重试
ConnectTimeout: 2000 # 服务连接时间
对时间有特殊要求可以配置下面两个,
#开户服务重试机制,默认是关闭,但是,开启OkToRetryOnAllOperations后,不配也行
cloud:
loadbalancer:
retry:
enabled: true
#这是容断器的时间 必须大于请求时间才能触发重试,容断器没有超时肯定不会去重试
hystrix:
command:
default:
execution:
# timeout:
# enabled:true
isolation:
thread:
timeoutInMilliseconds:1000
配置超时时间,默认是开启超时时间,这里有设置超时时间是1秒触发容断,默认是5秒
下面是配置的代码
/**
*
* @param post请求方式, 直接封装json传递参数
* @return 特别说明 ,容断器的回调函数必须与注入的容断函数保持一致,返回参数必须一致
*/
@HystrixCommand(fallbackMethod="postDataFallback")
private JSONObject postData(JSONObject jsonObj,String urls){
if (StringUtils.isBlank(urls)) {
return null;
}
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
HttpEntity formEntity = new HttpEntity(jsonObj.toString(), headers);
String result = restTemplate.postForObject(urls, formEntity, String.class);
JSONObject results = JSONObject.parseObject(result);
/*if (results.getIntValue("code") == 0){
results.getString("data");
}else{
results.put("code", 1);
}*/
return results;
}
//调用超时和不可用的时候执行的方法,返回参数与 提交参数一致尽可,无参数也可行
//返回参数必须和注入的方法一致 所以下面方法这样写是不会回调的
public void postDataFallback(JSONObject jsonObj,String url) {
logger.debug("服务注册中心返回失败"+url.toString());
//return "fallback";
}
正确方法应该如下
public JSONObject postDataFallback(JSONObject jsonObj, String url) {
logger.debug("服务注册中心返回失败" + url.toString());
System.out.println("**************************** "+url.toString());
return new JSONObject();
}
GET请求方式的熔断返回
@HystrixCommand(fallbackMethod = "getDataFallback")
private JSONObject getData(String url) {
// String url = "http://tms-mgr-ssss/jhb/waybill/updateStatus?vin=" + urls+
// "&fromTime=" + urls;
if (StringUtils.isBlank(url)) {
return null;
}
JSONObject result = JSONObject.parseObject(restTemplate.getForObject(url, String.class));
if (result.getIntValue("code") == 0) {
result.getString("data");
} else {
result = new JSONObject();
result.put("code", 1);
}
return result;
}
正确方法应该如下
JSONObject getDataFallback(String urls) {
System.out.println("____________________________________");
logger.debug("服务注册中心返回失败"+url.toString());
return new JSONObject();
}
服务请求这里后面再研究了下,配置有很大关系 重点 OkToRetryOnAllOperations 开启所有请求重试
基于HTTP响应码重试
clientName:
ribbon:
retryableStatusCodes: 404,502
注意点:
一般来说,不建议将ribbon.OkToRetryOnAllOperations 设为true。
因为一旦启用该配置,则表示重试任何操作,包括POST请求,而由于缓存了请求体,此时可能会影响服务器的资源。
此结论有待验证,之前结论里是说重试 GET请求
方法参数可以知道调用哪个服务不可用,会打印出IP地址,进行排查,当然不会抛出异常,相当能 try catch处理过,显示不可用的服务实例IP 如 192.168.11.88:3020 等详细信息。
那么断路器是在什么情况下开始起作用呢?这里涉及到断路器的三个重要参数:快照时间窗、请求总数下限、错误百分比下限。这个参数的作用分别是:
下面容断的返回值必须一致 其它配置都默认就可以,只需要改变一下配置容断超时时间就OK,被坑过
@GetMapping("/getelf")
@HystrixCommand(fallbackMethod="fallbackTest")
public JSONObject elfste(String urls){
urls="http://microservice-elefdata-service/getelefdata/test";
JSONObject result = JSONObject.parseObject(restTemplate.getForObject(url, String.class));
return result;
}
JSONObject fallbackTest(String urls) {
System.out.println("____________________________________");
logger.debug("服务注册中心返回失败"+url.toString());
return new JSONObject();
}
服务注册中心的服务实例转发,并不能保证全部都会转发到正常服务实例中去,偶尔会去不可用的服务实例,可能这是为了容错性的而做的策略,尝试去执行一次,如果服务可用下次请求就可能会自动落到此实例,
那么当断路器打开之后会发生什么呢?我们先来说说断路器未打开之前,对于之前那个示例的情况就是每个请求都会在当hystrix超时之后返回fallback
,每个请求时间延迟就是近似hystrix的超时时间,如果设置为5秒,那么每个请求就都要延迟5秒才会返回。当熔断器在10秒内发现请求总数超过20,并且错误百分比超过50%,这个时候熔断器打开。打开之后,再有请求调用的时候,将不会调用主逻辑,而是直接调用降级逻辑,这个时候就不会等待5秒之后才返回fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
今天重试和容断器总结
启动微服务时 注入的方法
1 @EnableHystrix 与 @EnableCircuitBreaker 效果一样, 前者包含后者
2 @HystrixCommand(fallbackMethod="fallbackTest") 里面的方法返回类型必须一致, 代码如上
3 配置重试机制 关键点 OkToRetryOnAllOperations: false 默认关闭,true开启就会自动重试,参数配置如上,下面是再次强调
tms-mgr:
ribbon:
# 同一实例最大重试次数,不包括首次调用,配置后本实例至少会执行两次
MaxAutoRetries: 1
开启局部微服务重试机制 必须加上指定的微服务
还有更多功能没有挖掘,学习的道路还有很长
参考 资料 https://www.jb51.net/article/129336.htm