LoadBalancer 是 Spring Cloud 官方提供的一个开源的、简单易用的客户端负载均衡器,它包含在 Spring Cloud Connons 中用于替换之前的 Ribbon 组件。相较于 Ribbon ,LoadBalancer 支持 RestTemplate,也支持 WebClient 等。
客户端负载和服务器端负载的区别(为什么不使用 Nginx)
Nginx 是服务器端负载均衡,客户端所有请求都会交给 Nginx,然后由 Nginx 实现转发请求。
LoadBalancer 是本地负载均衡,在调用微服务接口时,会在注册中心上获取注册信息服务列表后缓存到 JVM,从而在本地使用 RPC 进行远程服务调用。
在项目的pom文件中添加依赖
<!--loadBalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
将服务复制一份,同时启动两个服务,通过前文的方式进行跨服务调用,即可完成负载均衡,请求被分发到了两个模块中。
LoadBalancer 的默认算法是轮询算法,简单来说就是有几个服务注册,那么就按照顺序依次轮询发送请求。除开默认的轮询算法外,LoadBalancer 提供了另一种默认算法 - 随机算法。在官网中可以查阅两种算法的具体实现和源码阅读。
那么如何进行算法切换?修改RestTemplateConfig 类
@Configuration
@LoadBalancerClient(value = "cloud-payment-service",configuration = RestTemplateConfig.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
@LoadBalancerClient 注解的 value 值表示选择的服务名称,configuration 为配置类类名。新加入的 randomLoadBalancer 方法内容来自官网,作用是将算法更改为随机算法,具体如何实现各位可以自行探索。
Feign是一个声明式的 Web 服务客户端(Web 服务客户端就是 Http 客户端),让编写 Web 服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可实现。
OpenFeign 基本就是目前微服务的事实标准。
前面我们提到,LoadBalancer + RestTemplate 利用了 RestTemplate 来对 http 请求的封装处理,形成了一套模板化的调用方法。
但是在实际开发过程中,对于服务的调用可能不止一处,也就是同一个接口会被多处调用。一般来说都会针对每个微服务自行封装一套客户端类来包装这些调用。
OpenFeign 就是在这个基础上进一步进行封装,由它来完成依赖服务接口的定义。在 OpenFeign 下,我们只需要创建一个带有注解(@FeignClient)的接口并进行配置即可完成对服务提供方的接口绑定,统一对外暴露可以被调用的接口方法,简化了调用客户端的开发量。仅需服务提供方给出一份调用接口清单,消费者直接通过 OpenFeign 调用即可。
OpenFeign 同时也集成了 LoadBalancer。与 LoadBalancer 不同的是,通过 OpenFeign 只需要以声明式的方法定义服务绑定接口即可,天生支持负载均衡。
<!--open feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在 application.yml 的 spring-cloud-consul-discovery 配置下,新增优先使用服务 ip 注册为 true 的配置:
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
# 新增配置 优先使用服务 ip 注册
prefer-agent-address: true
在使用 Feign 功能的启动类上新增 @EnableFeignClients 注解,表示开启 OpenFeign 功能(所有使用到的都需要添加,包括服务方、调用方)
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Feign80 {
public static void main(String[] args) {
SpringApplication.run(Feign80.class, args);
}
}
前文说到,我们会统一暴露接口的调用方法,所以我们需要在前文的 api 模块中新增 Feign 的通用代码。
@FeignClient(value = "cloud-payment-service")
public interface OpenFeignApi {
/**
* 对应 8001、8002 的查询接口
* @param payDTO
* @return
*/
@PostMapping("/pay/select")
public ResultVO<PayDTO> selectPayDTO(@RequestBody PayDTO payDTO);
}
通过请求进行调用
@RestController
public class FeignController {
@Resource
private OpenFeignApi openFeignApi;
@PostMapping("/feign/pay/select")
public ResultVO selectPayDTO(@RequestBody PayDTO payDTO) {
return openFeignApi.selectPayDTO(payDTO);
}
}
使用测试工具进行测试,能够成功连通进行查询。
根据前文的介绍,我们在 Consul 中有应当有一个调用方和两个服务方。当我们存在一笔请求在服务方的运行时间过长,对调用方的实际体验就会非常的不友好。
OpenFeign 提供了超时控制功能,默认值为 60 秒超时报错。
在调用方模块 application. yml 的 spring-cloud 下添加配置
openfeign:
client:
config:
default:
# 连接超时时间
connect-timeout: 8000
# 读取超时时间,一般情况下,当响应时间超过8s时,绝大部分用户都会关闭请求
read-timeout: 8000
如果希望某个指定服务的超时时间,那么将上述配置的 default 名称更改为对应的服务名即可
openfeign:
client:
config:
cloud-payment-service:
# 连接超时时间
connect-timeout: 8000
# 读取超时时间,一般情况下,当响应时间超过8s时,绝大部分用户都会关闭请求
read-timeout: 8000
局部配置优于全局配置,当同时存在时,按照服务名的配置为准。
当分布式微服务内的模块逐渐增多时,我们很难保证每一次的全链路请求都能够成功。所以我们需要一套能够在请求失败后重新发起请求的方式。
OpenFeign 提供了一个重试机制。机制默认关闭,需要手动开启。
在调用方模块新增配置类,其中,注释的代码为初始默认配置,return 返回的新 Retryer 为开启后的配置,内部参数含义见代码注释。
@Configuration
public class FeignConfig {
@Bean
public Retryer retryer(){
// 默认配置 never 不走重试策略
// return Retryer.NEVER_RETRY;
// 初始间隔时间100ms,最大重试间隔时间1s,最大调用次数3次(失败后重试两次)
return new Retryer.Default(100, 1, 3);
}
}
当我们不对 OpenFeign 做多余的配置时,OpenFeign 默认使用 JDK 自带的 HttpURLConnection 发送 HTTP 请求。由于自带的 HttpURLConnection 没有线程池,导致性能和效率都比较低下。
OpenFeign 提供了修改默认 HTTP 的功能。
在调用方模块的 pom 文件下新增依赖
<!--httpclient5-->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<!--版本可交给主pom管理, 仅供演示-->
<version>5.3</version>
</dependency>
<!--feign-hc5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
<!--版本可交给主pom管理, 仅供演示-->
<version>13.1</version>
</dependency>
application.yml 的spring-cloud-openfeign 下,添加如下配置即可
httpclient:
hc5:
# 开启 Apache Http5 配置
enabled: true
OpenFeign 支持对请求和响应进行 GZIP 压缩,以减少通信过程中的性能损耗
在调用方模块的 application.yml 的 application.yml 的 spring-cloud-openfeign 下添加如下配置即可
compression:
# 开启请求压缩
request:
enabled: true
# 压缩类型
mime-types: application/json, application/xml
# 最小请求大小
min-request-size: 2048
# 开启响应压缩
response:
enabled: true
OpenFeign 提供了一个原生的日志打印的功能,可减少对于外部组件的依赖
在上文提到的重试机制的配置类中新增日志方法
@Bean
Logger.Level feignLoggerLevel(){
// 请求和响应的日志
return Logger.Level.FULL;
}
之后,在 aplication.yml 中添加 Feign 日志的配置
logging:
level:
com:
atguigu:
cloud:
api:
OpenFeignApi: debug
日志级别分为四个:NONE、BASIC、HEADERS、FULL。日志密度依次递增。配置内容从 level 开始,为带有包名的全路径名,OpenFeignApi 为我们之前在 api 模块定义的接口方法,含义是 Feign 对于这个接口开启日志打印功能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。