断路器:https://martinfowler.com/bliki/CircutiBreaker.html
核心思想:
在断路器对象中封装受保护的方法调用。
该断路器监控调用和断路情况
调用失败触发阈值后,后续调用直接由短路器返回错误,不再执行实际调用。
理解:
客户端通过circuit breaker调用服务提供者,正常的时候可以调用。如果服务提供方出现了问题,发生了超时, 前几次可以超时处理, 到达一个阀值可以通过断路器进行处理, 就不再向服务方发起请求。
importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.atomic.AtomicInteger;
@Aspect
@Component
@Slf4jpublic classCircuitBreakerAspect {//阀值
private static final Integer THRESHOLD = 3;//记录失败的次数
private Map counter = new ConcurrentHashMap<>();//记录被保护的次数
private Map breakCounter = new ConcurrentHashMap<>();/***
*@parampjp 程序连接点
*@return*@throwsThrowable*/@Around("execution(* 拦截的区域")public Object doWithCircuitBreaker(ProceedingJoinPoint pjp) throwsThrowable {//获取当前执行的方法
String signature =pjp.getSignature().toLongString();
log.info("Invoke {}", signature);
Object retVal;try{if(counter.containsKey(signature)) {//失败次数达到预制,如果保护次数没到,返回null
if (counter.get(signature).get() > THRESHOLD &&breakCounter.get(signature).get()
log.warn("Circuit breaker return null, break {} times.",
breakCounter.get(signature).incrementAndGet());return null;
}
}else{
counter.put(signature,new AtomicInteger(0));
breakCounter.put(signature,new AtomicInteger(0));
}
retVal=pjp.proceed();
counter.get(signature).set(0);
breakCounter.get(signature).set(0);
}catch(Throwable t) {
log.warn("Circuit breaker counter: {}, Throwable {}",
counter.get(signature).incrementAndGet(), t.getMessage());
breakCounter.get(signature).set(0);throwt;
}returnretVal;
}
}
Hystrix
Hystrix [hɪst'rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。本文所说的Hystrix是Netflix开源的一款容错框架,同样具有自我保护能力。为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。
Hystrix设计目标:
对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的
阻止故障的连锁反应
快速失败并迅速恢复
回退并优雅降级
提供近实时的监控

实现了断路服务器模式
在需要服务熔断的方法上添加@HystrixCommand注解, fallbackMethod指定熔断的地址,默认情况下@HystrixCommand是在另外一个线程执行的。可以做一些超时的处理。
@HystrixProperty(name="excution.isolation.strategy",value="SEMAPHORE")设置为信号
Hystrix配置项参考:
Spring cloud 支持
spring-cloud-starter-netfixi-hystrix
@EnableCircuitBreaker
Feign支持
feign.hystrix.enable=true
@FeignClient
fallback / fallbackFactory
简单示例:
pom引入
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
application.properties
feign.client.config.default.connect-timeout=500
feign.client.config.default.read-timeout=500
#开启feign支持
feign.hystrix.enabled=true
#cousul连接配置
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.prefer-ip-address=true
bootstarp.properties
spring.application.name=name-service
开启注解:
@EnableDiscoveryClient // 注册发现服务
@EnableFeignClients // feign的支持
@EnableCircuitBreaker // feignClient的演示
//Spring cloud 支持
@PostMapping("/order")
@HystrixCommand(fallbackMethod= "fallbackCreateOrder")publicCoffeeOrder createOrder() {/*业务代码*/
returnorder;
}publicCoffeeOrder fallbackCreateOrder() {
log.warn("Fallback to NULL order.");return null;
}
//FeignClient 的支持
importorg.springframework.cloud.openfeign.FeignClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestParam;importjava.util.List;
@FeignClient(name= "waiter-service", contextId = "coffee",
qualifier= "coffeeService", path="/coffee",
fallback= FallbackCoffeeService.class)//如果用了Fallback,不要在接口上加@RequestMapping,path可以用在这里
public interfaceTestService {
@GetMapping("/{id}")
Product getById(@PathVariable Long id);
}/*实现TestService*/
importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importjava.util.Collections;importjava.util.List;
@Slf4j
@Componentpublic class FallbackTestService implementsTestService{
@OverridepublicProduct getById(Long id) {/**发送了垄断的逻辑代码*/
return null;
}
}/**Controller调用*/@GetMapping("testGetById")publicString testGetById() {
TestService.getById((long) 1);return "";
}