6.2 Ribbon介绍
-
Spring Cloud Ribbon 是一套基于 Netflix Ribbon 实现的客户端(consumer)负载均衡和服务调用工具。
-
Ribbon 是 Spring Cloud Netflix 模块的子模块,它是 Spring Cloud 对 Netflix Ribbon 的二次封装。通过它,我们可以将面向服务的 REST 模板(RestTemplate)请求转换为客户端负载均衡的服务调用。
-
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用,Spring Cloud 将其与 Netflix 中的其他开源服务组件(例如 Eureka、Feign 以及 Hystrix 等)一起整合进 Spring Cloud Netflix 模块中,整合后全称为 Spring Cloud Netflix Ribbon
-
简单的说,Ribbon将NetFlix的中间层服务连接在一起。Ribbon的客户端组件提供一系列完整的配置项如:连接超时、重试等等。也就是在配置文件中列出LoadBalancer(简称LB:负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等)去连接这些机器。我们也很容易使用Ribbo实现自定义的负载均衡算法!
-
Ribbon 是 Spring Cloud 体系中最核心、最重要的组件之一。它虽然只是一个工具类型的框架,并不像 Eureka Server(服务注册中心)那样需要独立部署,但它几乎存在于每一个使用 Spring Cloud 构建的微服务中。
-
Spring Cloud 微服务之间的调用,API 网关的请求转发等内容,实际上都是通过 Spring Cloud Ribbon 来实现的,包括后续我们要介绍的 OpenFeign也是基于它实现的。
6.3 Ribbon在客户端进行服务调用
- Ribbon 也需要和 RestTemplate(Rest 模板)配合使用,以实现微服务之间的调用。
- 上节介绍过:RestTemplate 是 Spring 家族中的一个用于消费第三方 REST 服务的请求框架。RestTemplate 实现了对 HTTP 请求的封装,提供了一套模板化的服务调用方法。通过它,Spring 应用可以很方便地对各种类型的 HTTP 请求进行访问。
- 点开RestTemplate类发现源码中针对各种类型的 HTTP 请求都提供了相应的方法进行处理,例如 HEAD、GET、POST、PUT、DELETE 等类型的 HTTP 请求,分别对应 RestTemplate 中的 headForHeaders()、getForObject()、postForObject()、put() 以及 delete() 方法。
- 沿用基础工程的消费者microservice-cloud-consumer-dept-80的微服务,演示 Ribbon 是如何实现服务调用的。项目结构如下:
- 在其 pom.xml 中补充引入所需的依赖Spring Cloud Eureka/Ribbon的依赖
由于新版的spring-cloud-starter-netflix-eureka-client和spring-cloud-starter-netflix-ribbon会存在jar包冲突的问题,无法显示负载均衡的随机策略和自定义策略,只显示默认的轮询策略,所以我们使用旧版的spring-cloud-starter-eureka
<!--Spring Cloud Eureka 客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--Spring Cloud Ribbon 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-loadbalancer</artifactId>
<version>2.3.0</version>
</dependency>
- 在类路径(即 /resource 目录)下的配置文件 application.yml补充eureka的设置,配置内容如下
server:
port: 80
servlet:
context-path: /app
#Jetty specific properties
jetty:
threads:
acceptors: -1 #Number of acceptor threads to use. When the value is -1, the default, the number of acceptors is derived from the operating environment.
selectors: -1 #Number of selector threads to use. When the value is -1, the default, thenumber of selectors is derived from the operating environment.
max-http-form-post-size: 200000 #Maximum size of the form content in any HTTP post request.
eureka:
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: true #指示此客户端是否应从 eureka 服务器获取 eureka 注册表信息
service-url: #监控页面地址
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #发布的服务注册中心地址,单机
defaultZone: http://eurekaserver7001.com:7001/eureka/,http://eurekaserver7002.com:7002/eureka/,http://eurekaserver7003.com:7003/eureka/ #集群版 将当前的 Eureka Server 注册到 7003 和 7003 上,形成一组互相注册的 Eureka Server 集群
- 修改ConfigBean 的配置类,在RestTemplate 注入容器时标注@LoadBalanced以在客户端使用 RestTemplate 请求服务端时,开启负载均衡(Ribbon)开启
package com.example.config;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.RestTemplate;
/**
* @author CNCLUKZK
* @create 2022/9/7-23:17
*/
@Configuration
public class ConfigBean {
@Bean //将 RestTemplate 注入到容器中
@LoadBalanced //在客户端使用 RestTemplate 请求服务端时,开启负载均衡(Ribbon)
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean
public ConfigurableServletWebServerFactory configurableServletWebServerFactory(){
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.setPort(80);
factory.setContextPath("/app");
factory.setAcceptors(-1);
factory.setSelectors(-1);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"));
return factory;
}
}
- 修改DeptConsumerController,使用注册到 Spring Cloud Eureka 服务注册中心中的服务,即访问application.name某个服务下的请求,这个服务由多个请求可供选择,只修改REST_URL_PROVIDER_PREFIX常量即可,其他不用修改。
注意服务名不能用下划线
package com.example.controller;
import com.zk.springcloud.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
//这种方式是直调用服务方的方法,根本没有用到 Spring Cloud
//private static final String REST_URL_PROVIDER_PREFIX = "http://localhost:8001";
//面向微服务编程,即通过微服务的名称来获取调用地址
//使用注册到 Spring Cloud Eureka 服务注册中心中的服务,即 访问application.name某个服务下的请求,这个服务由多个请求可供选择
private static final String REST_URL_PROVIDER_PREFIX = "http://MICROSERVICE-CLOUD-PROVIDER-DEPT";
RestTemplate 是一种简单便捷的访问 restful 服务模板类,是 Spring 提供的用于访问 Rest 服务的客户端模板工具集,提供了多种便捷访问远程 HTTP 服务的方法
// 消费者不应该有service层,只要在controller中获取到provider的请求地址即可访问服务
//RestTemplate....供我们直接调用就可以了!注册到spring中
//(String url, Class<T> responseType, Map<String, ?> uriVariables)亲求实体
@Autowired
private RestTemplate template;
//不同于rpc那种DubboReference引用服务提供者的service,rpc是 接口调用 通过 反射
//获取指定部门信息
@GetMapping("/consumer/dept/get/{id}")
public Dept getDeptById(@PathVariable("id") Integer id){
return template.getForObject(REST_URL_PROVIDER_PREFIX+"/dept/get/"+id,Dept.class);
}
//获取部门列表
@GetMapping("/consumer/dept/list")
public List<Dept> getDepts(){
return template.getForObject(REST_URL_PROVIDER_PREFIX+"/dept/list",List.class);
}
@RequestMapping("/consumer/dept/add")
public boolean addDept(Dept dept){
return template.postForObject(REST_URL_PROVIDER_PREFIX+"/dept/add",dept,Boolean.class);
}
}
- 在 microservice-cloud-consumer-dept-80 的主启动类上,使用 @EnableEurekaClient 注解来开启 Eureka 客户端功能,代码如下。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class MicroserviceCloudConsumerDept80Application {
public static void main(String[] args) {
SpringApplication.run(MicroserviceCloudConsumerDept80Application.class, args);
}
}
-
依次启动服务注册中心 microservice-cloud-eureka-7001、服务提供者 microservice-cloud-provider-dept-8001 以及服务消费者 microservice-cloud-consumer-dept-80。
-
使用浏览器访问“http://eurekaserver7001.com/app/consumer/dept/list”或http://localhost/app/consumer/dept/list,结果如下图。
- 所以Ribbon和Eureka整合以后,容户端可以直接利用提供的服务名调用,不用关心服务的IP地址和端口号,是从注册中心集群中的任意一个,获取服务列表的特定服务。
- 开发过程中的问题:Caused by: java.lang.IllegalStateException: No instances available for MICROSERVICE-CLOUD-PROVIDER-DEPT找不到实例
- **造成的原因:**由于spring-cloud-starter-netflix-eureka-client 3.0以上的版本中已经存在了ribbon负载均衡的依赖,在依赖中又导入了Ribbon造成依赖冲突。
- 所以把该依赖注释掉就可以了。
<!--Spring Cloud Ribbon 依赖-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>-->
下一篇:SpringCloud-15-Ribbon实现负载均衡
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123814.html