Spring-Cloud 学习笔记-(4)负载均衡器Ribbon

目录

  • Spring-Cloud 学习笔记-(4)负载均衡器Ribbon
  • 1、前言
  • 2、什么是负载均衡
    • 2.1、问题分析
    • 2.2、什么是Ribbon
  • 3、快速入门
    • 3.1、实现方式一
      • 3.1.1、修改代码
    • 3.2、实现方式二
      • 3.2.1、启动类
      • 3.2.2、调用代码
      • 3.2.3、测试
      • 3.2.4、实现原理
      • 3.2.5、断点调式
    • 3.3、修改轮询策略
    • 3.4、重载机制
      • 3.4.1、为什么要有重载机制
      • 3.4.2、实现代码

Spring-Cloud 学习笔记-(4)负载均衡器Ribbon

1、前言

  • 上个章节我们做了什么?

    上个章节我们说了用eureka来实现服务的注册与发现,并且用过服务的seviceId拉取了服务列表List<ServiceInstance> instances = discoveryClient.getInstances("user-service") 从而实现服务的调用方(order-service)调用服务的提供方(user-service)

  • 本章节我们会做什么?

    负载均衡

2、什么是负载均衡

2.1、问题分析

​ 上个章节我们实现了服务之间的调用,把原来代码里面写死的ip地址,换成用serviceId拉取服务列表,然后从服务列表中获取实例的方式,虽然代码变得复杂了,但是思想上我们得到的升级,但是还是存在一个问题,就是ServiceInstance instance = instances.get(0);每次我们都取同一个ip,要想每次使用不同的ip,我们自己就要写负载均衡算法,从多个实例当中获取某一个实例进行调用,这次我们这一章节讲的就是负载均衡器Ribbon,它里面内置了很多负载均衡的算法,帮我们从实例列表中获取一个实例。

2.2、什么是Ribbon

1441417-20181220002144278-1607410729.png

3、快速入门

我们按照上节课方法启动,一个Eureka注册中心,两个(方便演示负载均衡)服务的提供方(user-service),最后我们修改服务调用方(order-service)代码

pom文件

<!-- ribbon -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

3.1、实现方式一

3.1.1、修改代码

    //注入  RibbonLoadBalancerClient@Autowiredprivate LoadBalancerClient client;
...//通过serviceId 拉取服务列表//List<ServiceInstance> instances = discoveryClient.getInstances("user-service");//ServiceInstance instance = instances.get(0);ServiceInstance instance = client.choose("user-service");
String jsonStr = restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/api/v1/user/2", String.class);

之前我们是通过serviceId(“user-service”)获取到的是服务列表,现在我们直接可以通过serviceId,返回的是单个实例,不是因为列表里面只有一个实例,是因为choose方法中已经帮我们做了复杂均衡了。

3.2、实现方式二

3.2.1、启动类

/*** 把RestTemplate注入到Spring容器中*/
@Bean
@LoadBalanced //增加注解   让RestTemplate内置一个负载均衡器
public RestTemplate restTemplate(){return new RestTemplate();
}

3.2.2、调用代码

String jsonStr = restTemplate.getForObject("http://user-service/api/v1/user/2", String.class);

之前我们把serviceId交出去,别人帮我们取一堆,或者取一个,现在直接把serviceId写在url路径中。

3.2.3、测试

启动order-service

访问:http://localhost:8781/api/v1/order/2

1441417-20181220002156804-1047745316.png

3.2.4、实现原理

其实实现方式二低层就是用的实现方式一,只不过实现方式二加了一个拦截器LoadBalancerInterceptor对RestTemplate请求做了拦截,然后把请求路径中的serviceId("user-service")拿到,然后通过方式一获取某一个实例进行调用。

3.2.5、断点调式

我们按两下shift搜索到LoadBalancerInterceptor这个拦截器,在intercept方法中打好断点

