1.前言
了解了 eureka 服务注册与发现 的3大角色 ,会使用RestTemplate 在消费者 调用提供者 的服务了,
那么如果引入了 集群 ,让提供者集群化 ,那么消费者如何调用 服务呢?
答案是使用 Ribbon 客户端负载均衡 ,与Nginx不同 ,Nginx是服务端的负载均衡 ,Ribbon则是运行在客户端的,原理是客户端从eureka 获取服务列表信息 ,然后根据在客户端
配置文件定义的 Ribbon 负载均衡策略来寻找要访问具体是那台服务器【即服务提供者,因为是集群 ,因此是不同的服务器 运行一样的代码,做一样的事情,因此注册在eureka上的应用名是一样的 ,但是ip或端口不同】
2.操作
(1)在消费者 的 pom.xml引入 Ribbon依赖包
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency>
完成的pom.文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.atguigu.springcloud</groupId> <!-- 父级maven模块的工程名字--> <artifactId>microservicecloud</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.example</groupId> <artifactId>demo-my-cen-test</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo-my-cen-test</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- 引入同级的maven--> <dependency> <groupId>com.example</groupId> <artifactId>demo-my-cen-2-2</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- <dependency>--> <!-- <groupId>org.yaml</groupId>--> <!-- <artifactId>snakeyaml</artifactId>--> <!--<!– <version>${version}</version>–>--> <!-- </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency><!-- 自己定义的api --> <groupId>com.atguigu.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <!-- Ribbon相关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-config</artifactId>--> <!-- </dependency>--> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>View Code
(2)
工程结构
(3)配置 RestTemplate,注册bean, ,配合注解 @LoadBalanced ,开启负载均衡
完成的配置文件
package com.example.demomycentest.cfgBean; import com.netflix.loadbalancer.BestAvailableRule; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RetryRule; import com.netflix.loadbalancer.RoundRobinRule; 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 MyConfigBean { @Bean ////添加注解@LoadBalanced,开启负载均衡。。。就这么简单 @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } //设置负载均衡策略 @Bean public IRule myRule() { //其他看看 https://www.cnblogs.com/htyj/p/10705472.html // //该策略通过遍历负载均衡器中维护的所有实例,会过滤调故障的实例,并找出并发请求数最小的一个,所以该策略的特征是选择出最空闲的实例 //return new BestAvailableRule(); //轮询策略,其实里面就是一个计数器 return new RoundRobinRule(); } }View Code
更过负载均衡策略可以查看这篇博文 : https://www.cnblogs.com/htyj/p/10705472.html
基本常用的默认策略 有 :
- RandomRule:
实现了从服务实例清单中随机选择一个服务实例的功能
- RoundRobinRule:
实现了按照线性轮询的方式一次选择每个服务实例的功能
- RetryTule:
实现了一个具备重试机制的实例选择功能
- WeightedRespinseTimeRule:
该策略是对RoundRobinRule的扩展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例,已达到更优的分配效果。
- ClientConfigEnabledRoundRobinRule
该策略较为特殊,我们一般不直接使用它。因为它本身并没有实现什么特殊的处理逻辑,真如代码中所示,在他的内部定义了一个RoundRobinRule策略,而choose函数的实现也正是使用了RoundRobinRule的线性轮询机制,所以它实现的功能实际上RoundeRobinRule相同。
虽然不能直接使用该策略,但是可以通过继承该策略,默认的choose就实现了线性轮询机制,但是可以在子类中实现更高级的策略
- BestAvailableRule
该策略通过遍历负载均衡器中维护的所有实例,会过滤调故障的实例,并找出并发请求数最小的一个,所以该策略的特征是选择出最空闲的实例
(4)application.yml文件配置
server: port: 565 spring: application: name: demo-my-cen-test datasource: type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 url: jdbc:mysql://localhost:3306/clinic?characterEncoding=utf-8 # 数据库名称 username: root password: mysql dbcp2: min-idle: 5 # 数据库连接池的最小维持连接数 initial-size: 5 # 初始化连接数 max-total: 5 # 最大连接数 max-wait-millis: 200 # 等待连接获取的最大超时时间 eureka: client: register-with-eureka: false # 当前微服务不注册到eureka中(消费端) service-url: defaultZone: http://localhost:7001/eureka/ # 如果有注册中心不在线,但是写上了地址,会报错 # ,http://localhost:7002/eureka/,http://localhost:7003/eureka/View Code
(5)controller层
package com.example.demomycentest.controller; //import com.example.demomycen22.pojo.Food; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @Controller public class GGController { private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT1"; /** * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap, * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。 */ @Autowired private RestTemplate restTemplate; @RequestMapping("/bb") @ResponseBody public String bb(){ // Food d = new Food(); // d.setApple("苹果"); // d.setEgg("鸡蛋"); // System.out.println(d); System.out.println("调用服务,开启负载均衡Ribbon"); //使用restTemplate 直接调用 ,postForObject 是post请求方式 ,getForObject是get请求方式,根据服务提供者的接口选择,这个是需要提前知道服务提供者的接口格式的 return restTemplate.getForObject(REST_URL_PREFIX + "/ask", String.class); } }View Code
(6)启动类需要使用注解@EnableEurekaClient ,注册为eureka客户端
3.测试
(1)提前准备好了2个 服务提供者作为集群,端口分别是8001,8003 ,一个服务注册中心,端口7001 ,本服务消费者端口565
(2)查看eureka控制面板
ok,运行正常
8001端口业务截图
8003端口业务截图
消费者565端口的业务 在 第二节(5)controller层 有源码,这里就不展示了
(3)去浏览器调用消费者接口 ,输入 http://localhost:565/bb
访问第一次
访问第2次
访问第三次
完美 !!!
因为是使用了轮询负载均衡策略 ,【就是轮流访问集群的每个服务器】,Ribbon会根据策略选择访问具体是哪个服务