[Cloud]ribbon面试准备

目录

前言:

1. Ribbon

1.1 IRule

1.2想要更改默认的负载均衡规则?

1.3 Ribbon原理

1.4 源码

2. 手写轮询算法


前言:

Ribbon

是一个软负载均衡的客户端的组件

服务消费者自己继承了Ribbon,从注册中心拉取服务端列表。

1. Ribbon

默认使用轮询的负载均衡算法

1.1 IRule

这个是Ribbon的负载均衡更改的接口

public interface IRule {
    Server choose(Object var1);

    void setLoadBalancer(ILoadBalancer var1);

    ILoadBalancer getLoadBalancer();
}
AbstractLoadBalance
public abstract class AbstractLoadBalancer implements ILoadBalancer {
    public AbstractLoadBalancer() {
    }

    public Server chooseServer() {
        return this.chooseServer((Object)null);
    }

    public abstract List<Server> getServerList(AbstractLoadBalancer.ServerGroup var1);

    public abstract LoadBalancerStats getLoadBalancerStats();

    public static enum ServerGroup {
        ALL,
        STATUS_UP,
        STATUS_NOT_UP;

        private ServerGroup() {
        }
    }
}

结合周阳的网易云课堂:

Ribbon中IRule自带的负载规则有这些,出厂默认为轮询。

 1.2想要更改默认的负载均衡规则?

@Configuration

public class MySelfRule {

@Bean

public IRule myRule(){

return new RandomRule();

}

}

注意上面配置类不能跟springboot目录放在一起

然后在springboot启动类上面加上

@RibbonClient(那么= “xxxx service“, configuration = MySelfRule .class)

1.3 Ribbon原理

负载均衡算法:rest接口的第几次请求%服务器的集群的总数量 = 实际调用的服务器位置的下标

每次重启之后从1开始计数

1.4 源码

public class RoundRobinRule extends AbstractLoadBalancerRule {
    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;
    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        this.nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        this.setLoadBalancer(lb);
    }

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        } else {
            Server server = null;
            int count = 0;

            while(true) {
                if (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) {
                        int nextServerIndex = this.incrementAndGetModulo(serverCount);
                        server = (Server)allServers.get(nextServerIndex);
                        if (server == null) {
                            Thread.yield();
                        } else {
                            if (server.isAlive() && server.isReadyToServe()) {
                                return server;
                            }

                            server = null;
                        }
                        continue;
                    }

                    log.warn("No up servers available from load balancer: " + lb);
                    return null;
                }

                if (count >= 10) {
                    log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                }

                return server;
            }
        }
    }

    private int incrementAndGetModulo(int modulo) {
        int current;
        int next;
        do {
            current = this.nextServerCyclicCounter.get();
            next = (current + 1) % modulo;
        } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

        return next;
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

视频地址


    private int incrementAndGetModulo(int modulo) {
        int current;
        int next;
        do {
            current = this.nextServerCyclicCounter.get();
            next = (current + 1) % modulo;
        } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

        return next;
    }

 

//这里面用了CAS,自旋锁。当前current = 0 

0+1 取余数,然后就可以进行CAS然后得到一个next

写的比较优雅,使用CAS 使用的是AtomicInteger中的CAS compareAndSet

因为它的类中有

private AtomicInteger nextServerCyclicCounter;

2. 手写轮询算法

如果是ribbon做负载均衡的话,@LoadBalanced

/**
 * 轮询接口
 */
public interface LoadBalance {
 
    ServiceInstance getInstance(List<ServiceInstance> serviceInstances);
}
@Component
public class MyLoadBalancer implements LoadBalance {
 
 
    //原子封装类
    private AtomicInteger atomicInteger = new AtomicInteger(0);
 
    /**
     * 计算得到当前调用次数
     * @return
     */
    public final int getAndIncrement(){
        int current;
        int next;
 
        do {
            current = atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current+1;
        }while (!atomicInteger.compareAndSet(current,next));   //利用CAS保证原子操作
 
        return next;
    }
 
 
    /**
     * 轮询算法
     * 当前调用数 % 服务实例数量
     * @param serviceInstances
     * @return
     */
    @Override
    public ServiceInstance getInstance(List<ServiceInstance> serviceInstances) {
        int index = this.getAndIncrement() % serviceInstances.size();
        //根据下标返回对应的服务实例
        return serviceInstances.get(index);
    }
}

策略调用:

@RestController
@Slf4j
public class OrderController {
 
    @Resource
    private RestTemplate restTemplate;
 
    @Resource
    private MyLoadBalancer myLoadBalancer;
 
    @Resource
    private DiscoveryClient discoveryClient;
 
 
 
    @GetMapping(value = "/consumer/payment/getInstance/{id}")
    public GeneralResult<Integer> getPaymentByInstance(@PathVariable("id")Long id){
        //获取所有服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if(instances == null || instances.size() <= 0){
            return null;
        }
        //根据我们的轮询算法得到对应的服务实例
        ServiceInstance instance = myLoadBalancer.getInstance(instances);
        //根据服务实例获得服务器的uri
        URI uri = instance.getUri();
        return restTemplate.getForObject(uri+"cloud/payment/get/"+id,GeneralResult.class);
    }
}

这部分转自:https://blog.csdn.net/weixin_44245778/article/details/107391072

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值