简介
Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。 在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。在Spring Cloud 构建的微服务中,Ribbon作为服务消费者的负载均衡器,有两种使用方式,一种是与RestTemplate相结合,另一种是与Feign相结合。
Ribbon的子模块
Ribbon包含很多子模块,但很多子模块没有用于生产环境,目前用于生产的Ribbon的子模块具体如下:
- ribbon-core:定义负载均衡接口、客户端接口、内置的负载均衡实现等API。
- ribbon-eureka :提供eureka客户端实现负载均衡的API。
- ribbon-httpclient:对Apache的HttpClient进行封装,该模块提供了含有负载均衡功能的REST客户端。
Ribbon整合Eureka
Ribbon实例
改造服务提供者
在上节的项目eureka-provider和eureka-provider-another中新建controller包,并新建PortController
@RestController
public class PortController {
@Value("${server.port}")
String port;
@RequestMapping("port")
public String getPort(){
return "Hello World, I'm from port:"+port;
}
}
该方法返回当前项目的端口号
搭建含Ribbon的服务消费者
新建eureka-ribbon-client
1)导入依赖:
<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>
2)yml配置:
spring:
application:
name: eureka-ribbon-client
server:
port: 8764
eureka:
client:
serviceUrl:
defaultZone: http://localhost:7000/eureka/
3)启动类:
@EnableEurekaClient
@SpringBootApplication
public class EurekaRibbonClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaRibbonClientApplication.class, args);
}
}
4)配置类:
@Configuration
public class RibbonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
此类注入了restTemplate的Bean对象,@LoadBalanced使restTemplate( )方法具备了负载均衡能力
5)service类:
@Service
public class RibbonService {
@Autowired
RestTemplate restTemplate;
public String hi(){
return restTemplate.getForObject
("http://eureka-provider/port",String.class);
}
}
6)Controller类:
@RestController
public class RibbonController {
@Autowired
RibbonService ribbonService;
@RequestMapping("/hi")
public String hi(){
return ribbonService.hi();
}
}
运行测试
启动
启动eureka-server、eureka-server-another、eureka-provider、eureka-provider-another和eureka-ribbon-client
访问
访问http://server1:7000/和http://server2:7009/,效果如下
![](https://img-blog.csdnimg.cn/img_convert/95decc005cf49217b755c5b631913edf.png)
访问http://localhost:8764/hi,效果如下:
刷新页面,效果如下
可以发现浏览器会轮流显示两个服务提供者的端口号,这是说明负载均衡起到了效果
Ribbon的工作原理
前面我们使用Ribbon实现负载均衡时,基本用法是注入一个RestTemplate,并使用@LoadBalanced注解标注RestTemplate,从而使RestTemplate具备负载均衡的能力。
当Spring容器启动时,使用@LoadBalanced注解修饰的RestTemplate会被添加拦截器,拦截器中使用了LoadBalancerClient处理请求,从而达到负载均衡的目的。
LoadBalancerClient是Spring Cloud提供的一个非常重要的接口,它继承自ServiceInstanceChooser接口,该接口的实现类是RibbonLoadBalanceClient,它们之间的关系如下图所示。
LoadBalancerClient的部分源码:
package org.springframework.cloud.client.loadbalancer;
import java.io.IOException;
import java.net.URI;
import org.springframework.cloud.client.ServiceInstance;
/**
* Represents a client-side load balancer.
*
* @author Spencer Gibb
*/
public interface LoadBalancerClient extends ServiceInstanceChooser {
/**
* Executes request using a ServiceInstance from the LoadBalancer for the specified
* service.
* @param serviceId The service ID to look up the LoadBalancer.
* @param request Allows implementations to execute pre and post actions, such as
* incrementing metrics.
* @param <T> type of the response
* @throws IOException in case of IO issues.
* @return The result of the LoadBalancerRequest callback on the selected
* ServiceInstance.
*/
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
/**
* Executes request using a ServiceInstance from the LoadBalancer for the specified
* service.
* @param serviceId The service ID to look up the LoadBalancer.
* @param serviceInstance The service to execute the request to.
* @param request Allows implementations to execute pre and post actions, such as
* incrementing metrics.
* @param <T> type of the response
* @throws IOException in case of IO issues.
* @return The result of the LoadBalancerRequest callback on the selected
* ServiceInstance.
*/
<T> T execute(String serviceId, ServiceInstance serviceInstance,
LoadBalancerRequest<T> request) throws IOException;
/**
* Creates a proper URI with a real host and port for systems to utilize. Some systems
* use a URI with the logical service name as the host, such as
* http://myservice/path/to/service. This will replace the service name with the
* host:port from the ServiceInstance.
* @param instance service instance to reconstruct the URI
* @param original A URI with the host as a logical service name.
* @return A reconstructed URI.
*/
URI reconstructURI(ServiceInstance instance, URI original);
}
其中两个execute方法用于执行请求,reconstructURI方法用于重构URI
其所继承的类ServiceInstanceChooser部分源码:
public interface ServiceInstanceChooser {
/**
* Chooses a ServiceInstance from the LoadBalancer for the specified service.
* @param serviceId The service ID to look up the LoadBalancer.
* @return A ServiceInstance that matches the serviceId.
*/
ServiceInstance choose(String serviceId);
}
上述源码中,ServiceInstanceChooser接口定义一个choose()方法,该方法用于根据serviceId选择一个服务实例,即通过服务名选择服务实例。
使用RibbonLoadBalanceClient实现负载均衡时,会从EurekaClient获取服务列表信息,然后根据IPing判断服务是否可用。如果服务可用,则会根据IRule选择负载均衡策略,否则会重新获取服务清单。
Ribbon的负载均衡策略
RoundRobinRule:
实现了按照线性轮询的方式依次选择服务的功能。
WeightedResponseTimeRule:
它是对RoundRobinRule的扩展,会根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越大,被选中的概率越高。
ZoneAvoidanceRule:
它是PredicateBasedRule的具体实现类,其内部通过使用ZoneAvoidancePredicate和AvailabilityPredicate判断是否选择某一个服务,前者用于判断服务所在区域的性能是否可用,后者用于过滤掉连接数过多的服务。
AvailabilityFilteringRule:
使用AvailabilityPredicate过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阀值的服务,然后对剩余的服务列表进行轮询。
BestAvailableRule:
用于先过滤掉多次访问故障而处于断路跳闸状态的服务,然后选择一个并发量最小的服务。
RandomRule:
该策略实现了从服务清单中随机选择一个服务的功能。
lClientConfigEnableRoundRobinRule:
该类是一个抽象类,该类本身没有实现什么特殊的处理逻辑,我们也不会直接使用该策略,但是通过BestAvailableRule和继承该策略默认实现了线性轮询,它的内部定义了一个RoundRobinRule策略,
lPredicateBasedRule:
继承了ClientConfigEnableRoundRobinRule,其内部会先通过chooseRoundRobinAfterFiltering()方法筛选服务清单,然后以线性轮询的方式从过滤后的服务清单中选择一个服务。
源码下载
文件下载 | 文件名称:本节代码.zip | 文件大小:1.96MB |
下载声明:本站文件大多来自于网络,仅供学习和研究使用,不得用于商业用途,如有版权问题,请联系博主! | ||
下载地址:点击下载 |