001-spring boot 2.5.x feign 生产环境使用参考

spring feign 总结

启用

项目中增加依赖

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-httpclient</artifactId>
      <version>10.12</version>
  </dependency>

激活配置
启动类添加载 @EnableFeignClients 如下:

@SpringBootApplication
@ComponentScans({@ComponentScan(value = "com.lydemo", excludeFilters = {@ComponentScan.Filter(IgnoreMark.class)})})
@ServletComponentScan("com.lydemo.helloworld.filter")
@EnableFeignClients
public class BootApplication {

基础配置 包括 超时,httpclient,日志配置

# feign配置
feign.httpclient.max-connections=200
feign.httpclient.max-connections-per-route=50
feign.httpclient.connection-timeout=1500
feign.client.config.default.connect-timeout=1500
feign.client.config.default.read-timeout=5000
feign.client.config.default.loggerLevel=BASIC

重试机制

总结:

  1. feign 的调用逻辑 入口: feign.SynchronousMethodHandler#invoke
  2. feign 自身默认 不启用重试 : Retryer.NEVER_RETRY (一般建议不用开启)

配置解析:
通过 org.springframework.cloud.openfeign.FeignClient#configuration 字段注释 发现 默认配置 在 org.springframework.cloud.openfeign.FeignClientsConfiguration

// org.springframework.cloud.openfeign.FeignClientsConfiguration#feignRetryer
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
  return Retryer.NEVER_RETRY;
}

参考:

  1. https://cloud.tencent.com/developer/article/1083249 (老的 用ribbon)
  2. https://codeleading.com/article/46553623072/ (feign 和 ribbon 重试机制对比)

启用 LoadBalancer 重试

说明

  1. 当不启用 (LoadBalancer 重试) 时候 client 是FeignBlockingLoadBalancerClient ,当启用重试时候 RetryableFeignBlockingLoadBalancerClient ,重试策略是 InterceptorRetryPolicy
  2. 代码执行逻辑 在: org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient#execute (spring boot 配置在org.springframework.cloud.openfeign.loadbalancer.DefaultFeignLoadBalancerConfiguration#feignRetryClient)
  3. 重试 机制 默认也未开启

启用配置
增加如下依赖:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

添加如下 配置

# loadbalancer 配置
# loadbalancer 配置 (retry.enabled 也会控制 RetryableFeignBlockingLoadBalancerClient 的生成)
spring.cloud.loadbalancer.retry.enabled=true
spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance=0
spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance=1

重试测试

logback 添加如下配置

<logger name="com.lydemo.helloworld.remote.feign" level="DEBUG"/>
<logger name="org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient" level="DEBUG"/>

启动 两个被调用实例 (我启动了helo2 demo 微服务),然后 快速停止其中一个,快速点击调用方实例,出现如下日志:

重试 日志如下

