简介
Ribbon实现客户端的负载均衡,负载均衡是指任务分摊到多个操作单元上进行执行.它建立在现有网络结构上,提供了一种廉价透明的方法拓展网络设备和服务带宽,增加了吞吐量,加强网络数据处理能力.提高网络的灵活性和可用性.
Ribbon 主要功能
1.支持DNS和IP与服务器通信.
2.可以根据负载均衡算法从多个服务中选取一个服务进行访问.
3.通过将客户端和服务器分成几个区域来建立客户端和服务器之间的关系.客户端尽量访问和自己在相同区域的服务,减少服务的延迟.
4.保留服务器的统计信息.ribbon可以实现用于避免频繁访问高延迟或故障的服务器.
5.保留区域的数据统计,ribbon可以实现避免访问可能失效的区域.
Ribbon 与 Nginx的区别
Nginx
Nginx是服务器端负载均衡,客户端所有请求统一交给Nginx,由Nginx实现负载均衡请求转发.
Ribbon
Ribbon是客户端负载均衡,在调用请求的时候会向注册中心获取注册信息服务列表,缓存到本地,然后实现本地负载均衡策略.
Ribbon主要组件
1.IRule - 规则模式
2.Iping - 管路
3.ServerList - 服务列表
4.ServerListFilter - 过滤服务列表
5.ServerListUpdater - 动态更新服务列表
6.IClientConfig - 配置信息
7.ILoadBalancer - 负载平衡器
1.IRule
功能:根据特定算法从服务列表选取一个服务进行访问.
RoundRobinRule
轮询规则,默认规则.
AvailabilityFilteringRule
负载均衡器规则,过滤掉 1.由于多次访问故障而处于断路状态的服务,2.并发的连接数量超过阈值的服务.然后对剩余的服务列表按照RoundRobinRule策略进行访问.
WeightedResponseTimeRule
根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越重,优先被选中.
RetryRule
按照RoundRobinRule的策略获取服务.如果获取服务失败.在指定时间内进行重试,获取可用的服务.
BestAvailableRule
此负载均衡器会过滤由于多次访问故障而处于断路状态的服务,然后选择一个并发量最小的服务.
RandomRule
随意获取一个服务
2.IPing
功能:在后台运行的一个组件,用于检测服务器列表是否运行正常.
NIWSDiscoveryPing
不执行真正的ping,如果Discovery Client认为是在线,则程序认为本次心跳成功,服务正常运行.
PingUrl
此组件会使用HttpClient调用一个服务,如果调用成功,则认为本次心跳成功,表示服务正常运行.
NoOpPing
永远返回true,表示服务永远正常.
DummyPing
默认实现,默认返回true,表示服务永远正常.
3.ServerList
功能:存储服务列表.分为静态和动态,如果为动态,后台有一个县城会定时刷新和过滤服务列表.
ConfigurationBasedServerList
从配置文件中获取所有服务列表.(静态)
DiscoveryEnabledNIWSServerList
从Eureka Client中获取服务列表。(动态)
DomainExtractingServerList
代理类,根据ServerList的值实现具体的逻辑
4.ServerListFilter
该接口允许过滤配置或动态获取的具有所需特性的服务器列表.
ZoneAffinityServerListFilter
过滤掉所有的不和客户端在相同zone的服务,如果和客户端相同的zone不存在,才不过滤不同zone服务.
ZonePreferenceServerListFilter
ZoneAffinityServerListFilter的子类。和ZoneAffinityServerListFilter相似,但是比较的zone是发布环境里面的zone。过滤掉所有和客户端环境里的配置的zone的不同的服务,如果和客户端相同的zone不存在,才不进行过滤。
ServerListSubsetFilter
ZoneAffinityServerListFilter的子类。此过滤器确保客户端仅看到由ServerList实现返回的整个服务器的固定子集。 它还可以定期用新服务器替代可用性差的子集中的服务器。
5.ServerListUpdater
功能:被DynamicServerListLoadBalancer用于动态的更新服务列表.
PollingServerListUpdater
默认的实现策略,此对象会启动一个定时线程池,定时执行更新策略.
EurekaNotificationServerListUpdater
当收到缓存刷新的通知梦回更新服务列表.
6.IClientConfig
功能:定义配置信息,用来初始化ribbon客户端和负载均衡器.
DefaultClientConfigImpl
IClientConfig的默认实现,配置文件里的部分值为ribbon。
7.ILoadBalancer
功能:定义软件负载平衡器操作的接口。动态更新一组服务列表及根据指定算法从现有服务器列表中选择一个服务.
DynamicServerListLoadBalancer
DynamicServerListLoadBalancer组合Rule、IPing、ServerList、ServerListFilter、ServerListUpdater 实现类,实现动态更新和过滤更新服务列表.
ZoneAwareLoadBalancer
这是DynamicServerListLoadBalancer的子类,主要加入zone的因素。统计每个zone的平均请求的情况,保证从所有zone选取对当前客户端服务最好的服务组列表
代码实现
实现原理图

准备工作
继续上一章笔记的工程,启动eureka-server,eureka-client;再修改eureka-client的端口号在启动一次.
如何启动两个实例:

spring cloud中实现 Ribbon
1.创建服务消费者(ribbon-server)
Cloud Discovery -> Eureka Discovery Client

创建完成后,在eureka-client项目的pom文件继承父pom文件,并查看是否引入了spring-cloud-starter-netflix-eureka-client的依赖.
并引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
添加配置文件application.yml如下:
#端口号
server:
port: 8084
#向服务注册中心注册
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8081/eureka/
#本服务名称
spring:
application:
name: service-ribbon
在启动类中,添加注解@EnableDiscoveryClient,向服务中心注册;并且向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。
@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
写一个测试类HelloService,通过之前注入ioc容器的restTemplate来消费service-hello服务的“/hello”接口,在这里我们直接用的程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String helloService() {
return restTemplate.getForObject("http://SERVICE-HELLO/hello",String.class);
}
}
写一个controller,在controller中用调用HelloService 的方法,代码如下
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping(value = "/hello")
public String hello() {
return helloService.helloService();
}
}
在浏览器上多次访问http://localhost:8084/hello,浏览器交替显示:
hello ! 我是 8082号服务器.
hello ! 我是 8083号服务器.
这说明当我们通过调用restTemplate.getForObject(“http://SERVICE-HELLO/hello,String.class)方法时,已经做了负载均衡,访问了不同的端口的服务实例。
网友评论