依赖默认eureka中集成
在RestTemplate中添加注解
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
默认RestTemplate发送请求为(模拟get请求,返回值为String,result为html):
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("http://www.baidu.com", String.class);
Ribbon接管后所做的事情(具体域名或ip替换成服务名称(或集群的服务名称)):
String url = "http://orderService/hello";
String result = restTemplate.getForObject(url, String.class);
1、Ribbon怎么将 http://orderService/hello 变成 http://127.0.0.1:8080/hello 发起请求?
- 拦截请求
- 截取服务名称
- 借助eureka来做服务发现 list<>
- 通过负载均衡算法,拿到一个服务 ip port (重点)
- 重构url
- 发起请求
LoadBalancerClient 是 SpringCloud 提供的一种负载均衡客户端,Ribbon 负载均衡组件内部也是集成了 LoadBalancerClient 来实现负载均衡。
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/testLoadBalance")
public void testLoadBalancer() {
ServiceInstance choose = loadBalancerClient.choose("orderService");
}
选择一个服务进入BaseLoadBalancer中:
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
// 请求次数++
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
再进入ZoneAvoidanceRule的父类PredicateBasedRule.choose方法
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// 选择轮询算法
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
AbstractServerPredicate.chooseRoundRobinAfterFiltering
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
if (eligible.size() == 0) {
return Optional.absent();
}
// 使用轮询算法
return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}
private int incrementAndGetModulo(int modulo) {
for (;;) {
// 请求次数
int current = nextServerCyclicCounter.get();
// 由于请求次数加一,线程不安全,加锁
int next = (current + 1) % modulo;
// 乐观锁,CAS自旋锁
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
2、使用其他算法:
orderservice: # 服務提供者的應用名稱
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # IRule下實現類算法的全限定類名
(1)随机策略 RandomRule:随机数选择服务列表中的服务节点Server,如果当前节点不可用,则进入下一轮随机策略,直到选到可用服务节点为止
(2)轮询策略 RoundRobinRule:按照接收的请求顺序,逐一分配到不同的后端服务器
(3)重试策略 RetryRule:在选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用 subRule 的方式选择一个可用的server;
(4)可用过滤策略 PredicateBaseRule:过滤掉连接失败 和 高并发连接 的服务节点,然后从健康的服务节点中以线性轮询的方式选出一个节点返回
(5)响应时间权重策略 WeightedRespinseTimeRule:根据服务器的响应时间分配一个权重weight,响应时间越长,weight越小,被选中的可能性越低。主要通过后台线程定期地从 status 里面读取平均响应时间,为每个 server 计算一个 weight
(6)并发量最小可用策略 BestAvailableRule:选择一个并发量最小的服务节点 server。ServerStats 的 activeRequestCount 属性记录了 server 的并发量,轮询所有的server,选择其中 activeRequestCount 最小的那个server,就是并发量最小的服务节点。该策略的优点是可以充分考虑每台服务节点的负载,把请求打到负载压力最小的服务节点上。但是缺点是需要轮询所有的服务节点,如果集群数量太大,那么就会比较耗时。
(7)区域权重策略 ZoneAvoidanceRule:综合判断 server 所在区域的性能 和 server 的可用性,使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate 用于过滤掉连接数过多的Server。
3、Ribbon配置:
ribbon:
eager-load:
enabled: false # 默认false,使用懒加载,true则第一次请求去拉取eureka中服务列表
eureka:
enabled: true
http: # 使用ribbon 用的restTemplate请求(底层 java.net.HttpUrlConnection 发的请求),方便但不支持连接池
client: # 发请求的工具有很多 HttpClient 它支持连接池,效率更高
enabled: false #开启ribbon超时管理
okhttp: # 移动端轻量级请求工具
enabled: false
ReadTimeout: 3000 #请求超时时间
ConnectTimeout: 3000 #连接超时时间
注意:Ribbon(ILoadBalancer接口)作用:从Eureka拉取服务列表,使用IRule算法实现客户端调用的负载均衡