热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringCloud笔记Ribbon负载均衡服务调用(八)

1.概述SpringCloudRibbon是基于NetflixRibbon实现的一套客户端负载均衡工具。Ribbon客户端组件提供了一系列完善的配置项,如连接超时&

1.概述

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。Ribbon客户端组件提供了一系列完善的配置项,如连接超时,重试等。简单地说,就是在配置文件中列出Load Balancer后面所有的机器,Ribbon会自动帮我们基于某种规则(如轮询,随机连接等)去连接这些机器,我们很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon官网:https://github.com/Netflix/ribbon,根据官网信息,可以看到Ribbon现在进入了维护模式,替换方案是Loadbalancer。

负载均衡的表现就是,将用户的请求分摊到多个服务器上,从而达到高可用的目的。常见的负载均衡软件有:Nginx、LVS、硬件F5等。

Nginx是服务器端负载均衡,客户端的请求都发给Nginx,Nginx实现分发,将请求发送到不同的服务器上。

Ribbon是客户端负载均衡,在调用微服务接口的时候,会在注册中心拿到注册信息服务列表缓存到本地JVM,在客户端通过某种规则,确定请求的链接,发送请求进行调用。

集中式LoadBalancer:在服务的消费方和提供方之间使用的独立LoadBalancer设备(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责把请求通过某种策略转发至服务的提供方。

进程内LoadBalancer:将LoadBalancer集成到消费方,消费者从服务注册中心获取到可用地址,自己再从这些地址中,选择一个作为要访问的服务器。Ribbon就属于进程内LoadBalancer,它只是一个类库,集成消费者进程,消费者通过它获取服务提供方的地址。


2.Ribbon负载均衡演示

之前,我们好像并没有加入Ribbon的依赖,也实现了负载均衡,其实在spring-cloud-starter-netflix-eureka-client坐标下,是引入了spring-cloud-starter-netflix-ribbon的,所以,我们仅仅只需要添加一个@LoadBalanced就可以实现负载均衡。

RestTemplate常见的方法有getForObject()、getForEntity()、postForObject()、postForEntity()方法。其中*ForObject()方法返回对象为响应体中数据转换成的对象,基本理解为JSON。*ForEntity()方法返回对象是ResponseEntity对象,包含了响应中的信息,比如响应头,响应状态码,响应体等。

将cloud-eureka-server7001、cloud-eureka-server7002的配置文件改成集群模式,让7001和7002互相注册,将cloud-provider-payment8001、cloud-provider-payment8002的配置文件改成集群模式,将cloud-consumer-order80的配置文件改成集群模式。在cloud-consumer-order80模块中的OrderController里,添加两个方法,分别调用getForEntity()和postForEntity()方法。

@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult getPaymentById2(@PathVariable("id") Long id) {ResponseEntity entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);System.out.println("status code=" + entity.getStatusCode());System.out.println("headers=" + entity.getHeaders());if (entity.getStatusCode().is2xxSuccessful()) {return entity.getBody();} else {return new CommonResult(404, "查找失败");}
}
@GetMapping("/consumer/payment/create2")
public CommonResult create2(Payment payment) {return restTemplate.postForEntity(PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();
}

先启动Eureka注册中心,再启动两个生产者,最后启动消费者,浏览器发送请求来调用*ForEntity()方法进行测试。在浏览器端,可以看到port的值,不断在8001和8002之前进行切换。


3.Ribbon核心组件IRule

IRule是一个接口,它有多个实现类,分别代表不同的负载均衡策略。使用IDEA生成一下它的子类的关系图(点击IRule,按下Ctrl+Alt+B获取所有子类,按下Ctrl+A全选子类,按下Ctrl+Alt+U,选择Java Class Diagrams)。


  • com.netflix.loadbalancer.RoundRobinRule:轮询
  • com.netflix.loadbalancer.RandomRule:随机
  • com.netflix.loadbalancer.RetryRule:先按照RoundRobinRule策略获取服务,如果获取服务失败,在指定时间内重试,获取可用服务
  • com.netflix.loadbalancer.WeigthResponseTimeRule:对RoundRobinRule扩展,根据响应速度进行选择,响应速度越快,优先级越高
  • com.netflix.loadbalancer.BestAvailableRule:先过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • com.netflix.loadbalancer.AvailabilityFilterRule:先过滤掉故障实例,再选择并发最小的实例
  • com.netflix.loadbalancer.ZoneAvoidanceRule:默认规则,符合判断server所在区域的性能和server可用性选择服务器

在这里提到,自定义Ribbon Client的时候,我们不能将自定义的配置类放在@ComponentScan所扫描的包及其子包下,否则我们自定义的配置类会被所有Ribbon Client所共享,达不到特殊化定制的目的了。

新建MyRule配置类,注意包名,这里我放在com.atguigu.rule包下,假设我改成了RandomRule。

package com.atguigu.rule;import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyRule {@Beanpublic IRule iRule() {return new RandomRule();}
}

告诉主启动类,使用的哪一个Ribbon Client。

package com.atguigu.springcloud;import com.atguigu.rule.MyRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;@SpringBootApplication
@EnableEurekaClient
// 自定义Ribbon规则适用于哪个服务(服务名要大写),自定义Ribbon规则对应的类
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", cOnfiguration= MyRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class, args);}
}

