一、Ribbon 负载均衡服务调用
1.1 概念
SpringCloud Ribbon 是基于Netflix Ribbon实现的一套 客户端负载均衡的工具
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端负载均衡算法和服务调用,Ribbon客户端组件提供一系列完善的配置项如 连接超时,超时重试等,简单来说,就是在配置文件中列出Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接)去连接这些机器,我们很容易使用Ribbon实现自定义的负载均衡算法。
LB(负载均衡):
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到高可用HA
Ribbon本地负载均衡客户端 VS Nginx 服务端负载均衡区别
Nginx 是服务器负载均衡,客户端的所有请求都会交给Nginx,然后由nginx实现转发请求,即负载均衡是由服务端实现的。
Ribbon本地负载均衡,在调用微服务接口的时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术
- 集中式LB:即在服务的消费方和提供方之间使用独立的LB设施,可以是硬件,如F5也可以是软件,如nginx,由该设施负责把访问请求通过某种策略转发到服务的提供方。
- 进程内LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器
- ribbon就属于进程LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
1.2 Ribbon简单负载均衡演示
Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他的所需请求的客户端结合使用,与eureka结合知识其一个实例
Ribbon 在工作的时候分为两步
- 第一步先选择EurekaServer,它优先选择在同一个区域内负载较少的Server
- 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址,其中Ribbon提供了多种策略:比如轮询,随机和根据响应时间加权。
在没有引入Ribbon jar包的时候也可以使用Ribbon 原因:
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka客户端集成了Ribbon
Ribbon + RestTemplate
RestTemplate
- getForObject 方法 (返回对象为响应体中数据转换成的对象,基本上理解为Json)
- getForEntity方法 (返回对象为ResponseEntity对象,包含了响应中的一些重要的信息,如如响应头,响应状态码,响应体)
- postForObject
- postForEntity
- get请求方法
- post请求方法
@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默认自带的负载均衡规则
1.3.1 IRULE: 根据特定的算法中从服务列表中选择一个要访问的服务
1.RoundRobinRule : 轮询
2. RandomRule: 随机
3. RetryRule : 先按照RoundRobinRule的策略获取服务,如果获取失败后则在指定时间内进行充实,获取可用的服务
4. WeightedResponseTimeRule: 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
5. BestAvailableRule: 会先过滤掉由于多次访问故障而处于短裤器跳闸状态的服务,然后选择一个并发量小的服务
6. AvailabilityFulteringRule : 先过滤掉故障实例,在选择并发较小的实例
7. ZoneAvoiddanceRule : 默认规则,复合判断server所在区域的性能和server 的可用性选择服务器
1.3.2 怎么替换LB策略
@springBootApplication 中的 @CompentScan 不能和Ribbon 的注解放在一起
- 新建myrule 包
- 在myrule包下新建MyselfRule类
@Configuration
public class MySelfRule {
@Bean
public IRule myRule() {
return new RandomRule();
}
}
- 主启动类添加@RibbonClient
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
1.3.3 负载均衡算法的原理,源码,手写
负载均衡算法 : rest接口的第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启动后rest几口计数从1开始。
list = 2 instance
1 % 2 = 1 -> index = 1 -> list.get(index)
2 % 2 = 2 -> index = 0 -> list.get(index)
3 % 2 = 1 -> index = 1 -> list.get(index)
源码 :
**nextServerCyclicCounter 是 AutomicInteger
compareAndSet CAS自选锁
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
手写 :
原理 + JUC (CAS + 自选锁的复习)
@GetMapping("/payment/lb")
public String getPaymentLB() {
return SERVER_PORT;
}
- loadBalance接口
package com.xzq.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
interface LoadBalancer {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
package com.xzq.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.sql.SQLOutput;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
private final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!atomicInteger.compareAndSet(current, next));
System.out.println("第几次访问,次数next:" + next);
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
二、OpenFeign服务接口与调用
2.1 概述
Feign 是一个声明式的webService客户端,使用feign能让编写WebService客户端更加简单
它的使用方法是定义一个服务接口然后再上面添加注解,Feign也支持可拔插式的编码器和解码器,SpringCloud对Feign进行了封装,使用SpringMVC标准注解和HttpMessageConverters,Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
Feign能干什么 ?
Feign旨在编写Java Http 客户端变得更加容易
前面在使用Ribbon + RestTemplate 的时候,利用RestTemplate 对http 请求的封装处理,行程了一套模板化的调用方法,但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端来包装这些依赖服务的调用,所以Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需创建一个接口使用注解的方式来配置他(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用SpringCloud Ribbon时,自动封装服务调用客户端的开发量。
Feign 继承了Ribbon
利用ribbon 维护了Payment的服务列表信息,并且通过轮询的方式实现了客户端的负载均衡,与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
Feign与OpenFeign
- Feign 是SpringCloud组件中的一个轻量级的RestFul的Http客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务.Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
- OpenFeign 是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等,OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping竹节虾的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
2.2 OpenFeign使用方式
微服务调用接口 + @FeignClient
1.新建cloud-consumer-feign-order80
<!--openfeign-->
<dependency>