03、SpringCloud之Ribbon(netflix)学习笔记(二)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 03、SpringCloud之Ribbon(netflix)学习笔记(二)

三、负载均衡算法



3.1、轮询算法思路


轮训的算法 怎么去实现
两台机器   A B
A
B
A
B
代码实现轮训的算法  List<机器>
请求次数
 int index =   1 % size    list.get(index);
% 取模 取余好处是一个周期函数 让得到的结果 总是小于 除数的
 1 / 2    1 % 2
1%2=1
2%2=0
3%2=1
4%2=0
全局顶一个int i = 0
i++  线程不安全的
i % size
怎么能做一个线程安全的轮训算法   加锁 效率极低  CAS 自旋锁 没有线程的等待和唤醒的开销
CAS 优点 性能好 java层面无锁的状态  但是在jvm层面 有锁的cmpxchg
CAS 缺点 会导致短暂时间内 CPU 飙升  还有ABA 问题



3.2、实战—项目中选择负载均衡算法



方式一:指定某个服务使用轮询算法(配置文件)

application.yaml:指定某个服务来使用对应的


# 访问不用的服务可以使用不用的算法规则
provider:  # 先写服务提供者的应用名称
    ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule    #几种算法的全限定类名


检验:在BaseLoadBalancer类中的chooseServer()中的下列行打上断点即可



方式二:全局配置负载均衡算法(注入bean方式)



在配置类中手动注入某个负载均衡算法:


//手动注入一个负载均衡器
@Bean
public IRule loadBalanced() {
    return new RandomRule();
}


方式三:自己实现一个负载均衡算法

package com.changlu.ribbonconsumer.config;



import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
/**
 * @Description: 我的自定义负载均衡器
 * @Author: changlu
 * @Date: 10:21 PM
 */
public class MyRule implements IRule {
    @Override
    public Server choose(Object key) {
        return null;
    }
    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
    }
    @Override
    public ILoadBalancer getLoadBalancer() {
        return null;
    }
}



实现好了自定义的负载均衡算法后,我们使用之前的方式一、方式二即可。


四、负载均衡源码分析


入口从下面的choose()开始:


//方式二:使用ribbon提供的客户端来进行负载均衡获取服务
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/testRibbon2")
public String testRibbon2(String serviceId) {
    //根据服务来进行选择一个实例
    ServiceInstance choose = loadBalancerClient.choose(serviceId);
    return choose.toString();
}


RibbonLoadBalancerClient.java:


public ServiceInstance choose(String serviceId) {
    //1、走this.choose
    return this.choose(serviceId, (Object)null);
}
public ServiceInstance choose(String serviceId, Object hint) {
    //2、走getServer
    Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
    return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    //3、走loadBalancer.chooseServer【=> ZoneAwareLoadBalancer】
    return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}


ZoneAwareLoadBalancer.java:


public Server chooseServer(Object key) {
    if (ENABLED.get() && this.getLoadBalancerStats().getAvailableZones().size() > 1) {
        ...
    } else {
        logger.debug("Zone aware logic disabled or there is only one zone");
        //走这里的选择服务器(key=default)
        return super.chooseServer(key);
    }
}


BaseLoadBalancer.java:这里实际上会进行使用当前实例的rule规则来进行负载均衡


public Server chooseServer(Object key) {
    if (this.counter == null) {
        this.counter = this.createCounter();
    }
    this.counter.increment();
    if (this.rule == null) {
        return null;
    } else {
        try {
            //根据对应的rule规则来进行选择key
            //当前this.rule => ZoneAvoidancePredicate
            return this.rule.choose(key);
        } catch (Exception var3) {
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
            return null;
        }
    }
}


ZoneAvoidanceRule#(其父类为:PredicateBasedRule,choose在其父类方法中)


注意默认走的是这个ZoneAvoidanceRule规则。

PredicateBasedRule.java:


public Server choose(Object key) {
    ILoadBalancer lb = this.getLoadBalancer();
    //走这个chooseRoundRobinAfterFiltering
    Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
    return server.isPresent() ? (Server)server.get() : null;
}


AbstractServerPredicate.java:


