Ribbon配置
全局配置
由于Spring cloud Feign
的客戶端負(fù)載均衡是通過spring cloud Ribbon
實(shí)現(xiàn)的术瓮,所以我們可以直接通過配置Ribbon客戶端的方式來自定義各個(gè)服務(wù)客戶端調(diào)用的參數(shù)滤淳。
ribbon.ConnectTimeout=500
ribbon.ReadTimeOut=5000
指定服務(wù)配置
大多數(shù)情況下援制,我們對于服務(wù)調(diào)用的超時(shí)時(shí)間可能會根據(jù)實(shí)際服務(wù)的特性做一些調(diào)整妨退,所以僅僅依靠默認(rèn)的全局配置是不行的。在使用spring cloud feign
的時(shí)候鸿摇,針對各個(gè)服務(wù)客戶端進(jìn)行個(gè)性化配置的方式與使用Spring Cloud Ribbon
時(shí)的配置方式時(shí)一樣的萨惑,都采用了<client>.ribbon.key=value
的格式進(jìn)行設(shè)置。我們使用@Feign(value="user-service")
來創(chuàng)建一個(gè)Feign客戶端的時(shí)候贞滨,同時(shí)也創(chuàng)建了一個(gè)名為user-service
的Ribbon
客戶端入热。所以我們也可以使用@Feign
中的name
或者value
屬性只來設(shè)置對應(yīng)的ribbon
參數(shù),比如:
user-service.ribbon.ConnectTimeout=500
user-service.ribbon.ReadTimeout=2000
user-service.ribbon.OkToRetryOnAllOperations=true
user-service.ribbon.MaxAutoRetriesNextServer=2
user-service.ribbon.MaxAutoRetries=1
重試機(jī)制
在spring cloud Feign
中默認(rèn)實(shí)現(xiàn)了請求的重試機(jī)制晓铆,而上面對user-service
客戶端的配置內(nèi)容就是對于請求超時(shí)以及重試配置的詳情勺良,
@GetMapping
public String userHello() throws Exception{
ServiceInstance serviceInstance = client.getLocalServiceInstance();
//線程阻塞,測試超時(shí)
int sleeptime = new Random().nextInt(3000);
logger.info("sleeptime:"+sleeptime);
Thread.sleep(sleeptime);
logger.info("/user,host:"+serviceInstance.getHost()+",service id:"+serviceInstance.getServiceId()+",port:"+serviceInstance.getPort());
return "hello world";
}
user-service.ribbon.ConnectTimeout=500
user-service.ribbon.ReadTimeout=2000
user-service.ribbon.OkToRetryOnAllOperations=true
user-service.ribbon.MaxAutoRetriesNextServer=2
user-service.ribbon.MaxAutoRetries=1
在pay-service
應(yīng)用中增加了重試配置參數(shù)骄噪,其中尚困,由于user-service.ribbon.MaxAutoRetries
設(shè)置為1,所以重試策略先嘗試訪問首選案例一次链蕊,失敗后才更換實(shí)例訪問事甜,而更換實(shí)例訪問的次數(shù)通過user-service.ribbon.MaxAutoRetriesNextServer
參數(shù)設(shè)置為2谬泌,所以會嘗試更換兩次實(shí)例進(jìn)行重試。
Ribbon的超時(shí)與Hystrix的超時(shí)是兩個(gè)概念逻谦。一般需要讓hystrix的超時(shí)時(shí)間大于Ribbon的超時(shí)時(shí)間掌实,否則Hystrix命令超時(shí)后,改命令直接熔斷邦马,重試機(jī)制就沒有任何意義了贱鼻。
Hystrix配置
spring cloud Feign
中,除了引入了用于客戶端負(fù)載均衡的spring cloud Ribbon
之外滋将,還引入了服務(wù)保護(hù)了容錯(cuò)的工具Hystrix
邻悬,spring cloud feign
客戶端的方法都封裝到Hystrix
命令中進(jìn)行服務(wù)保護(hù)。
全局配置
對于Hystrix的全局配置同spring cloud Ribbon
的全局配置一樣随闽,直接使用它的默認(rèn)配置前綴hystrix.command.default
就可以進(jìn)行設(shè)置父丰,比如設(shè)置全局的超時(shí)時(shí)間:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
在對hystrix進(jìn)行設(shè)置之前,需要確認(rèn)feign.hystrix.enabled
參數(shù)沒有被設(shè)置為false橱脸,否則該參數(shù)設(shè)置會關(guān)閉Feign客戶端的Hystrix支持础米。而對于我們之前測試重試機(jī)制時(shí),對于Hystrix的超時(shí)時(shí)間控制除了可以使用上面的配置來增加熔斷超時(shí)時(shí)間添诉,也可以通過feign.hystrix.enabled=false
來關(guān)閉Hystrix功能屁桑,或者使用hystrix.command.default.execution.timeout.enabled=false
來關(guān)閉熔斷功能。
禁用Hystrix
在spring cloud feign
中栏赴,可以通過feign.hystrix.enabled=false
來關(guān)閉Hystrix功能蘑斧。另外,如果不想全局地關(guān)閉Hystrix支持须眷,而只想針對某個(gè)服務(wù)客戶端關(guān)閉Hystrix支持時(shí)竖瘾,需要通過使用@Scope("protototype")
注解為指定的客戶端配置Feign.Builder
實(shí)例,
@Configuration
public class DisableHystrixConfigutation {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder(){
return Feign.builder();
}
}
在pay-service
服務(wù)的user-service
接口中引入該配置花颗。
@FeignClient(value = "user-service",configuration = DisableHystrixConfigutation.class)
...
指定命令配置
對于Hystrix命令的配置捕传,在實(shí)際應(yīng)用時(shí)往往也會根據(jù)實(shí)際業(yè)務(wù)情況制定出不同的配置方案。配置方法也跟傳統(tǒng)的Hystrix命令的參數(shù)配置相似扩劝,采用hystrix.command.<commandKey>
作為前綴庸论。而<commandKey>
默認(rèn)情況下會采用feign客戶端中的方法名作為標(biāo)識,所以棒呛,針對上面的hello方法聂示,可以如下配置:
hystrix.command.hello.isolation.thread.timeoutInmilliseconds=5000
需要注意的是,由于方法名有可能會重復(fù)簇秒,這個(gè)時(shí)候相同的方法名的hystrix配置會共用鱼喉,所以在進(jìn)行方法與配置的時(shí)候需要做好一定的規(guī)劃,當(dāng)然也可以重寫Feign.Builder
的實(shí)現(xiàn),并在應(yīng)用主類中創(chuàng)建它的實(shí)例來覆蓋自動化配置的HystrixFegin.Builder
實(shí)現(xiàn)扛禽。
服務(wù)降級配置
Hystrix提供的服務(wù)降級是服務(wù)容錯(cuò)的重要功能锋边,由于Spring cloud feign
在定義服務(wù)客戶端的時(shí)候與Spring cloud Ribbon
有很大的差別,HystrixCommand
定義被封裝起來编曼,我們無法像之前介紹spring cloud hystrix
時(shí)宠默,通過@HystrixCommand
注解的fallback
參數(shù)那樣來指定具體的服務(wù)降級處理方法。但是灵巧,spring cloud feign
提供了另外一種簡單的定義方式,
定義一個(gè)Feign客戶端的服務(wù)降級類UserServiceFallback抹沪,實(shí)現(xiàn)UserService接口刻肄,其中每個(gè)重寫方法的實(shí)現(xiàn)邏輯都可以用來定義相應(yīng)的服務(wù)降級邏輯,具體如下:
@Component
public class UserServiceFallback implements UserService{
@Override
public String index() {
return "error";
}
@Override
public String hello() {
return "hello error";
}
@Override
public String hello1(String username) {
return "hello username is null";
}
@Override
public User hello2(String username, Integer age) {
return new User("未知",0);
}
@Override
public String hello3(User user) {
return "user error";
}
}
- 在服務(wù)綁定接口
user-service
中融欧,通過@FeignClient
注解的fallback
屬性來指定對應(yīng)的服務(wù)降級實(shí)現(xiàn)類:
@FeignClient(value = "user-service",fallback = UserServiceFallback.class)
public interface UserService {
@RequestMapping("/user/index")
String index();
@RequestMapping("/user/hello")
String hello();
@RequestMapping(value = "/user/hello1",method = RequestMethod.GET)
String hello1(@RequestParam("username") String username);
@RequestMapping(value = "/user/hello2",method = RequestMethod.GET)
User hello2(@RequestHeader("username") String username, @RequestHeader("age") Integer age);
@RequestMapping(value = "/user/hello3",method = RequestMethod.POST)
String hello3(@RequestBody User user);
}
測試敏弃,停止用戶的服務(wù):
localhost:7070/pay/hello1?username=zhihao.miao
localhost:7070/pay/hello2
localhost:7070/pay/hello3
返回了我們在UserServiceFallback
中定義的每個(gè)方法的降級的重寫函數(shù)的實(shí)現(xiàn)。
fallbackFactory參數(shù)的使用
If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.
如果需要訪問到造成回退的具體原因噪馏,可以使用@FeignClient.注解的fallbackFactory屬性麦到。
@Component
public class HystrixClientFallbackFactory implements FallbackFactory<UserService> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public UserService create(Throwable throwable) {
logger.info("user service exception:" + throwable.getMessage());
return new HystrixClientWithFallBackFactory(){
@Override
public User hello2(String username, Integer age) {
return super.hello2(username, age);
}
};
}
}
定義HystrixClientWithFallBackFactory實(shí)現(xiàn)由@Feign注解標(biāo)記的接口,我這邊就實(shí)現(xiàn)了hello2方法欠肾,只測試這個(gè)方法瓶颠。
public class HystrixClientWithFallBackFactory implements UserService{
@Override
public String index() {
return null;
}
@Override
public String hello() {
return null;
}
@Override
public String hello1(String username) {
return null;
}
@Override
public User hello2(String username, Integer age) {
User user = new User();
user.setAge(0);
user.setUsername("zhihao.miao");
user.setId(-1);
return user;
}
@Override
public String hello3(User user) {
return null;
}
}
測試,斷開User服務(wù)之后刺桃,進(jìn)入保護(hù)模式粹淋,執(zhí)行HystrixClientWithFallBackFactory中的回退操作,
控制臺上輸出錯(cuò)誤日志:
其他配置
請求壓縮
spring cloud feign
支持對請求與相應(yīng)進(jìn)行GZIP壓縮瑟慈,以減少通信過程中的性能損耗桃移,我們只需要通過下面的兩個(gè)參數(shù)設(shè)置,就能開啟請求與相應(yīng)的壓縮功能葛碧。
feign:
compression:
request:
enabled: true
response:
enabled: true
同時(shí)借杰,我們還可以對請求壓縮做一些更細(xì)致的設(shè)置,比如下面的配置內(nèi)容指定壓縮的請求數(shù)據(jù)類型进泼,并設(shè)置了請求壓縮的大小下限蔗衡,只有超過了這個(gè)大小的請求才會對其進(jìn)行壓縮。
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
min-request-size: 2048
而mime-types
屬性和min-request-size
都是默認(rèn)值
參考資料
Feign request/response compression
日志配置
spring cloud Feign
在構(gòu)建被@FeignClient
注解修飾的服務(wù)客戶端時(shí)缘琅,會為每一個(gè)客戶端都創(chuàng)建一個(gè)feign.Logger
實(shí)例粘都,我們可以利用改日志對象的DEBUG
模式來幫助分析Feign的請求細(xì)節(jié)∷⑴郏可以在application.yml
配置logging.level.<feignClient>
的參數(shù)配置格式來開啟指定feign客戶端的debug日志翩隧,其中<feignClient>
為feign客戶端定義接口的完整路徑
logging:
level:
com.zhihao.miao.pay.service.UserService: debug
但是,只添加了該配置還無法實(shí)現(xiàn)對debug日志的輸出。這是因?yàn)閒eign客戶端默認(rèn)的Logger.Level對象定義為NONE級別堆生,該級別不會記錄任何Feign調(diào)用過程中的信息专缠,所以我們需要調(diào)整它的級別,針對全局的日志級別淑仆,可以在應(yīng)用主類中加入Logger.Level的Bean創(chuàng)建涝婉,
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class,args);
}
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
也可以實(shí)現(xiàn)配置類,然后在Feign客戶端來指定配置類以實(shí)現(xiàn)是否需要調(diào)整不同的日志級別蔗怠,比如說下面的實(shí)現(xiàn):
@Configuration
public class FullLogConfiguration {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
@FeignClient(value = "user-service",configuration = FullLogConfiguration.class)
public interface UserService {
@RequestMapping("/user/index")
String index();
@RequestMapping("/user/hello")
String hello();
@RequestMapping(value = "/user/hello1",method = RequestMethod.GET)
String hello1(@RequestParam("username") String username);
@RequestMapping(value = "/user/hello2",method = RequestMethod.GET)
User hello2(@RequestHeader("username") String username, @RequestHeader("age") Integer age);
@RequestMapping(value = "/user/hello3",method = RequestMethod.POST)
String hello3(@RequestBody User user);
}
訪問localhost:7070/pay/hello1?username=zhihao.miao
接口墩弯,控制臺上打印如下信息:
對于Feign的Logger級別主要有下面4類,可根據(jù)實(shí)際需要進(jìn)行調(diào)整使用:
- none:不記錄任何信息
- basic:僅記錄請求方法寞射,url以及響應(yīng)狀態(tài)碼和執(zhí)行時(shí)間
- headers:除了記錄basic級別的信息之外渔工,還會記錄請求和響應(yīng)的頭信息。
- FULL:記錄所有請求與響應(yīng)的明細(xì)桥温,包括頭信息引矩,請求體,元數(shù)據(jù)等侵浸。
參考資料
Feign logging
代碼地址
代碼地址