介绍
Ribbon是一个客户端负载均衡器,通过一定的逻辑选择服务。高级功能可以根据客户端划分的区域来建立联系以减少延迟。
基础组件
IRule
决定使用哪个一个服务器去提供服务。
实现类 | 描述 |
---|---|
RandomRule | 随机选择已经有的server |
BestAvailableRule | 选择并发请求最少的server |
RoundRobinRule | 轮询 |
RetryRule | 传入一个IRule,当IRule失败的时候重试一次 |
ClientConfigEnabledRoundRobinRule | 抽象类,一般不用。通过继承该策略,默认的choose就实现了线性轮询机制。可以基于它来做扩展。 |
WeightedResponseTimeRule | 每30秒计算一次服务器响应时间,以响应时间作为权重,响应时间越短的服务器被选中的概率越大。 |
AvailabilityFilteringRule | 过滤掉一直连接失败的被标记为circuit tripped的Server,并过滤掉高并发的Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个Server的运行状态; |
ZoneAvoidanceRule | 复合判断Server所在区域的性能和Server的可用性选择Server |
IPing
运行在后台,确定服务器是否还活着。下面感觉就PingUrl有实际作用。
实现类 | 描述 |
---|---|
DummyPing | 永远返回true,仿造的ping。 |
NoOpPing | 永远返回true。可理解服务器永久可用,不需要检查服务器是否可用。 |
PingConstant | 默认永远返回true,可设置永远返回false。 |
PingUrl | ping返回的状态码是200,返回true。 |
ServerList
可以是静态的,也可以是动态的,这个集合里面放了服务器地址,例:localhost:8080、localhost:8081…
ServerListFilter
用于DynamicServerListLoadBalancer过滤从ServerList实现返回的服务器的组件。功能区中有ServerListFilter的两种实现。
ZoneAffinityServerListFilter
筛选出与客户端不在同一区域中的服务器,除非客户端区域中没有可用的服务器。可以通过指定以下属性来启用此过滤器(假设客户端名称为“ myclient”,客户端属性名称空间为“ ribbon”):
myclient.ribbon.EnableZoneAffinity=true
ServerListSubsetFilter
此筛选器确保客户端仅看到由ServerList实现返回的所有服务器的固定子集。它还可以定期用新服务器替换可用性较差的子集中的服务器。要启用此过滤器,请指定以下属性.
myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
# 服务器必须使用VipAddress "myservice"向Eureka server 注册自己
myClient.ribbon.DeploymentContextBasedVipAddresses=myservice
myClient.ribbon.NIWSServerListFilterClassName=com.netflix.loadbalancer.ServerListSubsetFilter
# 只显示5个服务,默认是20个
myClient.ribbon.ServerListSubsetFilter.size=5
ILoadBalancer
增加、选择、标志下线、取得当前可用实例、取得所有服务实例方法。它管理所有实例,并通过获取实例方法的中的负载均衡策略选择合适实例返回。
实现类 | 描述 |
---|---|
NoOpLoadBalancer | 继承AbstractLoadBalancer,什么也不做 |
DynamicServerlistloadBalancer | 实现了服务清单在运行过程中动态更新的能力,同时具备服务清单过滤的功能 |
ZoneAwareLoadBalancer | 由于DynamicServerlistloadBalancer使用轮询方式调用实例,在区域不同的情况下,可能存在网络延迟等情况影响性能,所以出现了ZoneAwareLoadBalancer,它具有区域亲和性,会优先选择同区域的实例。它使用ZoneAvoidanceRule作为负载均衡策略。 |
使用类配置
定义一个配置类
/**
* Ribbon的类配置
* @author Chiang
*/
public class SayHelloConfiguration {
@Autowired
IClientConfig ribbonClientConfig;
@Bean
public IPing ribbonPing(IClientConfig config) {
// 使用ping的方式检查服务器是否存活
return new PingUrl();
}
@Bean
public IRule ribbonRule(IClientConfig config) {
// 过滤掉一直连接失败、高并发的Server或AvailabilityPredicate来包含过滤server
return new AvailabilityFilteringRule();
}
// 服务器地址、服务器过滤等等配置....
}
启动这个配置类
@SpringBootApplication
@RestController
// 打开注解代表启用类配置,可以与yml配置同时存在
@RibbonClients(
value = {
@RibbonClient(name = "say-hello", configuration = SayHelloConfiguration.class),
@RibbonClient(name = "say-bye", configuration = SayHelloConfiguration.class)
}
)
public class UserApplication {
// loadBalance开启RestTemplate的负载均衡
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping("/hi")
public String hi(@RequestParam(value = "name", defaultValue = "Artaban") String name) {
// 只使用say-hello配置的服务器
String greeting = this.restTemplate.getForObject("http://say-hello/greeting", String.class);
return String.format("%s, %s!", greeting, name);
}
@RequestMapping("/bye")
public String bye(@RequestParam(value = "name", defaultValue = "ZhangSan") String name) {
// 只使用say-bye配置的服务器
String greeting = this.restTemplate.getForObject("http://say-bye/greeting", String.class);
return String.format("%s, %s!", greeting, name);
}
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
使用yml配置
直接使用yml配置就去掉了@RibbonClient的注解了
@SpringBootApplication
@RestController
public class UserApplication {
// loadBalance开启RestTemplate的负载均衡
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping("/hi")
public String hi(@RequestParam(value = "name", defaultValue = "Artaban") String name) {
// 只使用say-hello配置的服务器
String greeting = this.restTemplate.getForObject("http://say-hello/greeting", String.class);
return String.format("%s, %s!", greeting, name);
}
@RequestMapping("/bye")
public String bye(@RequestParam(value = "name", defaultValue = "ZhangSan") String name) {
// 只使用say-bye配置的服务器
String greeting = this.restTemplate.getForObject("http://say-bye/greeting", String.class);
return String.format("%s, %s!", greeting, name);
}
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
yml配置
spring:
application:
name: user
port: 8888
say-hello:
ribbon:
eureka:
# 如果你不需要使用到Eureka就设置false,服务使用listOfServer指定
enabled: false
listOfServers: localhost:9092,localhost:9999
# 刷新服务器的时间间隔
ServerListRefreshInterval: 15000
# 配置为随机使用listOfServer中的一个服务器
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# 使用PingUrl检查服务器是否存活
NFLoadBalancerPingClassName: com.netflix.loadbalancer.PingUrl
# 请求连接的超时时间
ConnectTimeout: 2000
# 请求处理的超时时间
ReadTimeout: 5000
say-bye:
ribbon:
eureka:
enabled: false
listOfServers: localhost:8090
ServerListRefreshInterval: 15000
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.AvailabilityFilteringRule
NFLoadBalancerPingClassName: com.netflix.loadbalancer.PingUrl
在yml里通过类来配置ping、rule等规则的方式代表say-bye的命名
# 指定LoadBalancer实现类,负载均衡器
<clientName>.ribbon.NFLoadBalancerClassName: 实现 ILoadBalancer
# 指定IRule实现类,选择服务规则
<clientName>.ribbon.NFLoadBalancerRuleClassName: 实现 IRule
# 指定IPing,探测服务是否存活
<clientName>.ribbon.NFLoadBalancerPingClassName: 实现 IPing
# 指定ServerList实现类,服务列表
<clientName>.ribbon.NIWSServerListClassName: 实现 ServerList
# 指定ServerListFilter实现类,筛选服务列表
<clientName>.ribbon.NIWSServerListFilterClassName: 实现 ServerListFilter