Ribbon 客户端负载均衡

零、懒汉式改为饿汉式

【consumer-springboot-80子模块】

Ribbon默认使用懒汉式加载服务列表,更改为懒汉式
application.yml

ribbon: # Ribbon相关配置
  eager-load: # 采用饿汉式进行加载
    clients: dept.provider # 设置服务名称,使用“,”分割
    enabled: true # 启用饿汉式

在这里插入图片描述

一、基于配置文件

2、【consumer-springboot-80子模块】

按照SpringCloud 所给出的官方文档来讲,所有Ribbon相关的负载均衡策略全部都可以在application.yml配置文件之中进行定义,对于定义的模型采用的是“ServiceID.ribbon.类型=处理子类”,本次开发之中所使用的“dept.provider”名称就属于一个ServicelD,如果要想为项目进行 application.yml配置就采用如下的方式定义了。

修改application.yml配置文件,追加一个随机访问算法。

dept.provider: # 微服务的ID
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # IRule子类

按照现在所给出的代码的形式应该已经可以成功的进行了访问处理了,所以官方文档所提供的配置项是可以使用的。

3、【consumer-springboot-80子模块】修改application.yml配置文件,追加自定义负载均衡配置实现,现在默认情况下可以见到的负载均衡的算法为“DynamicServerListLoadBalancer”类型,本次配置同样的类型。

dept.provider: # 微服务的ID
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # IRule子类
    NFLoadBalancerClassName: com.netflix.loadbalancer.DynamicServerListLoadBalancer # ILoadBalancer

二、基于Bean配置

重要提醒:

不要与应用程序组件包重合。虽然之前所有配置的Bean都是放在了SpringBoot启动类的CLASSPATH环境之中,但是Ribbon的配置类不能够放在被直接扫描的路径下,因为会有可能造成配置的冲突。

package muyan.yootk.config.ribbon; // 该包不在应用程序启动类的扫描包路径下

import com.netflix.loadbalancer.IRule;
import muyan.yootk.loadbalancer.rule.NacosVersionRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 这个类必须使用该注解定义
public class DeptProviderRibbonConfig {
    @Bean // Bean注册
    public IRule ribbonRule() { // 自定义负载均衡规则
        return new RandomRule(); // 随机读取
    }
}

在没有进行该规则Bean配置的时候,之前采用的是一种轮询的处理模式:按照实例的数量(1,2,3,1,2,3)轮番调用,但是现在变为了随机调用。

package com.yootk.consumer;

import muyan.yootk.config.ribbon.DeptProviderRibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
// 如果此时要有多个配置项,可以使用@RibbonClients注解,该注解可以配置多个@RibbonClient
@RibbonClient(name = "dept.provider", configuration = DeptProviderRibbonConfig.class) // 自定义Ribbon配置
@EnableFeignClients("com.yootk.service") // Feign扫描包
public class StartConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartConsumerApplication.class, args);
    }
}

三、自定义规则

既然在Ribbon里面提供了如此多的默认的规则算法,那么也就可以由用户自己来进行自定义规则算法的使用了,此时直接定义配置Bean即可。

重要提醒:

不要与应用程序组件包重合。虽然之前所有配置的Bean都是放在了SpringBoot启动类的CLASSPATH环境之中,但是Ribbon的配置类不能够放在被直接扫描的路径下,因为会有可能造成配置的冲突。

1 权重优先调用

修改权重可以通过Nacos控制台的模型完成(一般是用于动态修改之中的操作),也可以直接通过微服务application.yml的方式来进行权重的配置。修改完成之后再次通过消费端来进行部门微服务的调用,这个时候发现并没有根据权重的大小来实现定义,这主要是因为Ribbon消费端的负载均衡的算法没有进行有效的配置

1.【provider-dept-*子模块】既然要观察权重可以考虑为所有部门微服务的节点来配置权重的内容,修改每一个微服务之中的application.yml 配置文件,编辑权重的内容:

provider-dept-8001配置:

spring:
  application: # 配置应用信息
    name: dept.provider # 是微服务的名称
  cloud: # Cloud配置
    nacos: # Nacos注册中心配置
      discovery: # 发现服务
        weight: 10

provider-dept-8002配置: weight: 50
provider-dept-8003配置: weight: 80

2、【consumer-springboot-80子模块】创建一个新的负载均衡算法,该算法将基于权重的高低进行调度。

package muyan.yootk.loadbalancer.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

