10.rabbion负载均衡和服务调用
spring cloud ribbon是基于NetflixRibbon实现的一套客户端(注意是客户端)负载均衡工具
LB负载均衡(Load Balance)是什么
简单的说就是将用户的请求平摊到多个服务器上,从而达到系统的HA(高可用)
常见的负载均衡有软件Nginx,LXS,硬件F5等
Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡区别
1.Nginx是服务器负载均衡,客户所有请求都会交给Nginx,然后由Nginx实现转发请求。即负载均衡是由服务端实现的。
2.Ribbon是本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册服务列表后缓存到JVM本地,从而在本地实现RPC远程服务调用技术!
集中式LB:
即在服务的消费方换和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责将访问请求通过某种策略转发到
服务的提供方!
进程内LB:
将LB逻辑集成到消费方,消费方从服务注册中心获知到有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器!
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它获取到服务提供方的地址!
Ribbon其实就是一个软负载均衡的客户端组件,它可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例!
Ribbon在工作时分成两步:
1.先选择EurekaServer,它优先选择在同一个区域内负载较少的server
2.再根据用户指定的策略,在从server渠道的服务注册列表中选择一个地址
其中的ribbon提供了多种策略;比如轮询、随机和根据响应时间加权等等!
总结:重要
ribbon:就是负载均衡+RestTemplate调用
RestTemplate的常用方法解析:
1.返回Object对象
2.getForEntity()返回的是ResponseEntity对象
Rabbion的核心组件IRule接口:
IRule:根据特定算法从服务列表中选取一个要访问的服务(有以下7种算法)
1.com.netflix.loadbalancer.RoundRobinRule:轮询
2.com.netflix.loadbalancer.RandomRule:随机
3.com.netflix.loadbalancer.RetryRule:先安装RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内进行重试,获取可用服务
4.WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的示例选择权重越大,月容易被选中
5.BestAvailableRule:会先过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
6.AvailabilityFilteringRule:会先过滤掉故障实例,再选择并发较小的实例
7.ZoneAvoidanceRule:默认规则,复合判断Server所在的区域的性能和server的可用性选择服务器
重点1:ribbon的负载均衡策略更换(ribbon的默认负载算法是轮询)
pom文件的解释:
因为在客户端引入了:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
spring-cloud-starter-netflix-eureka-client里包含有
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.1.RELEASE</version>
<scope>compile</scope>
</dependency>
如图所示:无需再单独引入ribbon的包
1.注意点,ribbon选择自己的负载方法时,需要创建自己的配置类,该配置类不能在springboot的包扫描范围内!
1.在自定义配置类中代码如下:
@Configuration
public class MyRule {
@Bean
public RandomRule getRandomRule()
//重点1:随机策略
return new RandomRule();
}
}
2.在springboot启动类上加上该注解:@RibbonClient 1.value:表示调用的服务在eureka的注册名称,configuration:是指自定义的配置类位置
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "CLOUD-PROVIDER",configuration = MyRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
如何编写自己的负载均衡
原理解析:
1.主要用到的是:List<ServiceInstance> instances =discoveryClient.getInstances(serverName)根据服务注册中心中的注册服务名称获取服务实例
2.根据下表获取到具体的ServiceInstance服务实例,String uri = instances.get(index).getUri().toString(),获取远程调用的uri即(http://192.168.137)
3.需要考虑的是代表访问次数的数字线程安全问题,因为会有多个客户端调用更改该数字:这里涉及到了CAS和自旋解锁等问题,等后面学习了JUC会明白
具体的代码设计如下:设计自己的轮询算法
1.负载均衡的接口
//传入远程服务的名称,获取到具体服务实例的URI
public interface MyLB {
String getUri(String serverName);
}
2.接口实现如下:这就是简单的轮询算法,可以在此基础上加上自己的逻辑等等,
但重点是:
1.discoveryClient获取服务相关信息
2.AtomicInteger:CAS和自旋解锁等JUC知识
@Component
@Slf4j
public class MyLbImp implements MyLB{
//重点1:使用discoveryClient获取服务相关信息
@Resource
private DiscoveryClient discoveryClient;
//重点2:使用AtomicInteger线程安全的去自增数字
private AtomicInteger atomicInteger;
public MyLbImp() {
this.atomicInteger = new AtomicInteger(0);
}
@Override
public String getUri(String serverName) {
List<ServiceInstance> instances = discoveryClient.getInstances(serverName);
int size = instances.size();
int current;
int next;
do {
current = atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!atomicInteger.compareAndSet(current, next));
log.info("current:" + current + " next:" + next);
int index = next % size;
String uri = instances.get(index).getUri().toString();
log.info("访问URI:" + uri);
return uri;
}
}
3.控制层调用:
@Resource
private MyLB myLB;
public CommResult queryUserById(@PathVariable("id") int id){
log.info("客户端根据id查询用户,用户id:"+id);
//重点1:根据服务名称获取对应的轮询访问地址!
String uri=myLB.getUri("PRODUCER-USER-API") + "/producer/queryUserById/" + id;
log.info("访问路径:"+uri);
CommResult result = restTemplate.getForObject(uri, CommResult.class);
return result;
}
7种负载均衡策略详解:https://blog.csdn.net/sufu1065/article/details/123492451