一、Ribbon简介
Ribbon是Netflix发布的负载均衡器,提供了对来自HTTP和TCP客户端行为的控制。为Ribbon配置提供者服务地址列表后,Ribbon可以根据我们指定的负载均衡算法,自动帮助消费者去请求提供者。Ribbon提供了许多负载均衡算法,如常见的轮询、随机等。我们也可以为Ribbin实现自定义负载算法。
二、通过配置自定义Ribbon
负载均衡策略
Spring Cloud Netflix默认为Ribbon提供了以下bean:
Bean Type | Bean Name | Class Name |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
自定义Ribbon客户端
可以通过注解@RibbonClient声明附加配置,此处声明的配置会覆盖配置文件中的配置。
@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration {
}
需要说明的是自定义的类必须加上@Configuration注解且不能包含在@componentscan注解扫描的包中,否则自定义的类将由所有加@ribbonclient注解的地方共享,若用@ComponentScan(或@SpringBootApplication),应该采取措施来避免它被包含到扫描的范围中。
如下,建立FooConfiguration,自定义serverlistfilter和ribbonPing类型bean,放在在@ribbonclient配置中
@Configuration
protected static class FooConfiguration {
@Bean
public ZonePreferenceServerListFilter serverListFilter() {
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.setZone("myTestZone");
return filter;
}
@Bean
public IPing ribbonPing() {
return new PingUrl();
}
}
自定义所有默认Ribbon
@RibbonClients不同于@RibbonClient,它 可以为所有的Ribbon客户端提供默认配置
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig {
public static class BazServiceList extends ConfigurationBasedServerList {
public BazServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
}
@Configuration
class DefaultRibbonConfig {
@Bean
public IRule ribbonRule() {
return new BestAvailableRule();
}
@Bean
public IPing ribbonPing() {
return new PingUrl();
}
@Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
}
@Bean
public ServerListSubsetFilter serverListFilter() {
ServerListSubsetFilter filter = new ServerListSubsetFilter();
return filter;
}
}
通过配置自定义Ribbon
从1.2.0版本开始,Spring Cloud Netflix支持自定义Ribbon客户端配置
支持配置的属性如下:
<clientName>.ribbon.NFLoadBalancerClassName
: 配置ILoadBalancer的实现类
<clientName>.ribbon.NFLoadBalancerRuleClassName
:配置IRule的实现类
<clientName>.ribbon.NFLoadBalancerPingClassName
: 配置IPing的实现类
<clientName>.ribbon.NIWSServerListClassName
: 配置ServerList的实现类
<clientName>.ribbon.NIWSServerListFilterClassName
:配置ServerListFilter的实现类
如application.yml配置
microservice-provider-order:
ribbon:
NIWSServerListClassName: com.ultradata.task.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.ultradata.task.RandomeRule
com.ultradata.task.ConfigurationBasedServerList、com.ultradata.task.RandomeRule类自己实现即可,也可以是默认的类
如com.netflix.loadbalancer.ConfigurationBasedServerList,com.netflix.loadbalancer.WeightedResponseTimeRule
三、与Eureka配合使用
- 当Ribbin与Eureka结合使用时候,ribbonServerList将被com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList的实现覆盖,该实现会将服务列表交给Eureka的服务治理机制来进行维护。
- IPing接口被com.netflix.niws.loadbalancer.NIWSDiscoveryPing覆盖,NIWSDiscoveryPing也委托给了Eureka来维护。
- 默认情况下,用于获取实例请求的ServerList接口实现将采用Spring Cloud Eureka中封装的org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList,其目的是为了让实例维护策略更加通用,所以将使用物理元数据来进行负载均衡,而不是使用原生的AWS AMI元数据。
- Spring Cloud Ribbon默认使用eureka实例元数据中提供的“zone”信息构建服务器列表,通过设置eureka.instance.metadatamap.zone的值,可以实现跨区域的实例配置,如将不同机房配置不同的区域值即可eureka.instance.metadatamap.zone=beijing。
但也可以通过设置ribbon.eureka.enabled=false来禁用Eureka维护。
1、由于eureka中整合了Ribbin,pom.xml引入eureka-client依赖即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
2、Rinbbon负载均衡操作,有两种方法
(1)为RestTemplate添加@LoadBalanced注解,启动RestTemplate客户端负载均衡
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan("com.ultradata.task")
public class ConsumerApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(ConsumerApplication.class, args);
}
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
消费者controller如下
import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ConsumerOrderController {
private static final Logger LOGGER = LoggerFactory.getLogger(ProviderOrderController.class);
@Autowired
private RestTemplate restTemplate;
@GetMapping("/order/${orderId}")
public String order(@PathVariable String orderId) {
return restTemplate.getForObject("http://microservice-provider-order"+orderId, String.class);
}
}
(2) 启动类不必为RestTemplate添加@LoadBalanced注解,直接用Ribbon提供的LoadBalancerClient实现
import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ConsumerOrderController {
private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerOrderController .class);
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/order/${orderId}")
public String order(@PathVariable String orderId) {
ServiceInstance serviceInstance = loadBalancerClient.choose("microservice-provider-order");
LOGGER.info("ServiceId:{},Host:{}:Port:{}",serviceInstance.getServiceId(),serviceInstance.getHost(),serviceInstance.getPort());
URI url = URI.create(String.format("http://%s:%s/pay"+, serviceInstance.getHost(), serviceInstance.getPort()));
return restTemplate.getForObject(url+orderId, String.class);
}
}
四、脱离Eureka使用
去掉启动类上的@EnableDiscorveryClient注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(ProviderApplication.class, args);
}
}
application.yml配置如下
server:
port: 8081
spring:
application:
name: microservice-consumer-pay
microservice-provider-order:
ribbon:
listOfServers: node01:8080,node02:8080,node03:8080
ribbon:
eureka:
enabled: false
#false不使用Eureka
listOfServers的地址列表是microservice-provider-order提供者的Ribbin的客户端地址列表,供microservice-consumer-pay调用
控制层实现和之前整合Eureka一样,不再展示。
参考:https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-ribbon.html