// 如果要想进行规则的定义常见的做法是直接使用IRule接口完成
// 推荐的做法是使用IRule接口对应的抽象子类AbstractLoadBalancerRule
@Slf4j
public class NacosWeightRule extends AbstractLoadBalancerRule { // Nacos权重规则
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties; // Nacos配置属性
    private IClientConfig clientConfig;
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }
    @Override
    public Server choose(Object key) { // 选择服务实例
        BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer(); // 获取负载均衡器
        String name = loadBalancer.getName(); // 调用微服务名称
        // 此时的场景就变为了原生项目的NacosClient组件进行处理的操作了
        NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance(); // 发现服务
        // 根据指定的服务名称以及分组名称获取服务的实例
        try {
            Instance instance = namingService.selectOneHealthyInstance(name, this.nacosDiscoveryProperties.getGroup());
            // 整个的代码是工作在SpringCloud之中的,所以需要将获取到的Instance对象实例转为Server对象实例
            return new NacosServer(instance); // NacosServer是Server子类
        } catch (NacosException e) {
            log.error("获取Nacos注册的微服务实例出错,异常为:" + e);
            return null;
        }
    }
}

3、【consumer-springboot-80子模块】DeptProviderRibbonConfig

package muyan.yootk.config.ribbon; // 该包不在应用程序启动类的扫描包路径下

import com.netflix.loadbalancer.IRule;
import muyan.yootk.loadbalancer.rule.NacosVersionRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 这个类必须使用该注解定义
public class DeptProviderRibbonConfig {
    @Bean // Bean注册
    public IRule ribbonRule() { // 自定义负载均衡规则
        return new NacosWeightRule(); // 随机读取
    }
}

启动类

package com.yootk.consumer;

import muyan.yootk.config.ribbon.DeptProviderRibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
// 如果此时要有多个配置项,可以使用@RibbonClients注解,该注解可以配置多个@RibbonClient
@RibbonClient(name = "dept.provider", configuration = DeptProviderRibbonConfig.class) // 自定义Ribbon配置
@EnableFeignClients("com.yootk.service") // Feign扫描包
public class StartConsumerApplication { // 沐言科技:www.yootk.com
    public static void main(String[] args) {
        SpringApplication.run(StartConsumerApplication.class, args);
    }
}
2 集群优先调用

1、【consumer-springboot-80子模块】NacosClusterWeightRule

package muyan.yootk.loadbalancer.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
public class NacosClusterWeightRule extends AbstractLoadBalancerRule {
    // 如果要想按照集群调用,那么首先一定要知道当前消费端的集群名称是什么
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties; // 注入Nacos发现服务配置项
    @Autowired
    private IClientConfig clientConfig;

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }

    @Override
    public Server choose(Object key) { // 核心关键
        BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer();
        // 如果此时没有这个调用的微服务名称,那么是无法实现最终的服务查询的
        String name = loadBalancer.getName();// 获取服务名称
        NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();
        // 获取指定服务名称的全部的实例列表数据
        try {
            // 根据指定的服务名称以及分组查询所有健康的服务实例列表,此时的列表包含有所有的集群信息
            List<Instance> instances = namingService.selectInstances(name, this.nacosDiscoveryProperties.getGroup(), true);
            // 理论上现在应该采用的是迭代的处理形式,将全部的集合列表进行迭代处理,随后进行集群名称的判断
            List<Instance> clusterInstance = instances.stream()
                    .filter(instance -> Objects.equals(instance.getClusterName(), this.nacosDiscoveryProperties.getClusterName()))
                    .collect(Collectors.toList());
            List<Instance> instancesChoose = null; // 保存最终的返回的列表
            // 如果以上的处理可以获取指定集群名称下的全部的服务实例数据,那么就可以随意返回一个,但是如果不能够获取?
            if (CollectionUtils.isEmpty(clusterInstance)) { // 此时集群下的实例列表为空
                // 此时在指定集群名称下没有查找到任何的实例列表,所以就把所获取到的全部实例列表
                instancesChoose = instances;
            } else { // 如果已经查找到了指定集群名称下的实例列表
               instancesChoose = clusterInstance; // 保存集群实例列表
            }
            // 因为最终所需要的是一个Server实例信息,所以这个时候可以考虑随机读取一个,或者按照权重返回一个
            Instance selectedInstance = ExtendBalancer.getHostByRandomWeight2(instancesChoose);
            return new NacosServer(selectedInstance); // 指定集群名称下的一个实例
        } catch (NacosException e) {
            log.error("服务实例查询时出现了错误,异常为:{}", e);
        }
        return null;
    }
}

