上一期我们搭建了网关和配置中心、注册中心。如果还没有看过往期文章的可以先了解: springcloud:什么是分布式微服务,如何学习微服务(一) springcloud:微服务涉及哪些技术、有哪些核心组件(二) springcloud:网关组件gateway详解(三) springcloud:注册中心、配置中心组件nacos详解(四) springcloud:保姆式教程-从零搭建微服务(五)
但是还有一个核心问题没有解决,那就是微服务间的通信问题。比如我们订单服务中需要调用商品列表数据,而商品列表数据是在商品服务中获取的,那么我们就需要在订单服务中调用商品服务的接口。这种服务间调用,就称为组间通信
目前常用的组件通信有RestTemplate和feign。RestTemplate的使用相对比较麻烦,需要写上服务IP等比较底层的信息,而feign则不需要,更加符合本地调用的方式。
本着最核心技术快速上手的理念,我们先针对更加常用的feign组件进行讲解。后续再详谈RestTemplate
1. Feign简介Feign是声明式的web service客户端,它让服务间的调用更加简单。使得整个调用变得像本地调用一样简单。
Feign中包含了Hystrix和ribbon。所以feign支持接口负载均衡,以及接口的熔断、降级、限流等处理。并且支持Http请求和响应的压缩。
1、要使用feign,我们需要引入feign的依赖
org.springframework.cloud
spring-cloud-starter-openfeign
2.2.6.RELEASE
需要注意的是,Feign默认是POST请求,如果要支持带参数的GET请求,那么还需要引入feign-httpclient依赖
io.github.openfeign
feign-httpclient
10.10.1
同时因为是web api,那么肯定还要引入Spring web依赖,已经引入过就不用重复引用了
org.springframework.boot
spring-boot-starter-web
2、在调用方服务的启动类中添加注解@EnableFeignClients
2.1 通过IP直接调用服务直接通过IP来调用的话只需要在调用方的服务中创建Feign接口类。其中name是服务名,url是实际的接口地址,如果有多个可以用逗号隔开
接口中书写的是对应到controller的URL地址。比如说用户controller中有一个list接口,url是list。那么Feign接口类中对应的方法也要和controller中的接口地址保持一致
@FeignClient(name = "order-server",url = "localhost:8081")
public interface OrderApi {
@GetMapping("list")
public List list();
}
有一个注意的点,如果controller中统一的接口前缀,比如说/user。在feign接口类中是不能通过@RequestMapping来申明的,而是必须在每个方法中添加上这个前缀,如下所示:
@FeignClient(name = "order-server",url = "localhost:8081")
public interface OrderApi {
String PREFIX = "order";
String LIST = PREFIX + "/list";
String PAGE = PREFIX + "/page";
@GetMapping(LIST)
public List list();
@GetMapping(PAGE)
public List page();
}
2.2 通过nacos调用
直接使用服务名即可,无需定义url。在调用方中创建该接口即可
@FeignClient(name = "product-server")
public interface ProductApi {
@GetMapping("list")
public List list();
}
测试
我们基于上节课搭建的springcloud项目来进行测试,为了不影响上节课的代码,单独创建一个springcloud2用于本章测试
1、在order-server服务中引入依赖
org.springframework.cloud
spring-cloud-starter-openfeign
2.2.7.RELEASE
io.github.openfeign
feign-httpclient
10.10.1
com.example
product-server-feign
0.0.1-SNAPSHOT
compile
2、在order-server中创建ProductApi接口类
@FeignClient(name = "product-server",url = "localhost:9091")
public interface ProductApi {
@GetMapping("list")
public List list();
}
3、在order-server启动类中添加@EnableFeignClients注解
4、在在order-server的OrderController中创建接口用于调用feign接口类中的方法
@RestController
@AllArgsConstructor
public class OrderController {
private final IOrderService orderService;
private final ProductApi productApi;
@GetMapping("list")
public List list(){
return orderService.list();
}
@GetMapping("listProduct")
public List listProduct(){
return productApi.list();
}
}
5、测试访问http://localhost/order-server/listProduct
可以看到我们在order服务用调用了product服务的list接口,其结果返回来商品列表信息
feign包含了ribbon,因此可以使用ribbon的重试、超时机制,只需要在配置文件中修改:
- 重试配置
#同一台实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetries=1
#重试负载均衡其他的实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetriesNextServer=1
#是否所有操作都重试
ribbon.OkToRetryOnAllOperations=false
- 超时配置:这里的连接超时指的是连接接口的时间,而业务逻辑超时时间指的是连接成功后业务逻辑的执行时间
#连接超时时间(ms)
ribbon.ConnectTimeout=1000
#业务逻辑超时时间(ms)
ribbon.ReadTimeout=6000
2.4 服务熔断、降级
在配置熔断降级之前我们需要理解什么是服务熔断?什么是服务降级?
服务熔断:当连续连接失败次数达到阈值后,直接报错,之后的相同请求也直接报错,这个措施称为熔断。相当于我们常见的保险丝,当确定了服务不能访问时,就直接断开后续的连接
服务降级:当连续连接失败次数达到阈值或者超时后,给请求方一个保底信息,这个保底信息可以是: (1)返回友好性的页面,比如重试按钮、联系邮箱或者一些基础的静态页面 (2)返回提示信息,并把数据写入到MQ中,后续通过MQ来重试 (3)返回友好性的提示信息,比如“稍后再来”、“服务忙,请稍后重试”等,不做其他处理 我们把以上这样的措施称为降级。
默认feign是不会用Hytrix来做服务降级等处理的,所以要使用的话需要在配置文件中开启:
feign.hystrix.enabled=true
2.4.1 降级配置
feign利用fallback类来实现请求失败后的回调方法 1、创建回调类
@Component
public class UserProviderBack implements UserApi {
@Override
public Map findById(@RequestParam("id") Integer id){
// 降级,给出友好性提示
return "服务走远了,请稍后重试";
}
@Override
public Map getMap(@RequestParam Map map){
// 降级,直接返回空数据
return null;
}
}
2、声明回调类
@FeignClient(name="user-provider",fallback= UserProviderBack.class)
public interface UserApi {
@GetMapping("/findById")
public Map findById(@RequestParam("id") Integer id);
@GetMapping("/getMap")
public Map getMap(@RequestParam Map map);
}
如果需要根据不同的错误类型来进行不同的降级处理,那么可以使用FallbackFactory
@Component
public class ProductFeignCallBackFactory implements FallbackFactory {
@Override
public ProductFeignNacos create(Throwable cause) {
return new ProductFeignNacos() {
@Override
public String getInfo() throws ClientException {
if(cause instanceof FeignException.InternalServerError){
return "远程服务器挂掉咯";
}else if(cause instanceof RuntimeException){
// 熔断
throw (RuntimeException) cause;
}
return "Cloud7DayProperties{'name':'兜底数据','price':0, 'size': 0}";
}
};
}
}
同时@FeignClient
里的调用也要改成fallbackFactory
@FeignClient(name = "product-server",
contextId="product-server-nacos",
fallbackFactory = ProductFeignCallBackFactory.class)
public interface ProductFeignNacos {
...
}
2.4.2 服务熔断
因为feign中附带了hytrix,我们通过hytrix来实现熔断
1、引入依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2.2.6.RELEASE
2、启动类添加注解 @EnableHystrix
3、修改配置文件
# feign对hytrix的支持默认是关闭的
feign:
hystrix:
enabled: true # 降级熔断:开启hytrix
#在10秒内,发生20次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
command:
default: # 或者填写具体的服务名称,default默认为全部服务
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 3000 # 请求超时时间,单位毫秒
circuitBreaker:
sleepWindowInMilliseconds: 10000 # 窗口期,当触发熔断机制后指定时间内,此该接口不会再被访问
requestVolumeThreshold: 20 # 请求阈值
errorThresholdPercentage: 50 # 错误百分比阈值
触发效果
因为feign集成了hytrix,而hytrix可以通过信号量SEMAPHORE或线程THREAD来实现限流
信号量形式
# 熔断
#在10秒内,发生10次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
command:
default: # 或者填写具体的服务名称,default默认为全部服务
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 # 请求熔断超时时间,单位毫秒
strategy: SEMAPHORE # 通过信号量限流
semaphore:
maxConcurrentRequests: 10 # 允许的最大并发
circuitBreaker:
sleepWindowInMilliseconds: 10000 # 窗口期
requestVolumeThreshold: 5 # 请求阈值
errorThresholdPercentage: 50 # 错误百分比阈值
限流效果
线程池形式
# 熔断
#在10秒内,发生10次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
command:
default: # 或者填写具体的服务名称,default默认为全部服务
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 # 请求熔断超时时间,单位毫秒
strategy: THREAD # 通过线程池限流,默认值
threadpool:
default:
coreSize: 1 # 并发执行的最大线程数,默认10
maxQueueSize: 2 # BlockingQueue的最大队列数,默认值-1
queueSizeRejectionThreshold: 2 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5
限流效果
好了,本期我们针对feign组件的讲解就到这里了,针对限流的配置我们并不推荐使用feign来实现,如果要做也是在fallback做处理,后续会详细讲解微服务中的限流措施。文中的测试代码也已经放到了git项目中,欢迎大家下载体验
下期预告1、微服务框架进阶讲解