0%

SpringCloud基础大全-服务调用

一、Ribbon

1.1 概述

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具

简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。Ribbon目前进入维护模式

LB负载均衡(Load Balance):将用户的请求平摊的分配到多个服务上,从而达到系统的高可用(HA)

常见的负载均衡的软件有Nginx、LVS

Ribbon与Nginx的区别:

  • Ribbon是本地负载均衡客户端,在调用服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术
  • Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后由Nginx实现转发请求。即负载均衡是由服务端实现的

进程内LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

Ribbon服务调用=负载均衡+RestTemplate调用

1.2 接口实现

  • eureka-client的依赖中已经包含了Ribbon
  • 消费侧的Controller接口如下(使用RestTemplate的getForEntity方法):
1
2
3
4
5
6
7
8
9
10
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id){
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
if(entity.getStatusCode().is2xxSuccessful()){
return entity.getBody();
}
else{
return new CommonResult(444,"操作失败");
}
}

1.3 Ribbon负载规则

  • RoundRobinRule:轮询
  • RandomRule:随机
  • RetryRule:先按照RoundRobinRule的策略获取服务,若获取失败则在指定时间内进行重试,获取可用的服务
  • WeigbtedBesponseTimeBule:RoundBobinRule扩展,响应速度越快的实例选择权更越大,越容易被选择.
  • BestAvailableRule:会先过婆填臾于多次访问故赜呃处天断路嚣跳灵球态的服务、然反选择一个并发曩悬少鲍服务
  • AvailabilityFileteringRule:先过滤掉故障实例,在选择并发较小的实例
  • ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器

1.4 负载规则替换

  • 原先的消费者端,其主启动类在com.atguigu.springcloud包下,而Ribbon修改负载规则要求不能放在同一个包下,所以需要在当前工程下创建一个新包com.atguigu.myrule,然后在创建自己的规则配置类
1
2
3
4
5
6
7
@Configuration
public class MySelfRule{
@Bean
public IRule myRule(){
return new RandomRule(); // 定义为随机
}
}
  • 配置类创建完成后,还需要在项目的主启动类上添加注解进行配置
1
2
3
4
5
6
7
8
@SpringBootApplilcation
@EnableEurekaClient
@RibbonClient(name="CLOUD-PAYMNET-SERVICE",configuration=MySelfRule.class)
public class OrderMain80{
public static void main(String[] args){
SpringApplication.run(OrderMain80.class, args);
}
}
  • 替换完成以后,服务调用的效果就可以通过接口调用观察出来

1.5 算法原理

轮询算法: rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。每次服务重启后会重新从1开始计算请求次数

1.6 手写算法

二、OpenFeign

2.1 使用

Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需要创建一个接口,并在接口上添加注解即可

首先还是老样子,新建一个maven工程cloud-consumer-feign-order80,然后配置service层和主启动类

  • 引入依赖
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 添加接口注解@FeignClient,接口中的方法对应了服务提供者的接口方法
1
2
3
4
5
6
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") // value为微服务名称
public interface PaymentFeignService{
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
}
  • 添加著启动类注解@EnableFeignClients
1
2
3
4
5
6
7
@SpringBootApplilcation
@EnableFeignClients
public class OrderMain80{
public static void main(String[] args){
SpringApplication.run(OrderMain80.class, args);
}
}
  • 最后Controller层调用接口方法
1
2
3
4
5
6
7
8
9
public class OrderFeignController{
@Resource
private PaymentFeignService paymentFeignService; // 调用本项目的接口方法

@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}

2.2 超时控制

消费者在访问服务提供者时,存在一个等待时间,OpenFeign默认等待1秒钟,超过后则报错,以下模拟超时情况,在服务提供者端添加一个请求超时接口

1
2
3
4
5
6
7
8
9
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout(){
try{
TimeUnit.SECONDS.sleep(3); // 等待3秒
}catch(InterruptedException e){
e.printStackTrace();
}
return serverPort;
}

在消费者端调用此接口时则会出现报错,可以在yml中配置Feign的超时时间

1
2
3
4
5
6
# 设置feign客户端超时时间(OpenFeign默认支持Ribbon)
ribbon:
# 指的是建立连接后所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000 # 单位ms
# 指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000

2.3 日志功能

OpenFeign提供了日志打印的功能

日志级别:

  • NONE:默认的,不显示任何日志
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间
  • HEADERS:除了BASIC中定义的信息外,还有请求和响应的头信息
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

在消费者侧的config包下新建FeignConfig类

1
2
3
4
5
6
7
@Configuration
public class FeignConfig{
@Bean
Logger.level feignLoggerLevel(){
return Logger.level.FULL;
}
}

在yml中开启Feign日志功能

1
2
3
4
logging:
level:
# feign日志以配置的日志级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug