文章目录
一、Ribbon是什么?
Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。
在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Eureka配合使用时的架构。
二、使用Ribbon
1.概念
我们在配置Eureka注册中心的时候,创建了两个服务提供者和一个消费者两个注册中心,现在需要用到这五个服务,因为Ribbon被集成在了 Eureka中,所以我们也不需要使用 maven坐标引入依赖。
配置注册中心的时候,其实有用到Ribbon这个东西。只是当时没有说。还记得我们配置的RestTemplate吗?
@Configuration
public class AppConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
没错就是这个,我们使用 @LoadBalanced
注解之后,
public static final String PAYMENT_URL = "http://SGG-PAYMENT-SERVICE/payment/";
这个时候,才可以通过服务名称访问到对应的服务实例。在配置服务中心的时候,我们就知道了Ribbon 是默认使用的轮询机制实现负载均衡的。 当然 Ribbon 默认给我们提供了很多其他的选择方式。
这个这个图可以看到。Ribbon 为我们提供了很多负载均衡的策略来提供给我们使用,默认使用的就是轮训机制, 就是上面的那个RoundRobinRule
,
2. 如何修改默认的负载均衡机制
我们将默认的轮询机制的负载均衡修改为 随机的。创建一个配置类
@Configuration
public class CustomRandomRule {
@Bean
public RandomRule randomRule() {
return new RandomRule();
}
}
注意: 这里这个类不能配置到SpringBoot启动类的同级别目录下以及子目录下,为什么呢?因为Ribbon的配置必须用@Configuration注解标识,并且不能被@Component注解或者@SpringBootApplication(因为里面包含了@Component)扫描到。因为如果被@ComponetScan扫描到会导致所有的RibbonClient都去共享这个配置。
所以我们这个类要配置在外一层里面才可以。 现在再去启动类上添加注解。
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "SGG-PAYMENT-SERVICE", configuration = LoadBlbanceConfig.class)
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class, args);
}
}
可以看到我们的添加了 RibbonClient
注解, 当然了如果你有多个服务需要配置,你也可以通过使用 @RibbonClients
这个注解, 这个注解可以添加多个 RibbonClient
接下来我们启动昨天的服务 7001, 7002, 8001 ,8002, 80 访问我们的接口试试看 , 还是不是默认的轮询机制了。
可以看到,我们的这个接口已经成为随机的了,现在是已经成功了。 有时候是 8001 有时候是8002, 而且找不到规律。
3. 自定义负载均衡策略。
我们前面说了,负载均衡策略主要是接口是 IRule 这个接口中的 choose 方法,作用就是用来决定这次的请求发送到哪一个实例上面。
public interface IRule{
/*
* choose one alive server from lb.allServers or
* lb.upServers according to key
*
* @return choosen Server object. NULL is returned if none
* server is available
*/
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
但是我们不准备实现该接口,我打算实现一个抽象类AbstractLoadBalancerRule
,该抽象类也是继承自 IRule
接口
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
@Override
public void setLoadBalancer(ILoadBalancer lb){
this.lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer(){
return lb;
}
}
CustomMyRule.java
/**
* @author gssznb
* @Date 2020/9/6
* @Descript: 如何自定义访问规则。, 通过集成 AbstractLoadBalancerRule 重写 choose 方法 。
*/
@Slf4j
public class CustomMyRule extends AbstractLoadBalancerRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
// 获取到 lb 对象
ILoadBalancer lb = super.getLoadBalancer();
// 获取到所有的实例对象
List<Server> allServers = lb.getAllServers();
AtomicReference<Server> s = new AtomicReference<>();;
// 遍历一下我们的这个所有的实例
allServers.forEach(server -> {
String host = server.getHost();
int port = server.getPort();
String scheme = server.getScheme();
Server.MetaInfo metaInfo = server.getMetaInfo();
String zone = server.getZone();
log.info("host: [ {} ], port: [ {} ], scheme: [ {} ]", host, port, scheme);
log.info("metaInfo: [ {} ], zone: [ {} ]", metaInfo, zone);
if (port == 8001) {
s.set(server);
}
});
// 我们这边实现的策略就是,不管怎么样,我们都始终使用 端口号为 8001 的实例
return s.get();
}
}
修改LoadBlbanceConfig.java
@Bean
public CustomMyRule randomRule() {
return new CustomMyRule();
}
修改启动类OrderApp.java
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "SGG-PAYMENT-SERVICE", configuration = LoadBlbanceConfig.class)
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class, args);
}
}
启动,访问接口!!可以看到不管我们访问多少次,他永远都是 8001 端口的实例。 这边将 allServer
中的实例信息打印出来
2020-09-08 20:29:02.621 INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule : host: [ 192.168.101.2 ], port: [ 8001 ], scheme: [ null ]
2020-09-08 20:29:02.621 INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule : metaInfo: [ com.netflix.niws.loadbalancer.DiscoveryEnabledServer$1@3b5d72b1 ], zone: [ defaultZone ]
2020-09-08 20:29:02.621 INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule : host: [ 192.168.101.2 ], port: [ 8002 ], scheme: [ null ]