SpringCloud-Ribbon负载均衡机制、手写轮询算法
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了SpringCloud-Ribbon负载均衡机制、手写轮询算法,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3860字,纯文字阅读大概需要6分钟。
内容图文
![SpringCloud-Ribbon负载均衡机制、手写轮询算法](/upload/InfoBanner/zyjiaocheng/635/b28ae2bc1a6e4adbb98ed593190b8571.jpg)
Ribbon 内置的负载均衡规则
在 com.netflix.loadbalancer
包下有一个接口 IRule
,它可以根据特定的算法从服务列表中选取一个要访问的服务,默认使用的是「轮询机制」
- RoundRobinRule:轮询
- RandomRule:随机
- RetryRule:先按照
RoundRobinRule
的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务 - WeightedResponseTimeRule:对
RoundRobinRule
的扩展,响应速度越快的实例选择权重越大,越容易被选择 - BestAvailableRule:会过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例
- ZoneAvoidanceRule:默认规则,复合判断 server 所在区域的性能和 server 的可用性选择服务器
负载规则的替换
如果不想使用 Ribbon 默认使用的规则,我们可以通过自定义配置类的方式,手动指定使用哪一种。
需要注意的是,自定义配置类不能放在 @ComponentScan
所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的 Ribbon 客户端所共享,达不到特殊化定制的目的了。
因此我们需要在 Spring Boot 启动类所在包的外面新建一个包存放自定义配置类
@Configuration
public class MyselfRule {
@Bean
public IRule rule(){
//随机
return new RandomRule();
}
}
然后在启动类上添加如下注解,指定服务名及自定义配置类
@RibbonClient(value = "CLOUD-PAYMENT-SERVICE", configuration = MyselfRule.class)
Ribbon 默认负载轮询算法的原理
算法概述
rest 接口第几次请求数 % 服务器集群总个数 = 实际调用服务器位置下标,服务每次重启后 rest 请求数变为1
源码
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
//循环获取服务,最多获取10次
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
//开启的服务个数
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
//计算下一个服务的下标
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
//通过此方法获取服务的下标,使用了 CAS 和自旋锁
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
手写轮询算法
在服务提供者写一个方法,返回端口号看效果就行
@GetMapping("/payment/lb")
public String roundLb(){
return this.serverPort;
}
负载均衡接口
public interface LoadBalancer {
/**
* 获取服务实例
*/
ServiceInstance getInstance(List<ServiceInstance>serviceInstances);
}
算法实现类
@Component
public class MyLb implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
/**
* 使用「自旋锁」和「CAS」增加请求次数
*/
public final int incrementAndGet() {
int current;
int next;
do {
current = atomicInteger.get();
//防溢出
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!atomicInteger.compareAndSet(current, next));
return next;
}
@Override
public ServiceInstance getInstance(List<ServiceInstance> serviceInstances) {
// 实际调用服务器位置下标 = rest 接口第几次请求数 % 服务器集群总个数
int index = incrementAndGet() % serviceInstances.size();
return serviceInstances.get(index);
}
}
编写服务消费者方法,记得注释 @LoadBalanced
注解,否则不生效
@GetMapping("/consumer/payment/lb")
public String roundLb(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances.size() <= 0){
return null;
}
ServiceInstance instance = loadBalancer.getInstance(instances);
URI uri = instance.getUri();
return restTemplate.getForObject(uri + "/payment/lb", String.class);
}
内容总结
以上是互联网集市为您收集整理的SpringCloud-Ribbon负载均衡机制、手写轮询算法全部内容,希望文章能够帮你解决SpringCloud-Ribbon负载均衡机制、手写轮询算法所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。