2、【consumer-springboot-80子模块】DeptProviderRibbonConfig

package muyan.yootk.config.ribbon; // 该包不在应用程序启动类的扫描包路径下

import com.netflix.loadbalancer.IRule;
import muyan.yootk.loadbalancer.rule.NacosVersionRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 这个类必须使用该注解定义
public class DeptProviderRibbonConfig {
    @Bean // Bean注册
    public IRule ribbonRule() { // 自定义负载均衡规则
        return new NacosClusterWeightRule (); // 随机读取
    }
}
3 元数据优先调用

1、【consumer-springboot-80子模块】NacosVersionRule

package muyan.yootk.loadbalancer.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
public class NacosVersionRule extends AbstractLoadBalancerRule {
    // 如果要想按照集群调用,那么首先一定要知道当前消费端的集群名称是什么
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties; // 注入Nacos发现服务配置项
    @Autowired
    private IClientConfig clientConfig;

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }

    @Override
    public Server choose(Object key) {
        BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer();
        // 如果此时没有这个调用的微服务名称,那么是无法实现最终的服务查询的
        String name = loadBalancer.getName();// 获取服务名称
        NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();
        try {
            // 根据指定的服务名称以及分组的名称获取全部的可用实例数据
            List<Instance> instances = namingService.selectInstances(name, this.nacosDiscoveryProperties.getGroup(), true);
            // 对获取到的实例集合进行迭代处理,筛选出所需要的与当前版本匹配的实例数据
            List<Instance> metadataVersionMatchInstance = instances.stream()
                    .filter(instance -> Objects.equals(
                            this.nacosDiscoveryProperties.getMetadata().get("version"), // 消费端配置的元数据版本项
                            instance.getMetadata().get("version"))) // 注册微服务实例配置的元数据版本项
                    .collect(Collectors.toList());
            // 必须考虑没有匹配版本下的实例筛选操作
            List<Instance> selectedInstances = null; // 最终所使用的实例集合
            if (CollectionUtils.isEmpty(metadataVersionMatchInstance)) {    // 没有查询到匹配的集合
                selectedInstances = instances;
            } else {
                selectedInstances = metadataVersionMatchInstance; // 版本匹配
            }
            Instance instance = ExtendBalancer.getHostByRandomWeight2(selectedInstances);
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("获取Nacos注册的微服务实例出错,异常为:" + e);
        }
        return null;
    }
}

3、【consumer-springboot-80子模块】DeptProviderRibbonConfig

package muyan.yootk.config.ribbon; // 该包不在应用程序启动类的扫描包路径下

import com.netflix.loadbalancer.IRule;
import muyan.yootk.loadbalancer.rule.NacosVersionRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 这个类必须使用该注解定义
public class DeptProviderRibbonConfig {
    @Bean // Bean注册
    public IRule ribbonRule() { // 自定义负载均衡规则
        return new NacosVersionRule (); // 随机读取
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
服务端负载均衡客户端负载均衡是两种不同的负载均衡方式。 服务端负载均衡是指通过一台独立的负载均衡服务器来接收客户端的请求,并根据负载均衡算法将请求分发给后端的应用服务器。这种方式需要额外的负载均衡服务器来进行请求分发。客户端发送请求后,负载均衡服务器会选择一个合适的后端服务器来处理请求。常见的服务端负载均衡实现方式有硬件负载均衡和软件负载均衡。硬件负载均衡使用专用设备(如F5、Array等),而软件负载均衡使用软件(如LVS、Nginx等)来实现。 客户端负载均衡是指在分布式系统中,客户端自己负责选择合适的后端服务器来处理请求,而不需要额外的负载均衡服务器。客户端首先从注册中心(如Eureka Server)获取服务列表,然后根据负载均衡算法选择一个服务。常见的客户端负载均衡实现方式是使用Ribbon。在客户端负载均衡中,消费者通过restTemplate远程调用触发Ribbon负载均衡策略,选择一个可用的服务提供者来处理请求。 所以,服务端负载均衡客户端负载均衡的主要区别在于负载均衡的位置和流程。服务端负载均衡需要一台独立的负载均衡服务器来进行请求分发,而客户端负载均衡是通过客户端自己的负载均衡算法来选择后端服务器处理请求,不需要额外的负载均衡服务器。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [服务器端的负载均衡客户端负载均衡](https://blog.csdn.net/weixin_55189228/article/details/125568795)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [服务端负载均衡客户端负载均衡Ribbon)的区别](https://blog.csdn.net/qq_42039738/article/details/105515996)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AloneDrifters

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值