spring cloud 客户端负载均衡 - Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,基于Netflix Ribbon实现的,Ribbon不像注册中心、网关那样需要单独部署,它是作为一个工具直接集成到Service里。后面要讲到的Feign里面也集成了Ribbon。
1、手动搭建一个客户端负载均衡
准备工作:
- 准备一个由 peer1、peer2 构成的配置中心
- 准备一个由 service-1(8091)、service-1(8092) 构成的服务端集群
- 准备一个Ribbon客户端
添加pom依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
Ribbon客户端,使用@EnableDiscoveryClient向Eureka注册:
@SpringBootApplication @EnableDiscoveryClient public class RibbonServiceApplication { public static void main(String[] args) { SpringApplication.run( RibbonServiceApplication.class, args ); } /** * 实例化RestTemplate,通过@LoadBalanced注解开启均衡负载 */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
调用Service-1提供的服务:
@Service public class UserService { @Autowired private RestTemplate restTemplate; public UserDto getUser(Long userId) { ResponseEntity<UserDto> responseEntity = restTemplate.getForEntity("http://service-1/getUser/{1}", UserDto.class, userId); return responseEntity.getBody(); } }
依次启动注册中心、Service-1两个实例和Ribbon,全部启动成功后,可以看到service-1启动了两个实例,如下图所示:
访问 Ribbon 客户端接口:http://localhost:9000/user/getByUserId
刷新页面,后端Service-1的两个实例分别输出日志:
service-1:8091
8091 provides service
service-1:8092
8092 provides service
8092 provides service
系统架构如图所示:
2、Ribbon配置
自动化配置
上面搭建负载均衡过程中没有任何Ribbon相关的配置,是因为Spring Cloud整合Eureka和Ribbon时做了很多默认配置。
在没有引入Spring Cloud Eureka时,Spring Cloud Ribbon 已经默认实现了这些配置bean:
-
IClientConfig :Ribbon客户端配置,默认采用 com.netflix.client.config.DefaultClientConfigImpl
-
IRule :Ribbon的负载均衡策略,默认采用 com.netflix.loadbalancer.ZoneAvoidanceRule
-
IPing:Ribbon实例心跳检查策略,默认采用 com.netflix.loadbalancer.NoOpPing,通过看实现可以看出:不会检查实例是否可用,始终返回true
-
ServerList:服务实例清单维护列表,默认采用 com.netflix.loadbalancer.ConfigurationBasedServerList
-
ServerListFilter :服务实例清单过滤机制,默认采用 org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter
-
ILoadBalancer :负载均衡器,默认采用 com.netflix.loadbalancer.ZoneAwareLoadBalancer
自定义配置:代码+RibbonClient方式
@RibbonClient(value = "service-1", configuration = MyRibbonConfig.class) public class RibbonServiceApplication {
自定义负载为随机时:
@Configuration public class MyRibbonConfig { @Bean public IRule ribbonRule() { new RandomRule(); } }
当自定义负载换为轮询时:
@Configuration public class MyRibbonConfig { @Bean public IRule ribbonRule() { new RoundRobinRule(); } }
分别在上面两种情况下刷新页面 http://localhost:9000/user/getByUserId (以刷新8次为例,观察service-1两个实例控制台打印的log):
- 当为 RandomRule 时发现service-1在8091和8092两个实例随机提供服务。
- 当为 RoundRobinRule 时发现service-1在8091和8092两个实例轮流提供服务。
自定义配置:代码+配置文件方式(Components of load balancer)
在properties里配置,通过反射方式创建,配置方式如下:
以 `<clientName>.ribbon.` 为前缀,加上下面的属性名(属性名来自 org.springframework.cloud.netflix.ribbon.PropertiesFactory 类):
NFLoadBalancerClassName
NFLoadBalancerRuleClassName
NFLoadBalancerPingClassName
NIWSServerListClassName
NIWSServerListFilterClassName
配置ribbon负载方式(针对service-1服务设置):
service-1:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
将自定义类赋给对应的属性可以做到服务级别的自定义配置。
3、附录
本文Demo地址:Ribbon Service