前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud系列(六)| 聊聊负载均衡

SpringCloud系列(六)| 聊聊负载均衡

作者头像
一缕82年的清风
发布2023-12-18 13:07:50
9100
发布2023-12-18 13:07:50
举报
文章被收录于专栏:lsqingfeng

一、负载均衡概述

上一篇文章中,我们在集成OpenFeign的过程中提示我们需要加入了一个依赖就是: spring-cloud-starter-loadbalancer。 顾名思义,这个包的作用就是用来做负载均衡的。

简单解释一下什么是负载均衡,就是当我们的服务有多个实例的时候,比如我们userservice, 一个端口号是8081,一个端口号是8082。当然这是因为我只有一天电脑只能一台机器上模拟。正常情况我们的两个用户服务肯定应该是部署在两台机器上,这样就可以防止其中一台机器出现故障而导致的服务不可用的问题,这叫做分布式部署。而部署了两个相同的服务,当我们有大量的请求过来的时候,就可以把请求平均分布到两台机器上分别处理,降低每个服务的负载,使他们的压力得到均衡。这就是服务均衡。

那我们实际来验证一下,我们加入了这个包是否实现了负载均衡的功能。怎么验证的,就是同时启动两个用户服务。然后调用的时候,看请求是否能够均衡的打到两个服务上。

二、负载均衡验证

我们先来改造一下我们的用户接口,由于两个服务的端口号是不一样的,我们就在程序当中打印一下端口号。

代码语言:javascript
复制
package com.lsqingfeng.springcloud.user.controller;

import com.lsqingfeng.springcloud.common.base.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @className: UserController
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 17:25
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

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

    @GetMapping("hello")
    public Result hello(String name){
        log.info("被请求到的服务端口号为: " + port);
        return Result.success(name);
    }

}

然后按照上篇文章的方式,启动两个用户服务。

另外一个:

然后自启动订单服务,订单服务的接口中已经通过openFeign成功调用了userservice中的接口。我们观察日志,看看调用的是哪个服务。

第一次调用:

服务一打印了日志:

再次调用:

服务二打印了日志。这就验证了请求是在两个机器上分别出现了。说明我们的负载均衡已经实现了。

而且Spring-Cloud-Loadbalancer默认的负载均衡策略就是轮训策略。也就是一人一下,轮着来。而负载均衡也有其他的策略。

三、spring-cloud-starter-loadbalancer

Spring Cloud LoadBalancer是一个客户端负载均衡器,类似于Ribbon,但是由于Ribbon已经进入维护模式,并且Ribbon 2并不与Ribbon 1相互兼容,所以Spring Cloud全家桶在Spring Cloud Commons项目中,添加了Spring cloud Loadbalancer作为新的负载均衡器,并且做了向前兼容。由于我们使用的SpringCloud版本比较新,引入的nacos依赖中已经不包含ribbon的相关依赖了。如果你使用的是相对比较老的版本,在使用Spring-cloud-loadbalancer的时候,需要将 ribbon的相关依赖排除掉,同时在配置文件中禁用ribbon。

关于spring-cloud-loadbalancer的具体内容,可以参看一下官方文档:

地址: Cloud Native Applications

通过文档中的描述,

Spring Cloud 中内部微服务调用默认是 http 请求,主要通过下面三种 API:

  • RestTemplate:同步 http API
  • WebClient:异步响应式 http API
  • 三方客户端封装,例如 openfeign

如果项目中加入了 spring-cloud-loadbalancer 的依赖并且配置启用了,那么会自动在相关的 Bean 中加入负载均衡器的特性。

  • 对于 RestTemplate,会自动对所有 @LoadBalanced 注解修饰的 RestTemplate Bean 增加 Interceptor 从而加上了负载均衡器的特性。
  • 对于 WebClient,会自动创建 ReactorLoadBalancerExchangeFilterFunction,我们可以通过加入ReactorLoadBalancerExchangeFilterFunction会加入负载均衡器的特性。
  • 对于三方客户端,一般不需要我们额外配置什么。

所以由于我们使用的是openFein,如果想要自己定义一套负载均衡的算法策略,我找了很多的资料都没有相关的介绍,应该是目前来讲,可能还不支持针对openFeign的定制化负载均衡策略。如果大家有相关资料也可以分享给我。目前来讲,这种轮训机制的策略也可以满足一般的负载均衡需求。

当然如果确实有自定义负载均衡策略的需要,那么我们也可以把openFeign的调用改为RestTemplate或者 WebClient。这样就可以实现了。

四、负载均衡实现

上面的内容写于2022年,现在是2023年,我又重新开始写这个专题的时候,又重新研究了一下这个问题。发现OpenFeign和 loadbalancer集成的时候,可以可以来配置负载均衡策略的。 只不过负载均衡的策略目前只有两种,一种是随机、一种是轮询。这里来讲解一下具体的配置过程。

首先要注意,我们要在调用方进行配置!在调用方进行配置!在调用方进行配置!在调用方进行配置!

那我们进入调用方的工程,先添加一个负载均衡的配置类。 创建一个conf包,添加一个类如下:

代码语言:javascript
复制
package com.lsqingfeng.springcloud.conf;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
* @className: LoadBalancedConfig
* @description: 
* @author liushuai
* @date 2023/3/8 3:45 PM
*/
@Configuration
public class LoadBalancedConfig {
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // 随机方式,轮询方式: RoundRobinLoadBalancer
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

这里最后返回的RandomLoadBalancer 就是代表的随机轮询策略机制。

然后在feignClient上添加一个注解。

代码语言:javascript
复制
@LoadBalancerClient(name="userservice", configuration = LoadBalancedConfig.class)

这里的configuration就指向我们刚刚写的那个配置类。完整代码如下:

代码语言:javascript
复制
package com.lsqingfeng.springcloud.order.client;

import com.lsqingfeng.springcloud.common.base.Result;
import com.lsqingfeng.springcloud.conf.LoadBalancedConfig;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @interface: UserFeignClient
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 19:10
 */
@Component
@FeignClient(name="userservice")
@LoadBalancerClient(name="userservice", configuration = LoadBalancedConfig.class)
public interface UserFeignClient {
    /**
     * userController中的hello
     * @param name
     * @return
     */
    @GetMapping("/user/hello")
    Result hello(@RequestParam("name") String name);
}

接下来就可以了。我们启动三个userService实例。 一个OrderService实例。 通过调用接口,查看被调用的服务情况。(关于idea启动过个服务报错,前面讲过)

我们调用了三次order/getOrder接口。查看UserService服务中的的日志

发现8084被调用了两次,8082被调用了一次。 看样子应该是随机的。

接下来换成轮询的试试。修改OrderService中的配置类。改为:RoundRobinLoadBalancer

代码语言:javascript
复制
@Configuration
public class LoadBalancedConfig {
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // 随机方式,轮询方式: RoundRobinLoadBalancer
        return new RoundRobinLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

重新启动OrderService.

再来调用三次服务:

发现每个服务都被调用了一次,验证了我们的猜测。说明我们还是可以对负载均衡的策略进行配置的。

如果觉得这两种方式满足不了,那么我们就只能自己去写实现了。可以参考RoundRobinLoadBalancer的方式尝试着去做下。其实如果没有啥特殊需求,这两种策略其实也足够使用了。

好了,关于这一部分的内容,我们就先到这里吧。代码已经上传到了gitCode。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、负载均衡概述
  • 二、负载均衡验证
  • 三、spring-cloud-starter-loadbalancer
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档