服务间通信
微服务间可以使用 HTTP 协议,RESTful 规范进行通信。Spring Cloud 提供了 2 种 RESTful 调用方式:Ribbon 和 Feign 。
Ribbon
客户端软负载组件,支持Eureka对接,支持多种可插拔LB策略。依赖 spring-cloud-starter-netflix-eureka-client
中已经默认加载了 Ribbon 的依赖。
Ribbon作为Spring Cloud的负载均衡机制的实现:
- Ribbon可以单独使用,作为一个独立的负载均衡组件。只是需要我们手动配置 服务地址列表。
- Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表(DiscoveryClient),并基于负载均衡算法,请求其中一个服务提供者实例。
- Ribbon与OpenFeign和RestTemplate进行无缝对接,让二者具有负载均衡的能力。OpenFeign默认集成了ribbon。
Ribbon 的自定义配置以及一些高级使用可以参考官方文档:Client Side Load Balancer: Ribbon
Ribbon组成
官网首页:https://github.com/Netflix/ribbon
ribbon-core: 核心的通用性代码。api一些配置。
ribbon-eureka:基于eureka封装的模块,能快速集成eureka。
ribbon-examples:学习示例。
ribbon-httpclient:基于apache httpClient封装的rest客户端,集成了负载均衡模块,可以直接在项目中使用。
ribbon-loadbalancer:负载均衡模块。
ribbon-transport:基于netty实现多协议的支持。比如http,tcp,udp等。
调用方式
使用RestTemplate
|
|
以上代码中使用 @LoadBalanced
注解,这样就可以让 RestTemplate 在请求时拥有客户端负载均衡的能力。
|
|
使用DiscoveryClient
|
|
负载均衡算法
Ribbon 提供了很多负载均衡的策略。详情可见:
策略名称 | 策略描述 |
---|---|
BestAvailableRule(最低并发策略) | 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。 |
AvailabilityFilteringRule(可用过滤策略) | 会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。 |
WeightedResponseTimeRule(响应时间加权策略) | 据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。 |
RetryRule(重试策略) | 先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。 |
RoundRobinRule(轮询策略) | 以简单轮询选择一个服务器。按顺序循环选择一个server。 |
RandomRule(随机策略) | 随机选择一个服务器。 |
ZoneAvoidanceRule(区域权衡策略)【默认实现】 | 复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。 |
切换负载均衡策略
注解方式
|
|
如上,配置IRule的新值,直接可以切换负载均衡策略
配置文件方式
给所有的服务指定负载均衡策略:
|
|
给特定的服务指定负载均衡策略:
|
|
Ribbon拦截
在服务调用的时候,我们可能不仅仅是简单地进行调用,会涉及到一些接口的校验、权限的校验等。要实现这些,可以实现ClientHttpRequestInterceptor
接口。
|
|
添加到resttemplate中
|
|
超时
Ribbon的配置如下:
|
|
重试
|
|
使用ribbon重试机制,请求失败后,每个6秒会重新尝试
Feign
Feign 是 Netflix 开发的声明式、模板化的 HTTP 客户端,Feign 的使用非常简单,创建一个接口,在接口上加入一些注解,这样就完成了代码开发。
Feign 是一个 Http 请求调用的轻量级框架,可以以 Java 接口注解的方式调用 Http 请求,而不用像 Java 中通过封装 HTTP 请求报文的方式直接调用。通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。Feign 封装 了HTTP 调用流程,面向接口编程
Spring Cloud OpenFeign
Spring Cloud OpenFeign 通过自动配置并绑定到Spring Environment和其他Spring编程模型习惯用法,为Spring Boot应用程序提供OpenFeign集成。
服务调用
使用 Feign 必须引入 spring-cloud-starter-openfeign
。在启动类 Application
上 @EnableFeignClients
注解。
服务提供者
|
|
服务消费者:简单使用
简单使用Feign不需要代码耦合,但是需要硬编码接口的信息。如下:
|
|
@FeignClient
也可以脱离Eureka使用,如:@FeignClient(name = "xxx",url="")
这个url就是接口的地址。
服务消费者:接口继承方式
此方法需要引入服务提供者提供的接口jar包。
|
|
以上代码中,@FeignClient(value = "producer-service")
指定了使用哪一个服务。
高级用法
自定义配置
feign的默认配置类是:org.springframework.cloud.openfeign.FeignClientsConfiguration。默认定义了feign使用的编码器,解码器等。
允许使用@FeignClient的configuration的属性自定义Feign配置。自定义的配置优先级高于上面的FeignClientsConfiguration。
|
|
如上面所示,在配置类上加上@Configuration注解,且该类在@ComponentScan所扫描的包中,那么该类中的配置信息就会被所有的@FeignClient共享。如果想要对某些的@FeignClient添加指定的配置,则:不指定@Configuration注解(或者指定configuration,用注解忽略),而是手动使用:@FeignClient(name = "service-valuation",configuration = FeignAuthConfiguration.class)
拦截器
上面代码中:
|
|
RequestInterceptor
是一个请求拦截器,我们可以继承它做很多事情,如:
|
|
如果是BasicAuth认证,可以重写BasicAuthRequestInterceptor。
然后,在配置文件中添加:
|
|
配置文件扩展
指定服务名配置:
|
|
通用配置:
|
|
属性配置比Java代码优先级高。也可通过配置设置java代码优先级高:
|
|
压缩
|
|
超时
Feign默认支持Ribbon;Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制。
保留原始异常信息
当调用服务时,如果服务返回的状态码不是200,就会进入到Feign
的ErrorDecoder
中,因此如果我们要解析异常信息,就要重写ErrorDecoder
原理
- 主程序入口添加@EnableFeignClients注解开启对Feign Client扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClient注解。
- 当程序启动时,会进行包扫描,扫描所有@FeignClient注解的类,并将这些信息注入Spring IoC容器中。当定义的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象封装了HTTP请求需要的全部信息,如请求参数名、请求方法等信息都在这个过程中确定。
- 然后由RequestTemplate生成Request,然后把这个Request交给client处理,这里指的Client可以是JDK原生的URLConnection、Apache的Http Client,也可以是Okhttp。最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。
参考资源
- Service Discovery: Eureka Clients
- Service Discovery: Eureka Server
- 深度剖析服务发现组件Netflix Eureka
- 深入理解Eureka之源码解析
- 深入理解Ribbon之源码解析
- 深入理解Feign之源码解析