通过浏览器进行访问,查看浏览器给出的端口信息,发现自定义的随机规则生效了。


4.Ribbon负载均衡算法

负载均衡算法:REST接口第几次请求数字%服务器集群总数量=实际调用服务器位置下标,每次重启服务器REST接口计数从1开始。找一个IRule接口的实现类,这里选择RoundRobinRule类,查看它的实现。

public Server choose(ILoadBalancer lb, Object key) {if (lb == null) {log.warn("no load balancer");return null;} else {Server server = null;int count = 0;while(true) {// 获取server,如果获取失败,进行重试,如果10次后,还没获取到server,就报错if (server == null && count++ <10) {// 获取所有状态是up的serverList reachableServers = lb.getReachableServers();// 获取所有serverList allServers = lb.getAllServers();int upCount = reachableServers.size();int serverCount = allServers.size();if (upCount != 0 && serverCount != 0) {// 计算出要访问的server下标int nextServerIndex = this.incrementAndGetModulo(serverCount);server = (Server)allServers.get(nextServerIndex);if (server == null) {Thread.yield();} else {if (server.isAlive() && server.isReadyToServe()) {return server;}server = null;}continue;}log.warn("No up servers available from load balancer: " + lb);return null;}if (count >= 10) {log.warn("No available alive servers after 10 tries from load balancer: " + lb);}return server;}}
}private int incrementAndGetModulo(int modulo) {int current;int next;// 利用cas和自旋锁,获取next的值do {current = this.nextServerCyclicCounter.get();next = (current + 1) % modulo;} while(!this.nextServerCyclicCounter.compareAndSet(current, next));return next;
}

下面手写一个本地的负载均衡。

cloud-eureka-server7001和cloud-eureka-server7002集群方式启动。

在cloud-provider-payment8001和cloud-provider-payment8002的controller里,加入如下方法,用于返回访问接口。

@GetMapping("/payment/loadbalance")
public String getLoadBalancePort() {return serverPort;
}

修改cloud-consumer-order80模块。

将配置类中的@LoadBalanced注解去掉,添加LoadBalancer.java接口和MyLoadBalancer.java实现类,同样,在MyLoadBalancer.java里用到cas和自旋锁。

package com.atguigu.springcloud.balance;import org.springframework.cloud.client.ServiceInstance;import java.util.List;public interface LoadBalancer {ServiceInstance instances(List serviceInstanceList);
}

package com.atguigu.springcloud.balance;import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;@Component
public class MyLoadBalancer implements LoadBalancer {private AtomicInteger atomicInteger = new AtomicInteger(0);@Overridepublic ServiceInstance instances(List serviceInstanceList) {int index = getAndIncrement() % serviceInstanceList.size();return serviceInstanceList.get(index);}public final int getAndIncrement() {int current, next;do {current = this.atomicInteger.get();next = current >= Integer.MAX_VALUE ? 0 : current + 1;} while (!this.atomicInteger.compareAndSet(current, next));System.out.println("next=" + next);return next;}
}

在OrderController.java里注入MyLoadBalancer实例和DiscoveryClient实例。添加一个请求方法,输出负载均衡后需要访问的端口号,测试负载均衡效果是否有效。

@GetMapping("/consumer/payment/loadbalance")
public String getPaymentLoadBalance() {// 通过discoveryClient,使用服务提供者对应的应用名称大写获取所有服务实例List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");if (instances == null || instances.size() == 0) {return null;}// instances()方法拿到所有的服务实例,使用访问次数%服务实例数量求得目标服务的下标,返回下标对应的服务实例ServiceInstance instance = myLoadBalancer.instances(instances);URI uri = instance.getUri();// 获取这个实例的uri// /payment/loadbalance请求对应服务提供者controller中新加的映射方法,返回当前服务提供者的serverPort的值return restTemplate.getForObject(uri + "/payment/loadbalance", String.class);
}

启动Eureka注册中心集群,启动服务提供者,启动服务消费者,通过浏览器访问http://localhost/consumer/payment/loadbalance,可以看到端口号的轮询变化,此时我们自己的负载均衡轮询策略生效。


推荐阅读
  • k8s+springboot+Eureka如何平滑上下线服务
    k8s+springboot+Eureka如何平滑上下线服务目录服务平滑上下线-k8s版本目录“上篇介绍了springboot+Euraka服务平滑上下线的方式,有部分小伙伴反馈k ... [详细]
  • MateCloud 3.5.8 发布,基于 Spring Cloud Alibaba 的微服务框架
    基于SpringCloudAlibaba的微服务框架MateCloud3.5.8已经发布。此版本更新内容包括:功能升级针对MybatisPlus3.4.3新特性进行微调依赖升级升级至SpringCloud2020.0.3升级至Mybatis-Plus3.4.3详 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了SpringCloudRibbon部分源码相关的知识,希望对你有一定的参考价值。1:ribbon是提供通过servi ... [详细]
  • zuul 路由不生效_Zuul网关到底有何牛逼之处?竟然这么多人在用~
    作者:kosamino来源:cnblogs.comjing99p11696192.html哈喽,各位新来的小伙伴们,大家好& ... [详细]
  • 学习笔记(34):第三阶段4.2.6:SpringCloud Config配置中心的应用与原理第三阶段4.2.6SpringCloud Config配置中心的应用与原理
    立即学习:https:edu.csdn.netcourseplay29983432482?utm_sourceblogtoedu配置中心得核心逻辑springcloudconfi ... [详细]
  • 2018深入java目标计划及学习内容
    本文介绍了作者在2018年的深入java目标计划,包括学习计划和工作中要用到的内容。作者计划学习的内容包括kafka、zookeeper、hbase、hdoop、spark、elasticsearch、solr、spring cloud、mysql、mybatis等。其中,作者对jvm的学习有一定了解,并计划通读《jvm》一书。此外,作者还提到了《HotSpot实战》和《高性能MySQL》等书籍。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 熟练掌握Spring Cloud,终于成为Java工程师的面试门槛 ... [详细]
  • 1.脚本功能1)自动替换jar包中的配置文件。2)自动备份老版本的Jar包3)自动判断是初次启动还是更新服务2.脚本准备进入ho ... [详细]
  • 服务网关与流量网关
    一、为什么需要服务网关1、什么是服务网关传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关& ... [详细]
  • TiDB | TiDB在5A级物流企业核心系统的应用与实践
    TiDB在5A级物流企业核心系统的应用与实践前言一、业务背景科捷物流概况神州金库简介二、现状与挑战神州金库现有技术体系业务挑战应对方案三、TiDB解决方案测试迁移收益问题四、说在最 ... [详细]
author-avatar
mobiledu2502858787
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有