Feign是一个声明式的REST客户端,它用了基于接口的注解方式,很方便实现客户端配置。
作用在消费端
使用步骤:
依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
调用接口
/**
* feign的声明式调用接口
* String url = "http://EUREKA-PROVIDER/goods/goods/"+id;
* 1.声明接口
* 2.添加 @FeignClient 注解,其中 value为服务提供方的应用名,即 ribbon调用时的url里的名称,而调用地址则由接口声明。
* 3.声明调用接口方法,接口方法规则要与服务提供方的调用方法规则一致,方法名和返回值可以不一致。
* 4.在控制层注入接口
*/
@FeignClient(value = "EUREKA-PROVIDER")
public interface GoodsFeignClient {
@GetMapping("/goods/goods/{id}")
public Goods findGoodsById(@PathVariable("id") Integer id);
}
@Resource
private GoodsFeignClient goodsFeignClient;
/**
* feign调用
* @param id
* @return
*/
@GetMapping("/goods3/{id}")
public Goods findGoodsById3(@PathVariable("id") Integer id){
Goods goods = goodsFeignClient.findGoodsById(id);
return goods;
}
Feign底层依赖于Ribbon实现负载均衡和远程调用,所以一般配置Ribbon的超时,但Feign实际也有自己的超时配置。
Ribbon默认超时一秒。超时报错。
调用方配置
# 设置Ribbon的超时时间
ribbon:
ConnentTimeOut: 1000 #连接超时时间 默认1s
ReadTimeOut: 3000 #逻辑处理的超时时间 默认1s
调用的数据包监控。
1.Feign只能记录debug级别的日志信息
# 设置当前的日志级别为debug
logging:
level:
com.li: debug
2.定义Feign日志级别Bean
@Configuration
public class FeignLogConfig {
/**
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL,记录完成的请求 响应数据
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
3.启用该Bean
@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class)
Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败(雪崩)。
雪崩:一个服务失败,导致整条链路的服务都失败的情形。
Hystrix主要功能 :
隔离:
线程池隔离:如果服务a调用服务时,服务挂掉,则可能a会有更多线程去调用服务,但都无法释放导致线程池可用线程资源耗尽,其他服务则不能正常调用,所以需要线程池隔离。默认为线程池隔离。
信号量隔离:添加访问次数,超过次数可以拒绝提供服务。
降级 :提供方和消费方都需要降级,异常,超时。给提示。
熔断 :
限流
当服务发生异常或调用超时,返回默认数据。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
/**
* 定义降级方法:
* 1.方法的返回值需要和原方法一样
* 2.方法的参数需要和原方法一样
*/
public Goods findGoods_fallback(@PathVariable("id") Integer id){
Goods goods = new Goods();
goods.setName("降级了~~~");
return goods;
}
/**
* feign调用
* @HystrixCommand 注解降级,当异常或超时后降级,默认超时一秒
* 其中 fallbackMethod 属性为降级后执行的方法,commandProperties 来指定其他配置
* @HystrixProperty 指定其属性配置,如超时时间,
* HystrixCommandProperties类中定义了各个参数
*/
@GetMapping("/goods/{id}")
@HystrixCommand(fallbackMethod = "findGoods_fallback",commandProperties = {
//超时三秒降级
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findGoodsById(@PathVariable("id") Integer id){
int i = 1/0;
Goods goods = goodsService.findOne(id);
goods.setName(goods.getName()+":"+port);
return goods;
}
@EnableCircuitBreaker
消费方也可以使用服务端的写法来编写降级
由于消费方使用feign组件进行远程调用,而feign组件已经集成了hystrix组件
定义feign 调用接口实现类,复写方法,即降级方法。
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public Goods findGoodsById(Integer id) {
Goods goods = new Goods();
goods.setName("消费端降级~~");
return goods;
}
}
在@FeignClient注解中使用fallback属性设置降级处理类。
@FeignClient(value = "EUREKA-PROVIDER",fallback = GoodsFeignClientFallback.class)
配置开启 feign的hystrix支持,默认关闭
# 启用feign的hystrix降级
feign:
hystrix:
enabled: true
注意:当服务端和消费端都提供了降级时,由于提供方已经降级所以提供的数据就是正常数据而不是异常数据,一般为调用超时或调用异常降级,所以显示的是服务端降级。
用于监控微服务的调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
如果熔断时,5秒后,断路器会半开尝试,调用失败继续打开断路器,如果调用成功次数达到阈值,则关闭熔断器。
熔断器机制默认是开启的。
配置
@GetMapping("/goods/{id}")
@HystrixCommand(fallbackMethod = "findGoods_fallback",commandProperties = {
//超时三秒降级
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//失败次数,默认20次
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),
//监控时间,默认5000毫秒
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败率,默认50%
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50")
})
Hystrix 提供了Hystrix-dashboard 功能,用于实时监控微服务运行状态。但只能监控一个微服务。
Netflix提供了Turbine,进行聚合监控。
在浏览器访问http://localhost:8769/hystrix/ 进入Hystrix Dashboard界面
界面中输入监控的Url地址 http://localhost:8769/turbine.stream,监控时间间隔2000毫秒和title,
网关旨在为微服务架构提供一直简单而有效的统一的API路由管理方式。
在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务接口完成一个用户请求。
存在的问题:
客户端多次请求不同的微服务,增加客户端的复杂性
认证复杂,每个服务都要进行认证
http请求不同服务次数增加,性能不高
网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
在目前的网关解决方案里,有Nginx+Lua、Netflix Zuul、Spring Cloud Gateway等
1.搭建网关模块
2.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
dependencies>
3.编写启动类
4.编写配置文件
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 网关配置
gateway:
#路由配置:转发规则
routes: #集合
# id:唯一标识。默认是一个UUID
# uri:转发路径
# predicates:条件,用于请求网关路径的匹配规则
- id: eureka-provider
uri: http://localhost:8001/
predicates:
- Path=/goods/**
注意:此时服务端请求调用有效http://localhost/goods/goods/1。消费端不能用80端口
1.静态路由
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 网关配置
gateway:
#路由配置:转发规则
routes: #集合
# id:唯一标识。默认是一个UUID
# uri:转发路径
# predicates:条件,用于请求网关路径的匹配规则
- id: eureka-provider
uri: http://localhost:8001/
predicates:
- Path=/goods/**
- id: eureka-consumer
uri: http://localhost:9000/
predicates:
- Path=/order/**
2.动态路由
通过eureka动态拉取数据
引入eureka-client配置
server:
port: 80
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: api-gateway-server
cloud:
# 网关配置
gateway:
#路由配置:转发规则
routes: #集合
# id:唯一标识。默认是一个UUID
# uri:转发路径
# predicates:条件,用于请求网关路径的匹配规则
- id: eureka-provider
# 静态路由
# uri: http://localhost:8001/
# 动态路由
uri: lb://EUREKA-PROVIDER
predicates:
- Path=/goods/**
- id: eureka-consumer
# uri: http://localhost:9000/
uri: lb://EUREKA-CONSUMER
predicates:
- Path=/order/**
# 微服务名称配置,并且配置后,不管路径添加不添加标识都能正常访问
discovery:
locator:
enabled: true #设置为true
lower-case-service-id: true #允许小写,因为Eureka默认应用名称为大写
3. 微服务名称配置
路径太多可能会冲突,可以使用名称来标识
spring:
cloud:
# 网关配置
gateway:
# 微服务名称配置,并且配置后,不管路径添加不添加标识都能正常访问
discovery:
locator:
enabled: true #设置为true
lower-case-service-id: true #允许小写,因为Eureka默认应用名称为大写
1.局部过滤器
Spring Cloud Gateway 中提供了大量的内置过滤器组件(过滤器工厂)
只需要配置文件中配置局部过滤器名称,并指定对应的值,就可以让其生效。
这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格。如下:
过滤器工厂 | 作用 | 参数 |
---|---|---|
AddRequestHeader | 为原始请求添加Header | Header的名称及值 |
AddRequestParameter | 为原始请求添加请求参数 | 参数名称及值 |
AddResponseHeader | 为原始响应添加Header | Header的名称及值 |
DedupeResponseHeader | 剔除响应头中重复的值 | 需要去重的Header名称及去重策略 |
Hystrix | 为路由引入Hystrix的断路器保护 | HystrixCommand 的名称 |
FallbackHeaders | 为fallbackUri的请求头中添加具体的异常信息 | Header的名称 |
PrefixPath | 为原始请求路径添加前缀 | 前缀路径 |
PreserveHostHeader | 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host | 无 |
RequestRateLimiter | 用于对请求限流,限流算法为令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus |
RedirectTo | 将原始请求重定向到指定的URL | http状态码及重定向的url |
RemoveHopByHopHeadersFilter | 为原始请求删除IETF组织规定的一系列Header | 默认就会启用,可以通过配置指定仅删除哪些Header |
RemoveRequestHeader | 为原始请求删除某个Header | Header名称 |
RemoveResponseHeader | 为原始响应删除某个Header | Header名称 |
RewritePath | 重写原始的请求路径 | 原始路径正则表达式以及重写后路径的正则表达式 |
RewriteResponseHeader | 重写原始响应中的某个Header | Header名称,值的正则表达式,重写后的值 |
SaveSession | 在转发请求之前,强制执行WebSession::save 操作 |
无 |
secureHeaders | 为原始响应添加一系列起安全作用的响应头 | 无,支持修改这些安全响应头的值 |
SetPath | 修改原始的请求路径 | 修改后的路径 |
SetResponseHeader | 修改原始响应中某个Header的值 | Header名称,修改后的值 |
SetStatus | 修改原始响应的状态码 | HTTP 状态码,可以是数字,也可以是字符串 |
StripPrefix | 用于截断原始请求的路径 | 使用数字表示要截断的路径的数量 |
Retry | 针对不同的响应进行重试 | retries、statuses、methods、series |
RequestSize | 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large |
请求包大小,单位为字节,默认值为5M |
ModifyRequestBody | 在转发请求之前修改原始请求体内容 | 修改后的请求体内容 |
ModifyResponseBody | 修改原始响应体的内容 | 修改后的响应体内容 |
Default | 为所有路由添加过滤器 | 过滤器工厂名称及值 |
**Tips:**每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory
结尾,这是Spring Cloud Gateway的一个约定,例如AddRequestHeader
对应的实现类为AddRequestHeaderGatewayFilterFactory
。
配置
spring:
application:
name: api-gateway-server
cloud:
# 网关配置
gateway:
#路由配置:转发规则
routes: #集合
# id:唯一标识。默认是一个UUID
# uri:转发路径
# predicates:条件,用于请求网关路径的匹配规则
# filters:配置局部过滤器
- id: eureka-provider
# 静态路由
# uri: http://localhost:8001/
# 动态路由
uri: lb://EUREKA-PROVIDER
predicates:
- Path=/goods/**
filters:
#添加请求参数,添加微服务名称配置时为null
- addRequestParameter=username, zhangsan
2. 全局过滤器
GlobalFilter 全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在某个路由上。
Spring Cloud Gateway 核心功能也是通过内置的全局过滤器来完成。
自定义全局过滤器
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定义全局过滤器执行~~~~~~");
//放行
return chain.filter(exchange);
}
/**
* 过滤器排序
* @return 数值越小,越先执行,0最先执行
*/
@Override
public int getOrder() {
return 0;
}
}