Spring Cloud Ribbon 负载均衡入门

1. 简介

Ribbon是Netflix开源的客户端负载均衡器,它在客户端实现服务调用的负载均衡,可以根据用户配置的策略从服务注册中心获取的服务列表中选择合适的实例进行请求。Ribbon不仅支持多种负载均衡策略,如轮询、随机、权重分配等,还提供了重试机制,增强了服务调用的稳定性和容错性。本文主要介绍nacos-discovery引入Ribbon,并结合Nacos实现服务间负载均衡。

2. 负载均衡策略

2.1. 负载均衡实现

两种主要方式实现服务的负载均衡:客户端级别负载均衡和服务端级别负载均衡。
1.客户端级别负载均衡(Client-side Load Balancing):客户端(通常是微服务架构中的服务消费者)负责负载均衡的逻辑。客户端从服务注册中心获取到所有可用的服务提供者的列表,并根据某种负载均衡策略(如轮询、随机、最少连接数等)选择其中一个服务实例进行调用。在Spring Cloud生态中,Ribbon就是一种典型的客户端负载均衡器。
2. 服务端级别负载均衡(Server-side Load Balancing): 在服务端负载均衡模型中,客户端发送请求到一个固定的接入点,如负载均衡器(硬件或软件形式,如Nginx等),这个接入点负责根据预定义的策略将请求分发到后端的多个服务实例上。服务端负载均衡器通常位于网络架构的边缘,它们可以根据请求的特性(如HTTP头部、URL、客户端IP等)以及服务器的性能指标(如CPU使用率、连接数、响应时间等)来进行负载均衡。
在微服务内部,客户端负载均衡更常见;而在面向公众服务或大规模分布式系统中,服务端负载均衡更为普遍。二者常结合使用,共同构建起高效、稳定且具有弹性的分布式系统。

2.2. 负载均衡规则

负载均衡规则是指导负载均衡器如何将流量或请求分配给后端服务器的一系列策略。以下是几种常见的负载均衡规则:
1.轮询(Round Robin):
这是最简单的负载均衡策略,请求会按照循环顺序分配给每一个后端服务器,每个服务器获得下一个请求的机会是均等的。
2.权重轮询(Weighted Round Robin,WRR):
类似轮询,但每个服务器可以被赋予不同的权重,权重高的服务器接受到的请求比例更大。
3. 最少连接(Least Connections):
请求总是被分配给当前连接数最少的服务器,这样可以避免某些服务器因处理过多请求而过载。
4. 加权最少连接(Weighted Least Connections,WLC):
结合了最少连接原则和权重,优先分配给连接数最少并且权重较高的服务器。
5. 源IP哈希(Source IP Hash):
根据客户端IP地址的哈希值来确定请求应该转发到哪一个服务器,以实现会话粘滞(session stickiness)。
6. 响应时间(Response Time):
根据服务器的响应时间来分配请求,将请求分配给最近响应速度快的服务器。
7. 随机(Random):
随机选择一个服务器处理请求,这种方法在服务器性能相近的情况下可以有效分散负载。

2.3. Ribbon负载均衡策略规则

在这里插入图片描述

