SpringCloud(Hoxton.SR3)基础篇:第二章、客户端提供负载均衡功能的服务(Ribbon)
一、Ribbon简介:
Ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。
需要解决的问题:
- ① 如何在配置Eureka Client注册中心时不去硬编码Eureka Server的地址?
- ② 在微服务不同模块间进行通信时,如何不去硬编码服务提供者的地址?
- ③ 当部署多个相同微服务时,如何实现请求时的负载均衡?
Ribbon是什么?
二、SpringCloud之Ribbon入门案例
<!-- eureka包含Ribbon依赖jar包 spring-cloud-netflix-ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
② 如何使用Ribbon
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
③ 如何解决硬编码
使用添加@LoadBalanced注解后的RestTemplate调用服务提供者的接口时,可以使用虚拟IP替代真实IP地址。所谓的虚拟IP就是服务提供者在application.properties或yml文件中配置的spring.application.name属性的值。示例如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.qxj.cloud.entity.User; @RestController public class MovieController { @Autowired private RestTemplate restTemplate; @RequestMapping(value="/movie/{id}",method = RequestMethod.GET,produces="application/json;charset=UTF-8") public User findById(@PathVariable Long id) {
//微服务的虚拟id http://provider-user User user = this.restTemplate.getForObject("http://provider-user:7900/simple/" + id, User.class); return user; } }
小总结:Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心ip地址和端口号
微服务(服务提供者)集群搭建:机器1
server:
port: 7900
spring:
application:
name: provider-user
#eureka客户端连接配置
eureka:
client:
service-url:
#注册中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#将ip注册到eureka上
prefer-ip-address: true
#微服务向eureka注册实例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
机器2
server:
port: 7901
spring:
application:
name: provider-user
#eureka客户端连接配置
eureka:
client:
service-url:
#注册中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#将ip注册到eureka上
prefer-ip-address: true
#微服务向eureka注册实例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
机器3
server:
port: 7902
spring:
application:
name: provider-user
#eureka客户端连接配置
eureka:
client:
service-url:
#注册中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#将ip注册到eureka上
prefer-ip-address: true
#微服务向eureka注册实例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
其中{Spring.application.name}都是一样的,不可以变。
三、Ribbon组件IRule
默认的是RoundBobinRule(轮询)
四、自定义负载均衡算法:
所谓的自定义Ribbon Client的主要作用就是使用自定义配置替代Ribbon默认的负载均衡策略,注意:自定义的Ribbon Client是有针对性的,一般一个自定义的Ribbon Client是对一个服务提供者(包括服务名相同的一系列副本)而言的。自定义了一个Ribbon Client 它所设定的负载均衡策略只对某一特定服务名的服务提供者有效,但不能影响服务消费者与别的服务提供者通信所使用的策略。根据官方文档的意思,推荐在 springboot 主程序扫描的包范围之外进行自定义配置类。其实纯代码自定义RibbonClient的话有两种方式:
方式一:在springboot主程序扫描的包外定义配置类,然后为springboot主程序添加 @RibbonClient 注解引入配置类。import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; import com.qxj.configuration.MySelfRule; @SpringBootApplication //该注解表明应用既作为eureka实例又为eureka client 可以发现注册的服务 @EnableEurekaClient //在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效 @RibbonClient(name = "provider-user",configuration = MySelfRule.class) public class ConsumerMovieRibbonApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerMovieRibbonApplication.class, args); } }
Rule配置文件类,配置类不应该在SpringBoot的包路径下,通过@RibbonClient 注解加载:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.loadbalancer.IRule; @Configuration public class MySelfRule { @Bean public IRule MyRule() { return new RandomRule_QXJ(); } }
自定义LoadBalance:
import java.util.List; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; public class RandomRule_QXJ extends AbstractLoadBalancerRule{ private int total = 0; // 总共被调用的次数,目前要求每台被调用5次 private int currentIndex = 0; // 当前提供服务的机器号 /** * 服务选择算法,要求每台被调用5次 * @param lb * @param key * @return */ public Server choose(ILoadBalancer lb,Object key) { if(lb == null) { return null; } Server server = null; while(server == null) { //判断当前线程是否中断 //interrupted()是静态方法:内部实现是调用的当前线程的isInterrupted(),并且会重置当前线程的中断状态 if(Thread.interrupted()) { return null; } //激活可用的服务 List<Server> upList = lb.getReachableServers(); //所有的服务 List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if(serverCount == 0) { return null; } if(total < 5) { server = upList.get(currentIndex); total++; }else { total=0; //使用下一台机器服务 currentIndex++; //若当前服务机器为upList集合里最后一台,重新使用第一台机器服务 if(currentIndex >= upList.size()) { currentIndex=0; } } System.out.println("currentIndex:" + currentIndex +"---total:"+total); //循环到第一台服务时,server==null,需要重新获取server if(server == null) { Thread.yield(); continue; } if(server.isAlive()) { return server; } //该代码实际上不会执行 server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(),key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } }
方式二:application.yml文件配置方式
#@RibbonClient(name = "provider-user") 与name相同,表示针对该微服务使用自定义负载均衡规则
provider-user:
ribbon:
NFLoadBalancerRuleClassName: com.qxj.configuration.RandomRule_QXJ
配置的优先级
配置文件的优先级 > java代码的配置方式 > netflix自定义的配置方式
版权声明:本文为CSDN博主「安小岩说他很忙」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/JinXYan/java/article/details/90726707