一、Ribbon介绍
1. Ribbon是提供客户端的负载均衡的插件。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
2. 负载均衡(LB)方案分类
目前主流的LB方案可分成两类:一种是集中式LB, 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如Nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;另一种是进程内LB,将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个可用的服务器。Ribbon就属于后者,集成于消费方进程,属于客户端的均衡负载,消费方通过它来获取到可用的服务器的地址。
3. Ribbon的主要组件(均为接口类型)
1. ServerList: 用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。
2. ServerListFilter: 仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。
3. IRule: 负载均衡算法策略,选择一个最终的服务地址作为LB结果。算法策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。
4. Ribbon提供的主要负载均衡策略介绍
1. 简单轮询负载均衡(RoundRobinRule):以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。
2. 随机负载均衡 (RandomRule): 随机选择状态为UP的Server
3. 加权响应时间负载均衡 (WeightedResponseTimeRule):根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。
4. 区域感知轮询负载均衡(ZoneAvoidanceRule):复合判断server所在区域的性能和server的可用性选择server
5. 带重试的轮询负载均衡(RetryRule):在失效时间deadline之前不断进行重试(重试时还是RoundRobinRule),超过了deadline还是没取到则返回null
6. 带过滤的轮询均衡负载(PredicateBasedRule):先通过内部定义的过滤器过滤一部分服务实例,然后再采用线性轮询方法从过滤出来的结果中选取服务
5. Ribbon工作流程
Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。
二、Ribbon单独使用
导入依赖
<dependencies>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-core</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-httpclient</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
sample-client.properties配置文件
# Max number of retries
sample-client.ribbon.MaxAutoRetries=1
# Max number of next servers to retry (excluding the first server)
sample-client.ribbon.MaxAutoRetriesNextServer=1
# Whether all operations can be retried for this client
sample-client.ribbon.OkToRetryOnAllOperations=true
# Interval to refresh the server list from the source
sample-client.ribbon.ServerListRefreshInterval=2000
# Connect timeout used by Apache HttpClient
sample-client.ribbon.ConnectTimeout=3000
# Read timeout used by Apache HttpClient
sample-client.ribbon.ReadTimeout=3000
# Initial list of servers, can be changed via Archaius dynamic property at runtime
sample-client.ribbon.listOfServers=www.sohu.com:80,www.163.com:80,www.sina.com.cn:80
sample-client.ribbon.EnablePrimeConnections=true
RibbonMain代码
public class RibbonMain {
public static void main( String[] args ) throws Exception {
ConfigurationManager.loadPropertiesFromResources("sample-client.properties");//使用 Archaius ConfigurationManager 加载属性;
System.out.println(ConfigurationManager.getConfigInstance().getProperty("sample-client.ribbon.listOfServers"));
RestClient client = (RestClient)ClientFactory.getNamedClient("sample-client");//使用 ClientFactory 创建客户端和负载均衡器;
/**
* 使用 builder 构建 http 请求。注意我们只支持 URI 的 "/" 部分的路径,
* 一旦服务器被负载均衡器选中,会由客户端计算出完整的 URI;
*/
HttpRequest request = HttpRequest.newBuilder().uri(new URI("/")).build();
for(int i = 0; i < 4; i ++) {
HttpResponse response = client.executeWithLoadBalancer(request);
System.out.println("Status for URI:" + response.getRequestedURI() + " is :" + response.getStatus());
}
//调用 API client.executeWithLoadBalancer(),不是 exeucte() API;
ZoneAwareLoadBalancer lb = (ZoneAwareLoadBalancer) client.getLoadBalancer();
System.out.println(lb.getLoadBalancerStats());
//动态修正配置中的服务器池;
ConfigurationManager.getConfigInstance().setProperty("sample-client.ribbon.listOfServers", "ccblog.cn:80,www.linkedin.com:80");
//等待服务器列表刷新(配置文件中定义的刷新间隔是为 3 秒钟);
Thread.sleep(3000);
//打印出负载均衡器记录的服务器统计信息
for(int i = 0; i < 3; i ++) {
HttpResponse response = client.executeWithLoadBalancer(request);
System.out.println("Status for URI:" + response.getRequestedURI() + " is :" + response.getStatus());
}
System.out.println(lb.getLoadBalancerStats());
}
}
三、Ribbon结合eureka使用
配置依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
添加application.yml文件
server:
port: 8081
spring:
application:
name: consumer #服务名
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka #注册进eureka
instance:
instance-id: consumer_8081 #在注册中心的名字
prefer-ip-address: true #访问路径时显示ip地址
修改主启动类,通过@EnableDiscoveryClient注解来添加发现服务能力。创建RestTemplate实例,并通过@LoadBalanced注解开启均衡负载能力。
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
调用Ribbon,创建Controller来消费服务。通过直接RestTemplate来调用服务。如果不想全部使用ribbon,可以不在RestTemplate上添加@LoadBalanced,而添加在Controller指定的方法上。
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@GetMapping("/user/info")
public String add() {
return restTemplate.getForEntity("http://xxx", String.class).getBody();
}
}