策略名说明
RandomRule(随机策略)随机选择服务实例进行负载均衡
RoundRobinRule(轮询策略)按照服务实例列表的顺序依次分配请求。
WeightedResponseTimeRule(响应时间加权策略)根据服务实例的响应时间动态调整权重,响应时间越短的服务实例权重越大,被选中的概率也就越大。
BestAvailableRule(最小并发数策略)遍历服务提供者列表,选取连接数最小的⼀个服务实例。如果有相同的最小连接数,那么会调用轮询策略进行选取
RetryRule(重试策略)并非标准的负载均衡策略,但在Ribbon中可以结合其他策略使用,如果某个服务实例在轮询或其他策略选定后无法正常响应,Ribbon可以尝试重试其他服务实例。
ZoneAvoidanceRule(区域亲和性策略试图在多个区域间平衡负载,避免过度集中在某一个区域,综合考虑了服务实例的连接数和区域因素。
AvailabilityFilteringRule(可用性过滤策略)会对服务实例进行过滤,例如,可以排除故障实例、只选择活动实例,或者根据特定规则(如服务实例的状态码)进行筛选。

3. 基本入门实现

准备工作
●搭建一个服务提供者provider-demo,启动两个实例,注册上nacos注册中心。
●搭建一个服务消费者consumer-demo,启动一个实例,注册上nacos注册中心。

nacos部署相关具体过程可以参考文章Spring Cloud Alibaba Nacos注册中心入门

3.1. 搭建服务提供者

创建项目作为服务提供者provider-demo。

  1. 创建maven项目
  2. 引入依赖
 <properties>
        <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.8.RELEASE</spring.cloud.alibaba.version>
    </properties>

    <!-- Spring Boot、Spring Cloud、Spring Cloud Alibaba 依赖-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- SpringMVC 相关依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
  1. 配置文件
spring:
  application:
    name: provider-demo # Spring 应用名
  cloud:
    # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
        service: ${spring.application.name}
        #  username: nacos  # 如果开启Nacos权限认证nacos.core.auth.enabled=true, 需要配置上账号密码
        #  password: nacos
server:
  port: ${random.int(18080,19090)}  # 项目启动随机端口范围
  1. 创建接口层
@RestController
public class EchoController {


    @Value("${server.port}")
    private String serverPort;

    /**
     * 获取日志记录器
     */
    private Logger logger = LoggerFactory.getLogger(EchoController.class);


    @GetMapping(value = "/echo/{name}")
    public String echo(@PathVariable String name) throws InterruptedException {
        // 模拟请求时长
        Thread.sleep(200);
        // 日志打印
        logger.info("echo print port:{}, name:{},",serverPort, name);
        return "provider-" + serverPort + "::" + name;
    }

}
  1. 启动项目
@SpringBootApplication
@EnableDiscoveryClient // 注解开启服务注册与发现功能
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

3.2. 搭建服务消费者

创建项目作为服务消费者consumer-demo,引入依赖同服服务提供者项目一致。

  1. 配置文件
spring:
  application:
    name: consumer-demo # Spring 应用名
  cloud:
    # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
        service: ${spring.application.name} # 注册到Nacos的服务名,不配置默认为应用名
        #  username: nacos  # 如果开启Nacos权限认证nacos.core.auth.enabled=true, 需要配置上账号密码
        #  password: nacos
server:
  port: 18081
  1. 初始化和配置RestTemplate Bean
@Configuration
public class RestTemplateConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}
  1. 创建接口层调用服务提供者接口
@RestController
public class TestController {


    @Autowired
    private RestTemplate restTemplate;

    private Logger logger = LoggerFactory.getLogger(TestController.class);

    /**
     * 注解方式调用
     * 直接通过restTemplate请求服务提供者
     */
    @GetMapping("/go-test")
    public String goTest(String name){
        // 2. 调用接口
        String requestUrl = "http://provider-demo/echo/" + name;
        String response = restTemplate.getForObject (requestUrl, String.class);
        logger.info("go-test, response:{}", response);
        return "consumer:" + response;
    }
    
}
  1. 启动项目
@SpringBootApplication
@EnableDiscoveryClient // 注解开启服务注册与发现功能
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

3.3. 简单说明测试

  1. 引入spring-cloud-starter-alibaba-nacos-discovery依赖默认引入 spring-cloud-netflix-ribbon依赖。因为nacos discovery组件集成了Ribbon。.

  2. nacos服务注册列表
    在这里插入图片描述

  3. 添加@LoadBalanced注解在RestTemplate Bean上,实现客户端负载均衡。在Controller层进行断点查看。

3.4. 请求服务消费者接口

请求接口http://127.0.0.1:28080/go-test?name=leader,调用接口十次,返回结果均衡。
在这里插入图片描述

4. 自定义Ribbon配置

4.1. 配置文件方式

创建一个新的服务消费者,基本与3.2搭建的服务消费者一致,只需要更改application.yml配置文件中的配置。

  1. 修改application.yml配置,增加配置provider-demo.ribbon.NFLoadBalancerRuleClassName配置项
spring:
  application:
    name: consumer-demo # Spring 应用名
  cloud:
    # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
        service: ${spring.application.name}
        #  username: nacos  # 如果开启Nacos权限认证nacos.core.auth.enabled=true, 需要配置上账号密码
        #  password: nacos
server:
  port: 28080
  
