一、概述
1.什么是OpenFeign
OpenFeign是一个声明性的Web服务客户端,它使得编写Web服务客户端变得更加容易。OpenFeign使用基于注解的方法定义请求接口,并且自动地处理了请求参数处理、编码、解码和错误处理。它是一个轻量级的库,可以与其他Java库和框架集成使用,例如Spring Cloud。OpenFeign的目标是简化HTTP API的调用,并为微服务架构提供一致的客户端体验。
2.什么是Hystrix
Hystrix是一个开源的延迟和容错库,由Netflix开发并维护。它旨在通过隔离服务之间的访问点、停止级联故障,以及提供备选响应来改进分布式系统的容错能力。
2.1.Hystrix具有的以下功能
1.服务熔断:如果检测到服务不可用那么会触发服务熔断,也就是断开跟服务的连接。
2.服务降级:当服务掉不通的时候,不是一个报错所以不应该触发全局异常,那么此时我们应该给一个托底数据/友好提示,响应给用户。
3.服务限流/资源隔离:限制服务只能进入多少请求,超过设置的数量的请求进行排队,这是为了防止突然的大流量冲垮服务。
4.缓存:Hystrix会帮我们缓存请求的数据,如果下次还是这个请求那么直接响应。
4.Hystrix熔断触发规则
1.服务调不通会触发
2.服务调用慢超时会触发
3.服务报错也会触发
3.什么是Zuul,为什么需要
在微服务架构中,服务之间的协作是非常复杂和困难的,主要涉及路由、过滤、负载均衡、缓存、安全认证等多个方面。这时就需要一个中间层来处理这些问题,而Zuul就是这样一个API网关中间件,它通过反向代理和负载均衡等技术,为服务提供者和服务消费者之间提供路由、过滤、安全认证、监控等功能,从而实现了微服务的可靠和高效运行。
二、OpenFeign的使用
1.导入依赖
<!--引入OpenFeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类加注解@EnableFeignClients
3.创建feign接口,规范在feign包下
package com.lzc.feign;
import com.lzc.domain.User;
import com.lzc.fallback.UserFeignClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
// contextId FeignClient的唯一标识,推荐类名小驼峰
// path 映射路径 也可以requestMapping写在类上
// value 服务名称
@FeignClient(contextId = "userFeignClient",path = "user",value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
@GetMapping
User getUser();
}
4.在需要调用的地方注入使用
package com.lzc.controller;
import com.lzc.domain.User;
import com.lzc.feign.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping
public User getUser(){
return userFeignClient.getUser();
}
}
三、Hystrix的使用
1.Hystrix可以通过以下几种方式与其他的框架或者库进行整合:
1. Hystrix和Spring Cloud整合:Hystrix和Spring Cloud结合是最常见,也是最简单的整合方式。Spring Cloud为Hystrix提供了自动化的配置和属性管理,大大简化了Hystrix的使用和部署过程。Spring Cloud还提供了Dashboard来可视化监控Hystrix命令的指标和熔断状态,方便快捷地进行故障排查和性能调优。
2. Hystrix和Netflix Eureka整合:Netflix Eureka是一种服务发现框架,可以使得服务消费者可以直接从Eureka Server注册中心获取服务提供者的地址信息。通过将Hystrix和Eureka结合,我们可以很容易地实现服务的自动熔断和自动容错,提高整个分布式系统的可用性和鲁棒性。
3. Hystrix和Ribbon整合:Ribbon是一种负载均衡框架,可以使得服务消费者可以通过负载均衡的方式调用服务提供者。通过将Hystrix和Ribbon结合,我们可以很容易地实现服务的高可用和高性能,从而提高整个分布式系统的稳定性和可靠性。
4. Hystrix和Zuul整合:Zuul是一种API网关,可以为服务提供者和服务消费者之间提供路由和过滤。通过将Hystrix和Zuul结合,我们可以很容易地实现服务的自动熔断和自动容错,以及API网关的功能,从而提高整个分布式系统的可用性和鲁棒性。
我们可以通常总结为
1.Ribbon整合Hystrix(了解)
1.方法独立降级:每个controller接口写一个降级方法
2.统一降级方法:整个类的所有方法用一个降级方法,但是要注意所有方法的返回值必须一致
2.OpenFeign整合Hystrix
1.普通降级
2.工厂降级-重点掌握
2.浅用Ribbon整合Hystrix
1.导入依赖
<!--Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.启动类加注解@EnableCircuitBreaker
3.方法加注解@HystrixCommand(fallbackMethod = "getUserFallbackMethod")
package com.lzc.controller;
import com.lzc.domain.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
@Autowired
private RestTemplate restTemplate;
// RestTemplate没加负载均衡的
// @GetMapping
// public User getUser(){
// User user = restTemplate.getForObject("http://localhost:1020/user", User.class);
// return user;
// }
// 开启RestTemplate负载均衡
@GetMapping
@HystrixCommand(fallbackMethod = "getUserFallbackMethod")
public User getUser(){
log.info("进入了getUser.........");
return restTemplate.getForObject("http://user-server/user", User.class);
}
public User getUserFallbackMethod(){
log.info("进入了getUserFallbackMethod......");
return new User(-1L,"熔断了.......");
}
}
3.OpenFeign整合Hystrix
1.导入依赖
<!--引入OpenFeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.@FeignClient(contextId = "userFeignClient",path = "user",value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)加上fallbackFactory=“”
3.创建UserFeignClientFallbackFactory类
package com.lzc.fallback;
import com.lzc.domain.User;
import com.lzc.feign.UserFeignClient;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {
@Override
public UserFeignClient create(Throwable throwable) {
return new UserFeignClient() {
@Override
public User getUser() {
log.info("我进feign的托底方法了........");
return new User(-2L,"熔断了.......");
}
};
}
}
4.整合Zuul
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2.启动类加上注解@EnableZuulProxy,开启Zuul服务支持
3.配置yml
server:
port: 1050 # 服务端口号
eureka:
client: # Eureka客户端配置,指向注册中心地址
serviceUrl:
defaultZone: http://localhost:1010/eureka/
instance:
prefer-ip-address: true # 开启使用IP地址进行注册
instance-id: zuul-server:1050 # 修改实例Id
spring:
application: # 指定此服务的应用名称
name: zuul-server
zuul:
prefix: "/apis" #统一访问前缀
ignoredServices: "*" #禁用掉使用浏览器通过服务名的方式访问服务
routes:
pay-server: "/pay/**" #指定pay-server这个服务使用 /pay路径来访问 - 别名
order-server: "/order/**" #指定order-server这个服务使用 /order路径来访问
4.1自定义Zuul的filter
Zuul的底层是通过各种Filter来实现的,Zuul中的Filter按照执行顺序分为了以下几种,当各种Filter出现了异常,请求会跳转到ErrorFilter,然后再经过PostFilter,最后返回结果,如果是PostFilter出现异常,那么也会走ErrorFilter,然后直接响应。
1.自定义拦截器,通过继承ZuulFilter
package com.lzc.fallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class PayServerFallback implements FallbackProvider {
// 得到日志对象
private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
@Override
public String getRoute() {
return "pay-server"; //"*"代表所有服务都有作用
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 0;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("抱歉,服务不可用".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
2.Zuul的熔断配置
package com.lzc.fallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class PayServerFallback implements FallbackProvider {
// 得到日志对象
private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
@Override
public String getRoute() {
return "pay-server"; //"*"代表所有服务都有作用
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 0;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("抱歉,服务不可用".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}