public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
    List<Server> eligible = this.getEligibleServers(servers, loadBalancerKey);
    //走其中的this.incrementAndGetModulo()
    return eligible.size() == 0 ? Optional.absent() : Optional.of(eligible.get(this.incrementAndGetModulo(eligible.size())));
}
//就是一个cas轮询操作
//modulo = 2(2.3中项目)
private int incrementAndGetModulo(int modulo) {
    for (;;) {
        int current = nextIndex.get();
        int next = (current + 1) % modulo;
        if (nextIndex.compareAndSet(current, next) && current < modulo)
            return current;
    }
}


五、ribbon负载均衡详细配置



ribbon:
    eager-load:
        enabled: false # ribbon它只有自己的话 能不能做服务发现 借助eureka  # ribbon需要去eureka中获取服务列表 如果false就懒加载
    eureka:
        enabled: true  # 开启eureka支持
    # 若是想要选择其他网络请求工具,可以来进行下面选择配置
    http:  # 我们使用ribbon 用的restTemplate发请求 java.net.HttpUrlConnection 发的请求  很方便 但是它不支持连接池
        client:  # 发请求的工具有很多 httpClient  它支持连接池 效率更好  如果你想改请求的工具 记得加这个依赖即可
            enabled: false
    okhttp: # 这个也是请求工具 移动端用的比较多 轻量级的请求
        enabled: false


六、Ribbon总结


可以使用Eureka+Ribbon来做分布式项目!


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQ9okMP1-1657598291528)(C:\Users\93997\AppData\Roaming\Typora\typora-user-images\image-20220705223200391.png)]


Ribbon 是客户端实现负载均衡的远程调用组件,用法简单 
Ribbon 源码核心: ILoadBalancer 接口:起到承上启下的作用 
    1. 承上:从 eureka 拉取服务列表 
    2. 启下:使用 IRule 算法实现客户端调用的负载均衡


设计思想:


每一个服务提供者都有自己的 ILoadBalancer 
userService---》客户端有自己的 ILoadBalancer 
TeacherService---》客户端有自己的 ILoadBalancer 
在客户端里面就是 Map<String,ILoadBalancer> iLoadBalancers Map<String,ILoadBalancer> iLoadBalancers 消费者端 
服务提供者的名称 value (服务列表 算法规则 )


如何实现负载均衡的呢?


iloadBalancer loadbalance = iloadBalancers.get(“user-service”) 
List<Server> servers = Loadbalance.getReachableServers();//缓存起来 
Server server = loadbalance .chooseServer(key) //key 是区 id,--》IRule 算法 chooseServer 下面有一个 IRule 算法
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
3月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
展望未来,随着5G、边缘计算等新技术的兴起,微服务架构的设计理念将会更加深入人心,Spring Cloud和Netflix OSS也将继续引领技术潮流,为企业带来更为高效、灵活且强大的解决方案。无论是对于初创公司还是大型企业而言,掌握这些前沿技术都将是在激烈市场竞争中脱颖而出的关键所在。
68 0
|
3月前
|
Java 对象存储 开发者
解析Spring Cloud与Netflix OSS:微服务架构中的左右手如何协同作战
Spring Cloud与Netflix OSS不仅是现代微服务架构中不可或缺的一部分,它们还通过不断的技术创新和社区贡献推动了整个行业的发展。无论是对于初创企业还是大型组织来说,掌握并合理运用这两套工具,都能极大地提升软件系统的灵活性、可扩展性以及整体性能。随着云计算和容器化技术的进一步普及,Spring Cloud与Netflix OSS将继续引领微服务技术的发展潮流。
65 0
|
1月前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
50 15
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
58 5
|
2月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
52 1
|
2月前
|
监控 Java 对象存储
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
46 1
|
3月前
|
Java 开发工具 对象存储
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
53 2
|
3月前
|
消息中间件 Java 对象存储
数据一致性挑战:Spring Cloud与Netflix OSS下的分布式事务管理
数据一致性挑战:Spring Cloud与Netflix OSS下的分布式事务管理
58 2
|
3月前
|
Java 对象存储 开发者
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
57 3
|
3月前
|
负载均衡 Java 对象存储
负载均衡策略:Spring Cloud与Netflix OSS的最佳实践
负载均衡策略:Spring Cloud与Netflix OSS的最佳实践
54 2