SpringCloud-Ribbon:负载均衡(基于客户端)

6. Ribbon:负载均衡(基于客户端)

6.1 负载均衡以及Ribbon

Ribbon是什么?

  • Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
  • 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法 ,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!

Ribbon能干嘛?

通过Ribbon的负载均衡(轮询、随机算法等)实现将10000个请求分配个多个服务注册中心(请求处理方)

  • LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
  • 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。
  • 常见的负载均衡软件有 NginxLvs 等等。
  • Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。

负载均衡简单分类:

  • 集中式LB
    即在服务的提供方和消费方之间使用独立的LB设施 ,如Nginx(反向代理服务器) ,由该设施负责把访问请求通过某种策略转发至服务的提供方!
  • 进程式 LB
    将LB逻辑集成到消费方消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
    Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址

6.2 SpringCloud集成Ribbon

① 在springcloud-consumer-dept-80 添加 Ribbon和Eureka依赖

xml 复制代码
<!--Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

② 在application.yml 配置Eureka

yml 复制代码
# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向 Eureka注册自己,注册服务器就好
    service-url: # 从三个注册中心中随机取一个去访问
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

③在启动类的上添加@EnableEurekaClient ,启动Eureka

④ 自定义Spring配置类:ConfigBean.java 配置负载均衡实现RestTemplate

java 复制代码
@Configuration
public class ConfigBean {//@Configuration -- spring  applicationContext.xml

    @LoadBalanced //配置负载均衡实现RestTemplate
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

⑤ 修改conroller:DeptConsumerController.java

java 复制代码
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

⑥测试结果:先启动7001、7002,再启动8001,最后客户端

6.3 使用Ribbon实现负载均衡

Ribben从服务注册中心获得可用的已注册服务列表,通过默认的轮询算法来实现负载均衡,选择服务提供者

流程图:

1、 新建两个服务提供者 :8002、8003

2、新建两个数据库,参考8001,为另外两个Moudle添加pom.xml依赖 、resourece下的mybatis和application.yml配置,Java代码

3、启动所有服务测试(根据自身电脑配置决定启动服务的个数),访问http://eureka7001.com:7002/查看结果

6.4 自定义负载均衡算法

在springcloud-provider-dept-80模块下的ConfigBean中进行配置

1.去查看IRule的源码,里面封装着许多负载均衡的算法,根据具体需求挑选使用就好

java 复制代码
@Configuration
public class MyRule {

    @Bean
    public IRule myRule(){
        return new MyRandomRule();//默认是轮询RandomRule,现在自定义为自己的
    }
}

查看IRule的源码,会发现许多负载均衡的算法

2.自定义负载均衡算法的要求

注意:官网要求

注:不是配置类,是配置类的算法,不和主启动类同一目录,否则会被扫描到,所有的RibbenClient都会共享使用

3.在启动类上,加载我们自定义的Ribben类

注意:指定name="具体的服务提供者的id",指定自定义的Ribben类

java 复制代码
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//开启负载均衡,并指定自定义的规则
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

4、另建新的包,配置自定义负载均衡算法以bean形式注入Spring中

5、自定义算法类

①先理解随机算法的源码:

②制定自定义算法的效果

③具体的算法

自定义的规则 :参考源码,修改一下

java 复制代码
public class MyRandomRule extends AbstractLoadBalancerRule {

    /**
     * 每个服务访问5次则换下一个服务(总共3个服务)
     * <p>
     * total=0,默认=0,如果=5,指向下一个服务节点
     * index=0,默认=0,如果total=5,index+1
     */
    private int total = 0;//被调用的次数
    private int currentIndex = 0;//当前是谁在提供服务

    //@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();//获得当前活着的服务
            List<Server> allList = lb.getAllServers();//获取所有的服务

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }

            //int index = chooseRandomInt(serverCount);//生成区间随机数
            //server = upList.get(index);//从或活着的服务中,随机获取一个

            //=====================自定义代码=========================

            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex > upList.size()) {
                    currentIndex = 0;
                }
                server = upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
            }
            
            //======================================================
            
            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }
            if (server.isAlive()) {
                return (server);
            }
            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }
        return server;
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub
    }
}

6、测试效果:

注意:

SpringCloud-Ribbon:负载均衡(基于客户端) 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

相关推荐
splage31 分钟前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
yaoyouzhong4 小时前
RabbitMQ HAProxy 负载均衡
rabbitmq·负载均衡·ruby
有梦想的小何5 小时前
`Java并发排障实录:没有报错,却把正确数据覆盖错了`
java·spring boot·mysql·spring cloud
未秃头的程序猿6 小时前
从“拆东墙补西墙”到“最终一致”:分布式事务在Spring Boot/Cloud中的破局之道
分布式·后端·spring cloud
Han.miracle6 小时前
eureka的使用负载均衡
运维·负载均衡
青槿吖7 小时前
告别RestTemplate!Feign让微服务调用像点外卖一样简单
java·开发语言·分布式·spring cloud·微服务·云原生·架构
我是无敌小恐龙7 小时前
Java SE 零基础入门 Day02 运算符与流程控制超详细笔记
java·数据结构·spring boot·笔记·python·spring·spring cloud
wzy06238 小时前
ProxySQL(一)—— 实现 MySQL 读写分离、读负载均衡
负载均衡·读写分离·proxysql
StackNoOverflow9 小时前
SpringCloud 声明式服务调用 —— Feign 全面解析(入门 + 原理 + 优化)
后端·spring·spring cloud
源远流长jerry1 天前
LVS 负载均衡完全指南:从入门到精通
运维·负载均衡·lvs