remote.feign.Helo2Client - [log,72] - [Helo2Client#queryUserByName] ---> GET http://HELO2/helo2/queryUserByName?name=lala&sign=2e3817293fc275dbee74bd71ce6eb056 HTTP/1.1
2021-07-25 01:54:29.508 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,120] - Service instance retrieved from LoadBalancedRetryContext: was null. Reattempting service instance selection
2021-07-25 01:54:29.510 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,128] - Selected service instance: [EurekaServiceInstance@6b1e9f0 instance = InstanceInfo [instanceId = helo2:192.168.3.6:42379, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 42379, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@2fff1f76]
2021-07-25 01:54:29.510 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,146] - Using service instance from LoadBalancedRetryContext: [EurekaServiceInstance@6b1e9f0 instance = InstanceInfo [instanceId = helo2:192.168.3.6:42379, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 42379, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@2fff1f76]
2021-07-25 01:54:29.514 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,120] - Service instance retrieved from LoadBalancedRetryContext: was null. Reattempting service instance selection
2021-07-25 01:54:29.523 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,128] - Selected service instance: [EurekaServiceInstance@6996f084 instance = InstanceInfo [instanceId = helo2:192.168.3.6:8080, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 8080, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@781923c7]
2021-07-25 01:54:29.523 [http-nio-46092-exec-7] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,146] - Using service instance from LoadBalancedRetryContext: [EurekaServiceInstance@6996f084 instance = InstanceInfo [instanceId = helo2:192.168.3.6:8080, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 8080, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@781923c7]
2021-07-25 01:54:29.533 [http-nio-46092-exec-7] DEBUG com.lydemo.helloworld.remote.feign.Helo2Client - [log,72] - [Helo2Client#queryUserByName] <--- HTTP/1.1 200  (25ms)

正常没有重试日志如下:

2021-07-25 02:10:55.381 [http-nio-46092-exec-10] DEBUG com.lydemo.helloworld.remote.feign.Helo2Client - [log,72] - [Helo2Client#queryUserByName] ---> GET http://HELO2/helo2/queryUserByName?name=lala&sign=2e3817293fc275dbee74bd71ce6eb056 HTTP/1.1
2021-07-25 02:10:55.381 [http-nio-46092-exec-10] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,120] - Service instance retrieved from LoadBalancedRetryContext: was null. Reattempting service instance selection
2021-07-25 02:10:55.382 [http-nio-46092-exec-10] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,128] - Selected service instance: [EurekaServiceInstance@4a2d6add instance = InstanceInfo [instanceId = helo2:192.168.3.6:8080, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 8080, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@781923c7]
2021-07-25 02:10:55.382 [http-nio-46092-exec-10] DEBUG org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient - [lambda$execute$2,146] - Using service instance from LoadBalancedRetryContext: [EurekaServiceInstance@4a2d6add instance = InstanceInfo [instanceId = helo2:192.168.3.6:8080, appName = HELO2, hostName = 192.168.3.6, status = UP, ipAddr = 192.168.3.6, port = 8080, securePort = 443, dataCenterInfo = com.netflix.appinfo.MyDataCenterInfo@781923c7]
2021-07-25 02:10:55.387 [http-nio-46092-exec-10] DEBUG com.lydemo.helloworld.remote.feign.Helo2Client - [log,72] - [Helo2Client#queryUserByName] <--- HTTP/1.1 200  (5ms)

feign circuitbreake

说明

  1. 默认未启用 ,需配置 :feign.circuitbreaker.enabled=false

使用配置

添加如下依赖

<!-- circuitbreaker 配置 start -->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- circuitbreaker 配置 end -->

配置

feign.circuitbreaker.enabled=true

因为添加了 resilience4j-spring-boot2 所以 resilience4j 可以如下配置:

# resilience4j circuitbreaker 配置
resilience4j.circuitbreaker:
  configs:
    default:
      slidingWindowType: COUNT_BASED
      slidingWindowSize: 100
      minimumNumberOfCalls: 100
      permittedNumberOfCallsInHalfOpenState: 10
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitIntervalFunctionInOpenState: 60
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
#      recordExceptions:
#        - org.springframework.web.client.HttpServerErrorException
#        - java.io.IOException
#      ignoreExceptions:
#        - java.lang.IllegalStateException
  instances:
    testService:
      baseConfig: default
      slidingWindowSize: 10
      minimumNumberOfCalls: 2
      failureRateThreshold: 1
      recordExceptions:
        - java.lang.Throwable

属性配置优先级高于Java Customizer configuration.

参考:

https://docs.spring.io/spring-cloud-circuitbreaker/docs/current/reference/html/#usage-documentation

java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] at com.unkown.data.hw.ipran.straight.collect.UnkownDataHwIpranStraightCollectApplication.main(UnkownDataHwIpranStraightCollectApplication.java:39) [classes/:na] Caused by: feign.FeignException$InternalServerError: [500 INTERNAL SERVER ERROR] during [POST] to [http://ants-flask/api/collect/endpoint] [RemoteIpranScanService#endpoint(String)]: [<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>TypeError: unsupported operand type(s) for +: 'int' and 'str' // Wer... (20567 bytes)] at feign.FeignException.serverErrorStatus(FeignException.java:231) ~[feign-core-10.10.1.jar:na] at feign.FeignException.errorStatus(FeignException.java:180) ~[feign-core-10.10.1.jar:na] at feign.FeignException.errorStatus(FeignException.java:169) ~[feign-core-10.10.1.jar:na] at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92) ~[feign-core-10.10.1.jar:na] at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96) ~[feign-core-10.10.1.jar:na] at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-10.10.1.jar:na] at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89) ~[feign-core-10.10.1.jar:na] at com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler.invoke(SentinelInvocationHandler.java:107) ~[spring-cloud-starter-alibaba-sentinel-2.2.3.RELEASE.jar:2.2.3.RELEASE] at com.sun.proxy.$Proxy131.endpoint(Unknown Source) ~[na:na] at com.unkown.data.hw.ipran.straight.collect.controller.RTrsHwIpranCircuitController.IpranSend(RTrsHwIpranCircuitController.java:94) ~[classes/:na] at com.unkown.data.hw.ipran.straight.collect.MyRunner.run(MyRunner.java:22) ~[classes/:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE] ... 5 common frames omitted
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值