provider-demo: # nacos中的服务提供者
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 配置随机策略  
  1. 测试
    请求接口http://127.0.0.1:28080/go-test?name=leader,调用接口十次,返回结果随机。

4.2. Spring JavaConfig 方式

使用 Spring JavaConfig 的方式,实现 Ribbon 全局和 客户端两种级别的自定义配置。

  1. 创建一个新的服务消费者,基本与3.2搭建的服务消费者一致。

  2. 创建RibbonConfiguration,DefaultGlobalRibbonClientConfiguration,ProviderDemoRibbonClientConfiguration,代码层次结构如下。(注意DefaultGlobalRibbonClientConfiguration和ProviderDemoRibbonClientConfiguration是在单独的ribbon包下的,没有放在Application启动类扫描到的包下,因为会被容器扫描加载到,导致项目都使用相同的Ribbon配置,不能单独自定义配置客户端级别。)

  3. DefaultGlobalRibbonClientConfiguration类

@Configuration
public class DefaultGlobalRibbonClientConfiguration {
    @Bean
    public IRule ribbonDefaultRule() {
        return new RoundRobinRule();
    }
}
  1. ProviderDemoRibbonClientConfiguration类
@Configuration
public class ProviderDemoRibbonClientConfiguration {

    @Bean
    @Primary  // @Primary 优先选择IRule bean
    public IRule ribbonCustomRule() {
        return new RandomRule();
    }

}
  1. RibbonConfiguration类
    负载均衡全局配置和客户端级别配置
@RibbonClients(
        value = {
                @RibbonClient(name = "provider-demo", configuration = ProviderDemoRibbonClientConfiguration.class) // 客户端级别的配置
        },
        defaultConfiguration = DefaultGlobalRibbonClientConfiguration.class // 全局配置
)
@Configuration
public class RibbonConfiguration {

}
  1. @RibbonClients 注解,通过 defaultConfiguration 属性声明 Ribbon 全局级别的自定义配置,通过 value 属性声明多个 Ribbon 客户端级别的自定义配置。
  2. @Primary注解在Spring框架中用于标识一个bean作为首选bean,DefaultGlobalRibbonClientConfiguration 和 ProviderDemoRibbonClientConfiguration 都创建了 IRule Bean,Spring容器会优先使用带有@Primary注解的bean。
  1. 测试
    请求接口http://127.0.0.1:28080/go-test?name=leader,调用接口十次,返回结果随机。
    在这里插入图片描述

拓展说明:

  1. 对于 Ribbon 客户端级别的自定义配置,推荐使用配置文件的方式,简单方便好管理。
  2. 配置文件方式的优先级高于 Spring JavaConfig 方式,客户端级别的优先级高于全局级别。

5. Nacos自定义负载均衡策略

5.1. 简介

Spring Cloud Alibaba Nacos Discovery组件集成Ribbon框架,并且自定义负载均衡策略规则
NacosRule
a. 获得健康的方服务实例列表
b. 优先选择相同 Nacos 集群的服务实例列表,保证高性能。如果选择不到,则允许使用其它 Nacos 集群的服务实例列表,保证高可用。
c. 从服务实例列表按照权重进行随机,选择一个服务实例返回。

5.2. 消费者服务搭建

创建一个新的服务消费者,基本与3.2搭建的服务消费者一致,只需要更改application.yml配置文件中的配置。

  1. 修改application.yml配置,增加配置provider-demo.ribbon.NFLoadBalancerRuleClassName配置项。
spring:
  application:
    name: consumer-demo # Spring 应用名
  cloud:
    # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
        service: ${spring.application.name}
        #  username: nacos  # 如果开启Nacos权限认证nacos.core.auth.enabled=true, 需要配置上账号密码
        #  password: nacos
server:
  port: 28080
  1. 更改服务提供者其中一个实例的权重为0,点击编辑修改权重为0。服务消费者请求时,依据NacosRule策略不会选择该实例。
    在这里插入图片描述
  2. 请求接口http://127.0.0.1:28080/go-test?name=leader,调用接口十次返回结果说明只请求到一个实例。
    在这里插入图片描述

6. Ribbon主要组件

在这里插入图片描述

7. 参考

  1. Spring Cloud Ribbon 中的7种负载均衡策略
  2. 微服务负载均衡器Ribbon详解
  3. Spring Cloud Netflix
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值