SpringCloud系列-2Ribbon简介与应用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud系列-2Ribbon简介与应用相关的知识,希望对你有一定的参考价值。
参考技术A负载均衡:建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
负载均衡说白了其实就是伴随着微服务架构的诞生的产物;过去的单体架构,前端页面发起请求,然后后台接收请求直接处理,这个时候不存在什么负载均衡;但是随着单体架构向微服务架构的演变,每个后台服务可能会部署在多台服务器上面,这个时候页面请求进来,到底该由哪台服务器进行处理呢?所以得有一个选择,而这个过程就是负载均衡;同时选择的方案有很多种,例如随机挑选一台或者一台一台轮着来,这就是负载均衡算法。
也可以通过例子来帮助自己记忆,就好比古代皇帝翻牌子,最开始皇帝只有一个妃子,那不存在翻牌子这回事,再怎么翻也只能是这一个妃子侍寝。但是随着妃子多了,就得有选择了,不能同时让所有妃子一起侍寝。
工作原理图如下:
HTTP重定向服务器是一台普通的应用服务器,其唯一个功能就是根据用户的HTTP请求计算出一台真实的服务器地址,并将该服务器地址写入HTTP重定向响应中返回给用户浏览器。用户浏览器在获取到响应之后,根据返回的信息,重新发送一个请求到真实的服务器上。DNS服务器解析到IP地址为192.168.8.74,即HTTP重定向服务器的IP地址。重定向服务器计根据某种负载均衡算法算出真实的服务器地址为192.168.8.77并返回给用户浏览器,用户浏览器得到返回后重新对192.168.8.77发起了请求,最后完成访问。
这种负载均衡方案的优点是比较简单,缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差;同时,重定向服务器本身的处理能力有可能成为瓶颈,整个集群的伸缩性规模有限;因此实践中很少使用这种负载均衡方案来部署。
DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网。人们在通过浏览器访问网站时只需要记住网站的域名即可,而不需要记住那些不太容易理解的IP地址。在DNS系统中有一个比较重要的的资源类型叫做主机记录也称为A记录,A记录是用于名称解析的重要记录,它将特定的主机名映射到对应主机的IP地址上。如果你有一个自己的域名,那么要想别人能访问到你的网站,你需要到特定的DNS解析服务商的服务器上填写A记录,过一段时间后,别人就能通过你的域名访问你的网站了。DNS除了能解析域名之外还具有负载均衡的功能,下面是利用DNS工作原理处理负载均衡的工作原理图:
由上图可以看出,在DNS服务器中应该配置了多个A记录,如:
www.woshuaiqi.com IN A 192.168.8.75;
www.woshuaiqi.com IN A 192.168.8.76;
www.woshuaiqi.com IN A 192.168.8.77;
因此,每次域名解析请求都会根据对应的负载均衡算法计算出一个不同的IP地址并返回,这样A记录中配置多个服务器就可以构成一个集群,并可以实现负载均衡。上图中,用户请求www.woshuaiqi.com,DNS根据A记录和负载均衡算法计算得到一个IP地址192.168.8.77,并返回给浏览器,浏览器根据该IP地址,访问真实的物理服务器192.168.8.77。所有这些操作对用户来说都是透明的,用户可能只知道www.woshuaiqi.com这个域名。
DNS域名解析负载均衡有如下优点:
同时,DNS域名解析也存在如下缺点:
请求过程:
用户发来的请求都首先要经过反向代理服务器,服务器根据用户的请求要么直接将结果返回给用户,要么将请求交给后端服务器处理,再返回给用户。
反向代理负载均衡
优点:
缺点:
代码实现
由于不同的服务器配置不同,因此它们处理请求的能力也不同,给配置高的服务器配置相对较高的权重,让其处理更多的请求,给配置较低的机器配置较低的权重减轻期负载压力。加权轮询可以较好地解决这个问题。
1.思路
根据权重的大小让其获得相应被轮询到的机会。
可以根据权重我们在内存中创建一个这样的数组s1,s2,s2,s3,s3,s3,然后再按照轮询的方式选择相应的服务器。
2.缺点:请求被分配到三台服务器上机会不够平滑。前3次请求都不会落在server3上。
nginx实现了一种平滑的加权轮询算法,可以将请求平滑(均匀)的分配到各个节点上。
代码实现
代码实现
思路:这里我们是利用区间的思想,通过一个小于在此区间范围内的一个随机数,选中对应的区间(服务器),区间越大被选中的概率就越大。
已知:
s1:[0,1] s2:(1,3] s3 (3,6]
代码实现
代码实现
REST(Representational State Transfer)表象化状态转变(表述性状态转变),基于HTTP、URI、XML、JSON等标准和协议,支持轻量级、跨平台、跨语言的架构设计。是Web服务的一种新的架构风格(一种思想)。
符合上述REST原则的架构方式称为RESTful
在Restful之前的操作:
http://127.0.0.1/user/query/1 GET 根据用户id查询用户数据
http://127.0.0.1/user/save POST 新增用户
http://127.0.0.1/user/update POST 修改用户信息
http://127.0.0.1/user/delete/1 GET/POST 删除用户信息
RESTful用法:
http://127.0.0.1/user/1 GET 根据用户id查询用户数据
http://127.0.0.1/user POST 新增用户
http://127.0.0.1/user PUT 修改用户信息
http://127.0.0.1/user DELETE 删除用户信息
之前的操作是没有问题的,大神认为是有问题的,有什么问题呢?你每次请求的接口或者地址,都在做描述,例如查询的时候用了query,新增的时候用了save,其实完全没有这个必要,我使用了get请求,就是查询.使用post请求,就是新增的请求,我的意图很明显,完全没有必要做描述,这就是为什么有了restful.
幂等性:对同一REST接口的多次访问,得到的资源状态是相同的。
安全性:对该REST接口访问,不会使用服务器端资源的状态发生改变。
SpringMVC原生态的支持了REST风格的架构设计
所涉及到的注解:
---@RequestMapping
---@PathVariable
---@ResponseBody
传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是RestTemplate。
定义一个简单的restful接口
使用RestTemplate访问该服务
从这个例子可以看出,使用restTemplate访问restful接口非常的 简单粗暴无脑 。(url, requestMap, ResponseBean.class)这三个参数分别代表 请求地址、请求参数、HTTP响应转换被转换成的对象类型。
RestTemplate方法的名称遵循命名约定,第一部分指出正在调用什么HTTP方法,第二部分指示返回的内容。本例中调用了restTemplate.postForObject方法,post指调用了HTTP的post方法,Object指将HTTP响应转换为您选择的 对象类型 。
RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。
实际上,由于Post 操作的非幂等性,它几乎可以代替其他的CRUD操作.
目前主流的负载方案分为以下两种:
Ribbon 是一个基于 HTTP和TCP的客户端负载均衡工具。通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求自动转换成客户端负载均衡的服务调用。
Spring Cloud Ribbon 虽然只是一个工具类框架,它不像服务注册中心、配置中心、API 网关那样需要独立部署,但是它几乎存在于每一个 Spring Cloud 构建的微服务和基础设施中。因为微服务间的调用,API 网关的请求转发等内容,实际上都是通过 Ribbon 来实现的(https://github.com/Netflix/ribbon)。
Ribbon主要提供:
Ribbon模块介绍:
与Nginx的对比
应用场景的区别:
1.先创建两个服务,用于负载均衡
Server 1 和Server2 的端口号要不同,不然起不来
Server 1接口如下:
Server 2接口如下:
启动类都是一样的,如下:
2.创建一个调用方来请求这个接口
引依赖包
配置启动类,并注入 RestTemplate
配置一下 application.properties,如下:
3.验证
再创建一个 测试方法来验证是否生效,放在test 目录下面,代码如下:
先启动 两个server ,然后在 测试 测试类 ,结果如下:
从结果可以看出实现了负载均衡,默认是 轮询策略,Client1和 clien2 依次调用。
Ribbon 中有两种和时间相关的设置,分别是请求连接的超时时间和请求处理的超时时间,设置规则如下:
Ribbon可以通过下面的配置项,来限制httpclient连接池的最大连接数量、以及针对不同host的最大连接数量。
负载均衡的核心,是通过负载均衡算法来实现对目标服务请求的分发。Ribbion中默认提供了7种负载均衡算法:
验证方法:
1.在BaseLoadBalancer.chooseServer()方法中加断点
2.在RandomRule.choose()方法增加断点,观察请求是否进入。
自定义负载均衡的实现主要分几个步骤:
ILoadBalancer 接口实现类做了以下的一些事情:
修改application.properties文件
在ribbon负载均衡器中,提供了ping机制,每隔一段时间,就会去ping服务器,由 com.netflix.loadbalancer.IPing 接口去实现。
单独使用ribbon,不会激活ping机制,默认采用DummyPing(在RibbonClientConfiguration中实例化),isAlive()方法直接返回true。
ribbon和eureka集成,默认采用NIWSDiscoveryPing(在EurekaRibbonClientConfiguration中实例化的),只有服务器列表的实例状态为up的时候才会为Alive。
IPing中默认内置了一些实现方法如下。
在网络通信中,有可能会存在由网络问题或者目标服务异常导致通信失败,这种情况下我们一般会做容错设计,也就是再次发起请求进行重试。
Ribbon提供了一种重试的负载策略:RetryRule,可以通过下面这个配置项来实现
由于在单独使用Ribbon的机制下,并没有开启Ping机制,所以所有服务默认是认为正常的,则这里并不会发起重试。如果需要演示重试机制,需要增加PING的判断。
1.引入依赖包
2.创建一个心跳检查的类
3.修改mall-portal中application.properties文件,添加自定义心跳检查实现,以及心跳检查间隔时间。
4.在goods-service这个模块中,增加一个心跳检查的接口
5.测试服务启动+停止,对于请求的影响变化。
LoadBalancer 是Spring Cloud自研的组件,支持WebFlux。
由于Ribbon停止更新进入维护状态,所以Spring Cloud不得不研发一套新的Loadbalancer机制进行替代。
1.引入Loadbalancer相关jar包
2.定义一个配置类,这个配置类通过硬编码的方式写死了goods-service这个服务的实例列表,代码如下
3.创建一个配置类,注入一个LoadBalancerClient
4.修改测试类
5.为了更好的看到效果,修改goods-service模块,打印每个服务的端口号码。
SpringCloud-03 Netflix Ribbon学习笔记
一、Ribbon简介
1、什么是Ribbon?
Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具,它可以很好地控制HTTP和TCP客户端的行为。 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!
2、Ribbon能干什么?
- LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
- 常见的负载均衡软件有 Nginx、Lvs(中国人研发的) 等等。
其中lvs是中国技术专家章文嵩发明的
- Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。
负载均衡简单分类:
- 集中式LB
即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方! - 进程式 LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。 Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
二、使用Ribbon
1、客户端导入依赖
<!--引入Eureka的依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--引入ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
2、application.yml配置
server:
port: 801
eureka:
client:
register-with-eureka: false #不向eureka注册自己
service-url:
defaultZone: http://localhost:7001/eureka/ #去哪个地方获取
3、Controller配置
和前面两节不一样的是,用Ribbon做负载均衡,地址不能写死,也就是不能和前面的一样写成一个具体的值如:localhost:8001,而是这个微服务的名字,也就是这个名字,如下。
package com.you.controller;
import com.you.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@ResponseBody
public class DeptComsumerController
@Autowired
RestTemplate restTemplate;
// public static final String REST_URL_PREFIX = "http://localhost:8001";
public static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@GetMapping("/consumer/dept/getDept/id")
public Dept getDeptOfId(@PathVariable("id") Long id)
System.out.println(REST_URL_PREFIX+"/dept"+"/aDept/"+id);
return restTemplate.getForObject(REST_URL_PREFIX + "/dept" + "/aDept/"+id, Dept.class);
4、Config的配置
在此文件里,增加了@LoadBalanced注解,该注解的作用是让RestTemplate有了负载均衡的能力,而且默认的负载均衡算法是轮询(也就是一个一个的尝试),可以使用系统配备的负载均衡算法,也可以自己写自己的负载均衡算法。
package com.you.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean
@Bean
@LoadBalanced //ribbon
/*配置负载均衡实现RestTemplate*/
/*IRule*/
/*RoundRobinRule 轮询 */
/*RandomRule 随机*/
/*AvailabilityFilteringRule 优先过滤掉跳闸、访问故障的服务,对剩下的进行轮询 */
public RestTemplate getRestTemplate()
return new RestTemplate();
5、启动类的配置
package com.you;
import com.tan.tanRule;
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
/*下面是处理负载均衡算法*/
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = tanRule.class)
public class DeptConsumer_80
public static void main(String[] args)
SpringApplication.run(DeptConsumer_80.class,args);
三、Ribbon实现负载均衡
为了实现负载均衡,扩充一下服务提供者,将原来的一个服务提供者,改为三个。
- 新建三个module,springboot-provider-8002、springboot-provider-8003。
- 参考springboot-provider-8001,修改application.xml(主要是端口号,数据库名,instance-id),其中application-name要保持一致。和微服务的名字一样。
- 启动Eureka_7001,启动这个三个提供者,根据自己的情况,如果电脑性能比较差,可以少启动一个。启动consumer_80。
访问consumer_80配置的Getmapping地址,然后不断的刷新,会看到依次访问三个数据库,并且一直重复,这就是默认的负载均衡算法:轮询
四、设计负载均衡算法
1、80启动类的改动
@RibbonClient()注释的应用,在psvm上面添加该注释,其具体内容为@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = tanRule.class),其中name的值即为微服务的名字,configuration的值对应的就是自己写的路由类
2、自定义路由类
需要注意,自定义的路由类,不可以用启动类放在同一目录,一般要比启动类高一级目录,放在同一目录下,需要配置CompentScan。
package com.tan;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
public class tanRule
@Bean
public IRule myRule()
return new tanRandomRule();
3、负载均衡算法的实现
可以模仿系统中的负载均衡算法,撰写自己的负载均衡算法,如下面的例子即为:每个端口的提供者访问5次,然后切换下一个端口,全部访问完成后则重新开始,代码如下:
package com.tan;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class tanRandomRule extends AbstractLoadBalancerRule
int total = 0;
int currentIndex = 0;
public tanRandomRule()
@SuppressWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key)
if (lb == null)
return null;
else
Server server = null;
while(server == null)
if (Thread.interrupted())
return null;
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
if(total<5)
server = (Server)upList.get(currentIndex);
total++;
else
total = 0;
currentIndex++;
if(currentIndex>2)
currentIndex = 0;
server = (Server)upList.get(currentIndex);
System.out.println("CurrentIndex:"+currentIndex);
System.out.println("Total:"+total);
System.out.println("sever 的值是:"+server);
if (server == null)
Thread.yield();
else
if (server.isAlive())
return server;
server = null;
Thread.yield();
return server;
protected int chooseRandomInt(int serverCount)
return ThreadLocalRandom.current().nextInt(serverCount);
public Server choose(Object key)
return this.choose(this.getLoadBalancer(), key);
public void initWithNiwsConfig(IClientConfig clientConfig)
以上是关于SpringCloud系列-2Ribbon简介与应用的主要内容,如果未能解决你的问题,请参考以下文章