1441417-20181220002221036-307164370.png

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {//1.拿到请求路径URI originalUri = request.getURI();//2.从路径中获取serviceIdString serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);//3.执行execute方法.. 我们接着看execute方法return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}// RibbonLoadBalancerClient类中
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {//4.根据serviceId获取到负载均衡器ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);//5.通过负载均衡器拿到某一个实例..我们接着看getServer方法Server server = this.getServer(loadBalancer);if (server == null) {throw new IllegalStateException("No instances available for " + serviceId);} else {RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));return this.execute(serviceId, ribbonServer, request);}}//RibbonLoadBalancerClient类中
protected Server getServer(ILoadBalancer loadBalancer) {//6.判断负载均衡器是不是为空,不为空调用chooseServer("default")方法,我们接着看return loadBalancer == null ? null : loadBalancer.chooseServer("default");
}//BaseLoadBalancer类中
public Server chooseServer(Object key) {//这里key是默认值“default”if (this.counter == null) {this.counter = this.createCounter();}this.counter.increment();if (this.rule == null) {return null;} else {try {//根据rule调用choose方法,其中IRule是一个接口,有很多实现类,每一个实现类对于不同的负载均衡策略,比如RandomRule随机,RoundRobinRule轮询等,我们BaseLoadBalancer类中有一个属性,   private static final IRule DEFAULT_RULE = new RoundRobinRule();代表默认轮询策略,有兴趣的可以看一下每一个实现的choose方法,比如轮询策略RoundRobinRule,底层维护一个自增长的count,每调用一次count++,然后每次用count模于服务列表的长度(比如第一次:1%5=1,第二次:2%5=2)得到的值为服务列表的位置索引,从而实现轮询。return this.rule.choose(key);} catch (Exception var3) {logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});return null;}}}

3.3、修改轮询策略

application.yml:

#--负载均衡轮询策略 
# serviceId
user-service:ribbon:#负载均衡策略的classNameNFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3.4、重载机制

3.4.1、为什么要有重载机制

在上一章中我们说到,一个正常的eureka客户端,每间隔30秒没有给服务器发送心跳,如果90秒服务器还没有收到心跳,服务器就会认为这个客户端已经宕机,但是eureka不会马上剔除,没间隔60会同意剔除这些失效的客户端,这样导致,我们服务实际上已经宕机了但是服务列表里面还有,这样服务的消费者在调用的时候就会报错,假设我们服务的提供方有五个,虽然只宕机了一台,但是还有四台是正常的,在这个时候我们条用这个服务如果出现报错信息肯定不是我们希望看到的,所有我们就有了这个重载机制,Spring Cloud 整合了Spring Retry 来增强RestTemplate的重试能力,当一次服务调用失败后,不会立即抛出一次,而是再次重试下一个服务。

3.4.2、实现代码

application.yml

#服务名称
spring:application:name: order-servicecloud:loadbalancer:retry:enabled: true # 开启Spring Cloud的重试功能#负载均衡轮询策略
user-service:ribbon:#负载均衡策略的classNameNFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRuleConnectTimeout: 250 # Ribbon的连接超时时间ReadTimeout: 1000 # Ribbon的数据读取超时时间OkToRetryOnAllOperations: true # 是否对所有操作都进行重试MaxAutoRetriesNextServer: 1 # 切换实例的重试次数MaxAutoRetries: 1 # 对当前实例的重试次数

我们测试发现,就算我们user-service宕机了,也能通过另一台服务实例获取到结果!

转载于:https://www.cnblogs.com/bigfly277/p/10147083.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248769.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

‘仿微信发表朋友圈’项目中登录功能的业务逻辑

登录功能 手机号验证码都通过后端验证后 返回用户数据 登陆成功 成功后 调用store中的setUser方法 store中的setUser方法 将后端返回的用户信息存储到localStorage中 同时登录成功后服务器会将token自动存入我们的cookie中 有过期时间 在我们请求需要登录的接口时将cookie中的…

kubernetes--配置文件

转载于:https://www.cnblogs.com/caiciadeliliang/p/10993388.html

微信动态中的背景图更换

初衷&#xff1a; 图一中的红框中的部分&#xff0c;作为用户自定义的背景图&#xff0c;如果用户没有上传也会为其自动设置一张背景图&#xff0c;当用户点击时则会出现图二中的选项 &#xff0c;点击取消则选项消失&#xff0c;点击从相册选择则会跳转本机的相册&#xff0c…

大数据学习——akka自定义RPC

实现 package cn.itcast.akkaimport akka.actor.{Actor, ActorSystem, Props} import akka.actor.Actor.Receive import com.typesafe.config.ConfigFactoryimport scala.collection.mutableimport scala.concurrent.duration._class Master(val host: String, val port: Int) …

从Client应用场景介绍IdentityServer4(一)

从Client应用场景介绍IdentityServer4&#xff08;一&#xff09; 原文:从Client应用场景介绍IdentityServer4&#xff08;一&#xff09;一、背景 IdentityServer4的介绍将不再叙述&#xff0c;百度下可以找到&#xff0c;且官网的快速入门例子也有翻译的版本。这里主要从Clie…

开发常用代码笔记

Vue 使用moment插件对时间进行格式化&#xff08;全局设置&#xff09; 下载插件 npm install moment --save 在main.js中引入插件 import moment from ‘moment’ 在main.js中定义全局过滤器 Vue.filter(dataFilter,function (dataStr,patten YYYY-MM-DD HH:mm:ss) {retur…

微信小程序——账号及开发工具

1. 注册微信小程序账号 点击我进入微信公众平台 进入后点击立即注册 注册成功且登录后进入小程序管理后台 2. 安装开发者工具 点击进入开发文档 进入安装开发工具&#xff08;稳定版本&#xff09; 一路默认下一步进行安装 3. 开发者工具的使用 使用注册微信小程序的微信号…

CSS注意的地方

content-box和border-box的区别 2018年02月27日 22:20:16 sulingliang 阅读数&#xff1a;8011盒子模型 盒子宽度&#xff1a;paddingbordercontent-width 盒子高度&#xff1a;paddingbordercontent-height 如图所示 盒子模型content-box 说明&#xff1a;在内容宽度和高度之…

机器学习笔记(6) 线性回归

先从最简单的例子开始,假设我们有一组样本(如下图的一个个黑色的圆点),只有一个特征,如下图,横轴是特征值,纵轴是label。比如横轴是房屋面积,纵轴是房屋价格. 现在我们要做什么呢&#xff1f;我们试图找到一条直线yaxb,可以尽量好的拟合这些点. 你可能要问了,为啥是直线,不是曲…

仿微信朋友圈项目梳理

项目功能简介&#xff1a; 用户通过手机号验证码进行登录和注册 可以浏览动态列表中的所有动态 登录成功后用户可以发表自己的动态 也可以对自己认可欣赏的动态进行点赞和评论 也可以通过动态结识志同道合的朋友 进行聊天和探讨 前端&#xff1a;采用Vue框架搭建 weui进行页面…

echarts鼠标事件以及自定义数据获取

事件添加方法&#xff1a; 对应官网位置&#xff1a;https://www.echartsjs.com/api.html#events 鼠标事件包括 click、dblclick、mousedown、mousemove、mouseup、mouseover、mouseout、globalout、contextmenu。 myChart.on(click, function (params) {console.log(params); …

[数学]点、线、面分割问题

平面分割问题 p条直线相交于一点时&#xff0c;分割的图形有 2*(n-1) 个&#xff0c;此时再加一条直线&#xff0c;在 2*(n-1) 的基础上再加 n条&#xff0c;此时为2*n n条曲线&#xff0c;其中有m条相交于一点&#xff0c;每两个曲线都交于两点 平面上有n条直线&#xff0c;且…

移动开发

1.移动端基础 1.1 浏览器现状 PC端浏览器 360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器&#xff08;停止服务&#xff09;、搜狗浏览器、IE浏览器 移动端浏览器 UC、QQ浏览器、欧朋浏览器、百度手机浏览器、360、搜狗、猎豹、谷歌等其他手机自带的浏览器 国…

Django之路由系统

Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。 你就是以这种方式告诉Django&#xff0c;对于这个URL调用这段代码&#xff0c;对于那个URL调用那段代码。 URLconf配置…

微信小程序——操作数据库

案例一&#xff1a;统计用户的访问次数 业务需求&#xff1a; 统计每个用户对程序的访问次数将访问次数存储到数据库中访问次数应该与用户进行关联 业务逻辑&#xff1a; 如果用户是第一次访问此程序&#xff0c;向数据库添加一条记录&#xff1a;{openid&#xff1a;45454…

shop--12.阿里云部署以及域名绑定

一、申请阿里云服务器&#xff08;1&#xff09;PC访问阿里云https://www.aliyun.com/&#xff0c;申请阿里云帐号&#xff08;可以用您的支付宝帐号登录&#xff0c;因为支付宝帐号已经进行了实名认证&#xff0c;使用起来更方便&#xff09;并登录&#xff08;2&#xff09;找…

微信小程序——获取用户的运动步数

程序获取用户信息步骤 点击参考微信文档中的授权首先程序先向用户申请访问哪些权限用户做出选择后返回给程序程序携带权限访问服务器如果用户允许则返回信息如果用户为允许则不返回 自定义函数getUserRun 为获取用户的微信运动数据 页面加载调用此函数函数中执行下面操作 1…

第一次个人作业

该作业所属课程&#xff1a;https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2作业要求地址&#xff1a;https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2/homework/3340团队名称&#xff1a;脑壳痛 作业的目标 1.通过测试其他组的软件项目学习其…

微信小程序——解决上传并部署云函数时报错ResourceNotFound.Function, 未找到函数版本,请创建后再试。 (7f2d9d2d-5eac-4575-9n57-acd66cfa587g

1. 上传部署我们的云函数 2. 报错 错误信息为&#xff1a;Error: ResourceNotFound.Function, 未找到函数版本&#xff0c;请创建后再试。 (7f2d9d2d-5eac-4575-9b57-acd66cfa587e) 3. 原因 原因是可能我们在调试的时候不小心将我们开发控制台中的云函数删除了 4. 解决办法…

【IT界的厨子】酱香鲈鱼

食材: 前世曾经回眸的鲈鱼一条(主要选刺少的鱼&#xff0c;适合孩子吃&#xff0c;大人吃随意&#xff0c;草鱼比较大) 五花肉少许(肥一些的) 豆腐 辅料: 葱姜 蒜(选) 大料 香菜 调味: 啤酒(两罐) 黄豆酱或豆瓣酱(选) 老抽 生抽 料酒 盐 步骤: 1、鱼肉划开&#xff0c;方便炖的…