一.Hystrix
1.Hystrix介绍
Hystrix是一个延迟和容错库,旨在隔离远程系统、服务和第三方库的访问点,停止级联故障,并在不可避免的复杂分布式系统中启用弹性。
2.Hystrix解决的问题
2.1正常情况下
当一切正常时,请求流可能是这样的:
2.2发生故障时
当后端系统之一发生故障时,它可以阻止整个用户请求:
2.3Hystrix解决方案
- 线程隔离, Hystrix给每个服务设置独立的线程池, 和主应用服务器的线程池进行隔离, 同时, 多个服务之间的线程池进行隔离;
- 服务的降级和熔断, 服务降级是指当服务繁忙时,如果服务出现异常,不是粗暴的直接报错,而是返回一个友好的提示,虽然拒绝了用户的访问,但是会返回一个友好的结果; 熔断是服务调用失败次数达到阈值时, Hystrix会主动将服务熔断, 停止服务, 而当情况好转之后, 可以自动重连(弹性).
3.服务降级
应该在服务消费者方使用(demo-consumer), 服务降级发生的情况:
1.超时, 默认是1秒,
2.抛出异常
3.1添加依赖
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
3.2配置启动类注解
//@SpringBootApplication
//@EnableDiscoveryClient
//@EnableCircuitBreaker
@SpringCloudApplication
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
}
}
3.3代码
@Service
@DefaultProperties(defaultFallback = "fallback")
public class DemoService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public ResponseEntity userList(List<Integer> ids) {
List<User> list = new ArrayList<>();
for (Integer id : ids) {
// 直接将服务名写入路径, Ribbon会通过拦截器解析
String url = "http://demo-provider/user/" + id;
User user = restTemplate.getForObject(url, User.class);
list.add(user);
}
return ResponseEntity.ok(list);
}
// 如果单独指定(fallbackMethod), fallback方法和目标方法的要求:
// 返回值类型一致
// 参数列表一致
// 如果是默认的fallback, 要求没有参数列表
public ResponseEntity fallback() {
// ResponseEntity.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
return ResponseEntity.ok("服务器繁忙, 请稍后重试...");
}
}
3.4全局配置超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000 # 配置Hystrix的全局超时时间
Hystrix的超时时间应该大于重试的超时时间, 否则重试无效.
4.服务熔断
当确定服务无效时, 需要快速失败, 将服务暂时停止. 同时, 要在指定的时间后继续尝试重新访问, 如果故障解决, 服务继续生效.
4.1 熔断器的工作流程
4.2熔断器的状态
4.3Hystrix的熔断机制
Hystrix默认请求阈值为20, 如果20次请求的50%失败, 服务熔断. 服务的默认熔断休眠期为5秒, 5秒后进入半开模式, 如果请求成功, 熔断器关闭
可以通过如下方式进行修改:
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000")
})
public ResponseEntity userList(List<Integer> ids) {
List<User> list = new ArrayList<>();
for (Integer id : ids) {
// 直接将服务名写入路径, Ribbon会通过拦截器解析
String url = "http://demo-provider/user/" + id;
User user = restTemplate.getForObject(url, User.class);
list.add(user);
}
return ResponseEntity.ok(list);
}
二.Feign
Feign是netflix开发的一款声明式web客户端, 可以简化基于REST的远程调用.
1.添加依赖
<!--Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类上开启
@SpringCloudApplication
@EnableFeignClients
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
3.提供feign客户端接口
@FeignClient("demo-provider")
public interface UserClient {
@GetMapping("/user/{id}")
User userInfo(@PathVariable("id") Integer id);
}
4.修改调用代码
@Service
public class DemoService {
@Autowired
private UserClient userClient;
public ResponseEntity userList(List<Integer> ids) {
List<User> list = new ArrayList<>();
for (Integer id : ids) {
list.add(userClient.userInfo(id));
}
return ResponseEntity.ok(list);
}
}
5.Feign集成Hystrix配置
@Component
public class UserClientFallback implements UserClient {
@Override
public User userInfo(Integer id) {
User user = new User();
user.setId(id);
user.setRealname("查无此人...");
return user;
}
}
feign:
hystrix:
enabled: true # 开启hystrix
三.Zuul
网关, 整个微服务系统的统一入口. 作用:
- 分发请求
- 鉴权(过滤)
服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由, 负载均衡功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色, 为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性.
1.创建网关工程
添加zuul启动器依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
2.配置路由规则
server:
port: 10000
# 配置路由规格
zuul:
routes:
demo-provider:
path: /demo-provider/** # 映射的访问路径
url: http://127.0.0.1:8080/ # 路由的地址
3.面向服务的配置
需要添加eureka-client的启动器, 由zuul从eureka拉取服务列表, 实现动态路由并进行负载均衡
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
修改yml配置
server:
port: 10000
# 配置路由规格
zuul:
routes:
demo-provider: # /demo-provider/** # 简化配置
path: /user/** # 映射的访问路径
serviceId: demo-provider # 要调用的服务id, 底层使用ribbon进行负载均衡
strip-prefix: false # 不要忽略前缀
ignored-services:
- demo-consumer # 忽略哪些服务
spring:
application:
name: demo-gateway
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka/
registry-fetch-interval-seconds: 10
instance:
prefer-ip-address: true
ip-address: 127.0.0.1