微服务实战(三) OpenFegin 声明式服务调用
概述
- Fegin是一个声明式的Http客户端,它使得写Http客户端变得更简单,使用Fegin只需要创建一个接口并注解,它具有可插拔的注解特性。
- Nacos很好的兼容了Fegin,Fegin中也是默认集成了Ribbons实现负载均衡的效果,底层使用了HttpClient作为服务框架。
Feign+Nacos实现服务间调用
引入依赖
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Ailibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类添加注解
@EnableFeignClients
启用feign客户端
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
定义接口
@FeignClient
定义feign客户端
参数:
- name 与value相同,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现。
- url: url一般用于调试,可以手动指定@FeignClient调用的地址
- fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
- url: url一般用于调试,可以手动指定@FeignClient调用的地址
- configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
- fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
@FeignClient(value = "sunnyws-service-example1")
public interface Example1Client {
@GetMapping("/test")
void test();
}
调用
@Resource
private Example1Client example1Client;
@GetMapping("/test")
public void test(){
log.info("开始调用example1服务的test方法!");
long time1=System.currentTimeMillis();
example1Client.test();
long time2=System.currentTimeMillis();
log.info("耗时:"+(time2-time1)+"ms");
log.info("调用完成!");
}
Feign + Hystrix 服务的熔断 降级
- 请求熔断:Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。
- 服务降级 Fallback:当处理出现异常,或不具备处理能力时(负载过高、线程池用完),则会快速返回一个预先指定的值。
- Fallback主要是用来解决依赖的服务不可用或者调用服务失败或超时,使用默认的返回值。
- OpenFeign 中Fallback
是通过
Hystrix实现的, 所以需要开启
Hystrix
- 有服务熔断,必然要有服务降级。
- 在网络请求时,可能会出现异常请求,如果还想再异常情况下使系统可用,那么就需要熔断,降级处理。
修改配置
- feign.hystrix.enabled: true #开启
Hystrix
默认关闭 - hystrix默认超时时间为1s
spring:
application:
name: sunnyws-service-example2
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.10:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
config:
server-addr: 172.16.220.10:8848
file-extension: yml
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
feign:
hystrix:
enabled: true
hystrix:
command:
default: #配置服务降级全局超时时间
execution:
isolation:
thread:
timeoutInMilliseconds: 12000 #默认(1s)
timeout:
enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon
circuitBreaker:
#10秒内,5次请求,失败率在50%,熔断8秒。
requestVolumeThreshold: 5 #默认20 ,一个rolling window内最小的请求数。如果设为20, 10秒(Hystrix的滑动窗口算法)内发起了至少20次请求,失败率超过50%(errorThresholdPercentage),从熔断开启后,不在调用该远程服务
sleepWindowInMilliseconds: 8000 #默认5S 休眠时长
errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%
定义Fallback实现类
实现Feign接口
@Slf4j
@Component
public class Example1ClientFallBack implements Example1Client {
@Override
public void test() {
log.info("熔断方法被调用了!");
}
}
Feign接口指定一个实现Feign接口的实现类
@FeignClient(value = "sunnyws-service-example1",fallback = Example1ClientFallBack.class)
public interface Example1Client {
@GetMapping("/test")
void test();
}
Feign + Ribbon 服务的负载均衡和重试
- openfeign默认集成了ribbon,做下简单配置即可实现负载均衡
- openfeign中ribbon默认负载算法为轮询
- openfeign中ribbon默认重试机制为当前请求实例 重试1次
比较常用的负载均衡策略有:
随机 (Random)
轮询 (RoundRobin)
一致性哈希 (ConsistentHash)
哈希 (Hash)
加权(Weighted)
- Ribbon 提供了 IRule 接口,通过其可以设置并更换负载均衡规则。
- IRule 实质就是 根据某种负载均衡规则,从服务列表中选取一个需要访问的服务。
- 一般默认使用 ZoneAvoidanceRule + RoundRobinRule。
#【IRule 子类如下:】
RoundRobinRule
#轮询,按照服务列表顺序 循环选择服务。
RandomRule
#随机,随机的从服务列表中选取服务。
RetryRule
#重试,先按照轮询策略获取服务,若获取失败,则在指定时间进行重试,重新获取可用服务。
WeightedResponseTimeRule
#加权响应时间,响应时间越低(即响应时间快),权重越高,越容易被选择。刚开始启动时,使用轮询策略。
BestAvailableRule
#高可用,先过滤掉不可用服务(多次访问故障而处于断路器跳闸的服务),选择一个并发量最小的服务。
AvailabilityFilteringRule
#可用筛选,先过滤掉不可用服务 以及 并发量超过阈值的服务,对剩余服务按轮询策略访问。
ZoneAvoidanceRule
#区域回避,默认规则,综合判断服务所在区域的性能 以及 服务的可用性,过滤结果后采用轮询的方式选择结果。
基本使用
OpenFeign默认集成Ribbon,如果只是简单的使用,直接在配置文件中添加相应配置即可。
spring:
application:
name: sunnyws-service-example2
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.10:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
config:
server-addr: 172.16.220.10:8848
file-extension: yml
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
feign:
hystrix:
enabled: true
ribbon:
MaxAutoRetries: 0 #(默认1次 不包括第一次)最大重试次数,当注册中心中可以找到服务,但是服务连不上时将会重试,如果注册中心中找不到服务则直接走断路器
MaxAutoRetriesNextServer: 2 #(默认0次 不包括第一次)切换实例的重试次数
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
ConnectTimeout: 3000 #(默认1s)请求连接的超时时间
ReadTimeout: 3000 #(默认1s)请求处理的超时时间
hystrix:
command:
default: #配置服务降级全局超时时间
execution:
isolation:
thread:
timeoutInMilliseconds: 12000 #默认(1s)
timeout:
enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon
circuitBreaker:
#10秒内,5次请求,失败率在50%,熔断8秒。
requestVolumeThreshold: 5 #默认20 ,一个rolling window内最小的请求数。如果设为20, 10秒(Hystrix的滑动窗口算法)内发起了至少20次请求,失败率超过50%(errorThresholdPercentage),从熔断开启后,不在调用该远程服务
sleepWindowInMilliseconds: 8000 #默认5S 休眠时长
errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%
设置超时时间
hystrix
hystrix:
command:
default: #配置服务降级全局超时时间
execution:
isolation:
thread:
timeoutInMilliseconds: 12000 #默认(1s)
timeout:
enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon
ribbon
ribbon:
MaxAutoRetries: 0 #(默认1次 不包括第一次)最大重试次数,当注册中心中可以找到服务,但是服务连不上时将会重试,如果注册中心中找不到服务则直接走断路器
MaxAutoRetriesNextServer: 1 #(默认0次 不包括第一次)切换实例的重试次数
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
ConnectTimeout: 3000 #(默认1s)请求连接的超时时间
ReadTimeout: 3000 #(默认1s)请求处理的超时时间
- Hystrix与Ribbon的默认请求超时时间都是1秒
- 在接口调用的时候,两个计时器会同时读秒。所以建议配置Hystrix的超时时间要大于ribbon的超时时间,ribbon重试超时后,再进行熔断处理。
- OpenFeign默认开启
Ribbon
,开启Hystrix
需要添加配置。当开启Hystrix,单独设置Hystrix的超时时间,可能会小于Ribbon的默认时间,会出现不确定的结果。 - 当Hystrix超时时间 < Ribbon超时时间,程序会先回调进入到Hystrix的fallback方法,并继续执行下去。Ribbon会继续发送请求,直到请求完成,或达到重试次数,Ribbon的重试也就没有了意义。
- Ribbon的重试次数不包括第一次请求,如果
MaxAutoRetries=1
,MaxAutoRetriesNextServer=2
,则最大请求次数为6((1+1)*(2+1)
)次,最大超时时间为(ConnectTimeout+ReadTimeout)*6
作者: SunnyWs