服务调用端负载均衡-Ribbon

1.什么是负载均衡

负载均衡是微服务架构中必须使用的技术,经过负载均衡来实现系统的高可用、集群扩容等功能。负载均衡可经过硬件设备及软件来实现,硬件好比:F五、Array等 ,软件好比:LVS、Nginx等 。web

以下图是负载均衡的架构图:算法

 

用户请求先到达负载均衡器(也至关于一个服务),负载均衡器根据负载均衡算法将请求转发到微服务。负载均衡算法有:轮训、随机、加权轮训、加权随机、地址哈希等方法,负载均衡器维护一份服务列表,根据负载均衡算法将请求转发到相应的微服务上,因此负载均衡能够为微服务集群分担请求,下降系统的压力。spring

2.什么是Ribbon

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

下图展现了Eureka使用Ribbon时的大体架构: 

Ribbon工做时分为两步:第一步选择Eureka Server,它优先选择在同一个Zone且负载较少的Server;第二步再根据用户指定的策略,再从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了不少策略,例如轮询round robin、随机Random、根据响应时间加权等。服务器

3.Ribbon组件和原理

Ribbon是Netflix发布的开源项目,主要功能是为REST客户端实现负载均衡。它主要包括六个组件:架构

  • ServerList,负载均衡使用的服务器列表。这个列表会缓存在负载均衡器中,并按期更新。当Ribbon与Eureka结合使用时,ServerList的实现类就是DiscoveryEnabledNIWSServerList,它会保存Eureka Server中注册的服务实例表。
  • ServerListFilter,服务器列表过滤器。这是一个接口,主要用于对Service Consumer获取到的服务器列表进行预过滤,过滤的结果也是ServerList。Ribbon提供了多种过滤器的实现。
  • IPing,探测服务实例是否存活的策略。
  • IRule,负载均衡策略,其实现类表述的策略包括:轮询、随机、根据响应时间加权等,其类结构以下图所示。app

    !image负载均衡

     

    咱们也能够本身定义负载均衡策略,好比咱们就利用本身实现的策略,实现了服务的版本控制和直连配置。实现好以后,将实现类从新注入到Ribbon中便可。dom

  • ILoadBalancer,负载均衡器。这也是一个接口,Ribbon为其提供了多个实现,好比ZoneAwareLoadBalancer。而上层代码经过调用其API进行服务调用的负载均衡选择。通常ILoadBalancer的实现类中会引用一个IRule。ide

  • RestClient,服务调用器。顾名思义,这就是负载均衡后,Ribbon向Service Provider发起REST请求的工具。

Ribbon工做时会作四件事情:

  1. 优先选择在同一个Zone且负载较少的Eureka Server;
  2. 按期从Eureka更新并过滤服务实例列表;
  3. 根据用户指定的策略,在从Server取到的服务注册列表中选择一个实例的地址;
  4. 经过RestClient进行服务调用。

4.如何使用Ribbon

下面的例子,咱们将利用以前构建的eureka-server做为服务注册中心、eureka-client做为服务提供者做为基础。而基于Spring Cloud Ribbon实现的消费者,咱们能够根据eureka-consumer实现的内容进行简单改在就能完成,具体步骤以下:

  • 根据eureka-consumer复制一个服务消费者工程,命名为:eureka-consumer-ribbon。在pom.xml中增长下面的依赖:
<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
</dependencies>
  • 修改应用主类。为RestTemplate增长@LoadBalanced注解:
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

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

	public static void main(String[] args) {
		new SpringApplicationBuilder(Application.class).web(true).run(args);
	}
}
  • 修改Controller。去掉原来经过LoadBalancerClient选取实例和拼接URL的步骤,直接经过RestTemplate发起请求。
@RestController
public class DcController {

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/consumer")
    public String dc() {
        return restTemplate.getForObject("http://eureka-client/dc", String.class);
    }

}

在完成了上面你的代码编写以后,读者能够将eureka-server、eureka-client、eureka-consumer-ribbon都启动起来,而后访问http://localhost:2101/consumer ,来跟踪观察eureka-consumer-ribbon服务是如何消费eureka-client服务的/dc接口的,而且也能够经过启动多个eureka-client服务来观察其负载均衡的效果。能够看到这里,咱们除了去掉了原来与LoadBalancerClient相关的逻辑以外,对于RestTemplate的使用,咱们的第一个url参数有一些特别。这里请求的host位置并无使用一个具体的IP地址和端口的形式,而是采用了服务名的方式组成。那么这样的请求为何能够调用成功呢?由于Spring Cloud Ribbon有一个拦截器,它可以在这里进行实际调用的时候,自动的去选取服务实例,并将实际要请求的IP地址和端口替换这里的服务名,从而完成服务接口的调用。