Eureka 和 Ribbon

Eureka 和 Ribbon

薛定谔的汪

上次学习了 Eureka 服务的注册和调用,当某个服务搭建了多实例,共同注册到了 Eureka 上,那么 Eureka 是如何把消费者们的请求均衡到这些多个实例的呢?今天来学习下 Eureka 负载均衡相关的东西。

使用 Feign

新建 eureka-provider1的 SpringBoot 项目

启动类

添加@EnableEurekaCLient注解

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaClient
public class EurekaProvider1Application {

public static void main(String[] args) {
SpringApplication.run(EurekaProvider1Application.class, args);
}
}

配置文件

1
2
3
4
5
6
7
8
9
server:
port: 9001
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka/
spring:
application:
name: provider

Controller

1
2
3
4
5
6
7
8
9
@RestController
public class Provider1Controller {

@GetMapping("hello")
public String hello(){
return "hello! Yakai! from provider1";
}

}

eureka-provider项目的controller修改返回内容

1
2
3
4
5
6
7
8
9
@RestController
public class ProviderController {

@GetMapping("hello")
public String hello(){
return "hello! Yakai! from provider";
}

}

这样同一个服务“provider”有两个实例,启动 注册中心server,两个服务提供者、消费者项目,访问http://localhsot:10000/hello ,进行测试:

发现第一次返回:hello! Yakai! from provider
第二次返回:hello! Yakai! from provider1
第三次:hello! Yakai! from provider
第四次:hello! Yakai! from provider1
……

发现两种结果交替出现,说明 Eureka 服务中心提供了负载均衡的功能,当然,两台实例不足以证明是轮询负载均衡的结论,当不断增加实例时,发现每个实例依然是按顺序被调用后,这说明 使用 Fegin 远程调用,请求是默认自动轮询到服务的每个实例来处理。

使用 Ribbon

Ribbon 简介

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer 后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon 的组件

ServerList

  • 用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。

ServerListFilter

  • 仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。

IRule

  • 选择一个
  • 最终的服务地址作为负载均衡结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。

Ribbon 的工作流程

Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果,和Dubbo 的负载均衡流程有点类似。

Ribbon 主要负载均衡策略

轮询(RoundRobin)

随机(Random)

加权响应时间负载均衡 (WeightedResponseTime)

根据响应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。

区域感知轮询负载均衡(ZoneAvoidanceRule)

复合判断server所在区域的性能和server的可用性选择server

实现负载均衡

看图了解到,Ribbon 存在于消费者端,也就是客户端

测试 Ribbon

原provider不变,新建eureka-consumer-ribbon 项目

引入依赖

其实 Fegin、eureka-server 已经集成了 Ribbon,这里引入 eureka-server 即可

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

开启 Ribbon 的负载均衡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootApplication
@EnableEurekaClient
public class EurekaConsumerRibbonApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaConsumerRibbonApplication.class, args);
}

@Bean
@LoadBalanced //RestTemplate 开启了负载均衡
RestTemplate restTemplate(){
return new RestTemplate();
}
}

消费者controller

在这里直接用程序名(spring.application.provider)替代了具体的url地址,在 Ribbon 中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名:

一般来讲, RestTemplate 应该在 service 层注入,然后 controller 层调 service,service 可再进行一些逻辑处理,这里为了省事直接注入到了 controller 层。

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class ConsumerController {

@Autowired
private RestTemplate restTemplate;

@GetMapping("hello")
public String hello() {
return restTemplate.getForEntity("http://provider/hello", String.class).getBody();
}
}

启动相关项目,访问 http://localhost:10001/hello 查看显示内容:

发现第一次返回:hello! Yakai! from provider
第二次返回:hello! Yakai! from provider1
第三次:hello! Yakai! from provider
第四次:hello! Yakai! from provider1

发现 Ribbon 的默认负载均衡也是轮询。

自定义 Ribbon 客户端

上面测试知道,Ribbon 默认的负载均衡策略是轮询,如果想改变其默认策略,比如使用随机该怎样配置?

这就需要自定义 Ribbon 配置类,但是官方文档警告:这个测试配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则自定义的这个配置类就会被所有的Ribbon客户端(@RibbonClient)所共享,这样达不到特殊定制化了。

在学习 SpringBoot 后知道,@SpringBootApplication注解里集成了@ComponentScan,它会自动扫描该注解的启动类所在的包以及该包的子包都将被所有 Ribbon 客户端所共享。

解决方法:

1.新建一个不在 @ComponentScan扫描下的包,在这个包下创建 Ribbon 配置类。

2.仍在启动类所在的包下或子包下创建启动 Ribbon 配置类,但排除@ComponentScan扫描,可以使用自定义注解的方式。

我使用的是第二种方法,一是代码结构清晰,二是在 Ribbon 配置类中可以不用再注入IClientConfig

自定义忽略@ComponentScan扫描的注解

1
2
3
public @interface IgnoreCompnentScan {

}

Ribbon 配置类

1
2
3
4
5
6
7
8
9
10
@Configuration
@IgnoreCompnentScan
public class RibbonConfig {

//返回“随机”负载均衡策略
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
@EnableEurekaClient
//name 是服务名,configuration 是 Ribbon 配置类
@RibbonClient(name = "provider",configuration = RibbonConfig.class)
//有@IgnoreCompnentScan注解的忽略扫描
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = IgnoreCompnentScan.class)})
public class EurekaConsumerRibbonApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaConsumerRibbonApplication.class, args);
}

@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}

启动相关程序,访问 http://localhsot:10001/hello,并多次刷新,发现返回的内容不再是有序出现,因为使用了 RandomRule,导致每次调用返回的内容都是随机的。

除此用代码配置 Ribbon 配置类的方式外,还可以配置文件的方式,二者都可以。

  • Title: Eureka 和 Ribbon
  • Author: 薛定谔的汪
  • Created at : 2018-06-01 18:20:16
  • Updated at : 2023-11-17 19:37:36
  • Link: https://www.zhengyk.cn/2018/06/01/springcloud/load-balance/
  • License: This work is licensed under CC BY-NC-SA 4.0.