SpringCloud LoadBalancer
作者:mmseoamin日期:2024-04-27

SpringCloud LoadBalancer

1.什么是LoadBalancer

LoadBalancer(负载均衡器)是一种网络设备或软件机制,用于分发传入的网络流量负载请求到多个后端目标服务器上,从而实现系统资源的均衡利用和提高系统的可用性和性能。

负载均衡器(LoadBalancer)就像是一位交通指挥官,它的工作是管理到达一个网站或应用的所有网络流量。想象一下,如果很多人同时访问同一个网站,就像是一群车辆同时开进一个十字路口。如果没有交通指挥,路口就会变得非常拥堵,车辆难以通行。同样地,在网络世界里,如果很多用户同时向一个服务器发送请求(比如打开网页、下载文件等),服务器可能会因为处理不过来而变得缓慢甚至崩溃。这时候,负载均衡器就像交通指挥一样,它会将流量分散到多个服务器上,确保每台服务器只处理它能够应付的流量量。这样,就算有很多用户同时访问,网站或应用也能平稳运行,每个用户都能获得良好的体验。

简而言之,负载均衡器的任务就是确保网络流量均匀分布,防止任何单一服务器因为过载而出现问题,从而保持整个网络系统的稳定和高效。

1.1负载均衡的分类

对于java程序员,只需要知道负载均衡分为服务器负载均衡和客户端 负载均衡

1.服务器负载均衡指的是存放在服务器端的负载均衡器,例如Nginx,HAProxy,F5

服务器端负载均衡是指负载均衡逻辑被实现在网络层面,通常由专门的硬件或软件(如负载均衡器)完成。在这种策略中,客户端向一个统一的地址发送请求,负载均衡器负责将请求分发到后端的多个服务器上。

步骤:

1.接收请求:负载均衡器接收到客户端的请求。

2.选择算法:负载均衡器使用某种算法选择一个后端服务器。

3.转发请求:负载均衡器将请求转发到选定的服务器。

优点:

对客户端透明,客户端不需要知道后端服务的具体分布。

统一管理,负载均衡策略的更改和维护更容易。

缺点:

可能会成为性能瓶颈和单点故障。

网络延迟可能会稍微增加,因为所有请求都需要经过负载均衡器。

2.客户端负载均衡值得是嵌套在客户端的负载均衡器,例如Ribbon,SpringCloud LoadBalancer

客户端负载均衡是指负载均衡逻辑被实现在客户端。在这种策略中,客户端负责决定将请求发送到哪个服务器。这通常涉及到以下几个步骤:

1.服务发现:客户端首先从服务注册中心获取所有可用服务实例的列表。

2.选择算法:客户端使用某种算法(如轮询、随机、最少连接等)从这些服务实例中选择一个。

3.发送请求:客户端直接将请求发送到选定的服务实例。

优点:

更灵活,可以根据客户端的具体需求和环境定制负载均衡策略。

减少了网络延迟,因为决策是在客户端本地进行的。

缺点:

增加了客户端的复杂性。

所有客户端都需要实现负载均衡逻辑。

1.2常见的负载均衡策略(不区分类型的)

  1. 轮询(Round Robin)

    描述:轮询是最简单的负载均衡策略,它按顺序将每个新请求分配给下一个服务器。当到达列表末尾时,它会重新开始。

    使用场景:适用于服务器性能相似且负载相对均衡的情况。

  2. 加权轮询(Weighted Round Robin)

    描述:与轮询类似,但给每个服务器分配一个权重。服务器的权重越高,分配给该服务器的请求就越多。

    使用场景:适用于服务器性能不均或希望给特定服务器更多流量的情况。

  3. 随机(Random)

    描述:随机选择一个服务器来处理新的请求。

    使用场景:适用于服务器数量较多且请求分布均匀的场景。

  4. 加权随机(Weighted Random)

    描述:类似于随机策略,但考虑服务器的权重。权重越高的服务器被选中的概率越大。

    使用场景:当服务器性能不均匀时,希望根据性能分配不同的请求量。

  5. 最小连接(Least Connections)

    描述:选择当前连接数最少的服务器来处理新的请求。这种方法考虑了服务器的当前负载。

    使用场景:适用于请求处理时间波动较大的场景。

  6. 加权最小连接(Weighted Least Connections)

    描述:与最小连接策略类似,但考虑了服务器的权重和当前连接数。

    使用场景:当服务器性能不同且请求处理时间不一致时使用。

  7. 基于资源(Resource Based)

    描述:根据服务器的实际资源使用情况(如CPU、内存使用率)来分配请求。

    使用场景:适用于资源敏感型应用,如高CPU或内存需求的应用。

  8. IP哈希(IP Hash)

    描述:根据请求的源IP地址进行哈希计算,然后分配到特定的服务器。这样可以保证来自同一IP地址的请求总是被发送到同一个服务器。

    使用场景:适用于需要保持用户会话(session)一致性的场景。

    SpringCloud LoadBalancer内置的策略只有轮询和随机,其他可以自己写

2.如何使用SpringCloud LoadBalancer

在项目种添加Spring Cloud OpenFeign和Nacos之后,再添加SpringCloud LoadBalancer,就会在进行接口调用的时候直接使用SpringCloud LoadBalancer

3.轮询负载均衡策略

SpringCloud LoadBalancer默认是轮询的负载均衡策略

具体配置请看我nacos文章,我直接上代码了

消费者

import com.example.consumer.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getname")
    public String getName(@RequestParam("id") Integer id){
        return userService.getName(id);
    }
}
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Service
@FeignClient("loadbalancer-service")
public interface UserService {
    @RequestMapping("/user/getname")
    String getName(@RequestParam("id") Integer id);
}

生产者

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private ServletWebServerApplicationContext context;
    @RequestMapping("/getname")
    public String getName(@RequestParam("id") Integer id){
        return context.getWebServer().getPort()+":Producer-port-"+id;
    }
}

4.随机负载均衡

实现随机负载均衡策略的步骤如下:

1.创建随机负载均衡策略(不用记,用的时候直接复制粘贴)

SpringCloud LoadBalancer,在这里插入图片描述,第1张

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.core.env.Environment;
public class RandomLoadBalancerConfig {
    @Bean
    ReactorLoadBalancer randomLoadBalancer(Environment environment,
             LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

2.设置随机负载均衡策略

2.1设置局部随机负载均衡策略(有时候可能会失灵,官方bug)

SpringCloud LoadBalancer,在这里插入图片描述,第2张

import com.example.consumer.config.RandomLoadBalancerConfig;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Service
@FeignClient("loadbalancer-service")
@LoadBalancerClient(name="loadbalancer-service",configuration = RandomLoadBalancerConfig.class)
public interface UserService {
    @RequestMapping("/user/getname")
    String getName(@RequestParam("id") Integer id);
}

2.2设置全局随机负载均衡策略(建议)

SpringCloud LoadBalancer,在这里插入图片描述,第3张

@SpringBootApplication
@EnableFeignClients
@LoadBalancerClients(defaultConfiguration = RandomLoadBalancerConfig.class)
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

6.Nacos权重负载均衡器

1.新建Nacos负载均衡器

SpringCloud LoadBalancer,在这里插入图片描述,第4张

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import com.alibaba.nacos.client.env.NacosClientProperties;
import jakarta.annotation.Resource;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
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.core.env.Environment;
@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerConfig.class)
public class NacosLoadBalancerConfig {
    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;
    @Bean
    ReactorLoadBalancer nacosLoadBalancer(Environment environment,
             LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new NacosLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name,nacosDiscoveryProperties);
    }
}

2.设置负载均衡器

和上面一样,只不过configuration /defaultConfiguration 后面变成NacosLoadBalancerConfig.class,这个Nacos的负载均衡器,局部的就没问题,可以自己在nacos里面调整权重自己测,官方bug

7.缓存

SpringCloud LoadBalancer在获取实例的时候有两种选择

1.及时获取:每次从注册中心得到最新健康的实例,效果好,开销大

2.缓存服务列表:每次得到服务列表之后,缓存一段时间,这样既能保证性能,同时也能兼容一定的及时性

而SpringCloud LoadBalancer中默认开启了缓存服务列表的功能

SpringCloud LoadBalancer默认缓存的重要特性有两项:

1.缓存的过期时间为35秒

2.缓存保存个数为256个

设置方式如下

server:
  port: 8080
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        register-enabled: false # 当前服务不注册到nacos里面
    loadbalancer:
      cache:
        enabled: false # 关闭LoadBalancer缓存
        ttl: 35s
        capacity: 1024 #重启就没有了,因为是内存级别的

PS:建议开启缓存,因为效率高

8.执行原理

OpenFeign底层是通过HTTP客户端对象RestTemplate实现接口请求的,而负载均衡器的作用只是在请求客户端发送之前,得到一个服务器的地址给RestTemplate对象。

它可以执行:

1.流量分发:当用户或客户端发起请求时,请求首先到达负载均衡器。负载均衡器根据预定义的规则(比如轮询、最少连接数、最快响应时间等)决定将请求发送到哪个服务器。

2.健康检查:负载均衡器定期检查所有服务器的健康状态。如果某个服务器出现问题(比如宕机或响应过慢),负载均衡器会将其从流量分配中移除,直到该服务器恢复正常。

3.提高可用性:通过分散流量到多个服务器,负载均衡器减少了任何单点故障的可能性,并确保高可用性。

4.弹性扩展:根据流量的增加,可以向负载均衡器后面添加更多的服务器来处理增加的负载。

9.RestTemplate 和@RequestMapping 区别

RestTemplate 主要用于在你的应用程序中作为客户端发送请求到其他服务。

@RequestMapping 主要用于在你的 Spring MVC 应用程序中处理来自客户端的请求。

两者的主要区别在于 RestTemplate 是用于发出请求的,而 @RequestMapping 是用于接收和处理请求的。

10.Rest服务

REST服务(Representational State Transfer,表现层状态转移)指的是遵循REST原则和约束的Web服务。REST是一种软件架构风格,它定义了一套规则和原则,用于设计网络应用程序中的分布式系统。REST服务通常使用HTTP协议作为通信手段,并广泛应用于构建网络服务(如API)。

REST服务的主要特点包括:

1.无状态(Stateless):每个请求从客户端到服务器必须包含理解和处理请求所需的所有信息,不依赖于服务器的上下文或会话状态。

2.统一接口(Uniform Interface):REST定义了一组操作原则,使不同的系统可以通过统一的接口交互。这包括使用标准的HTTP方法(如GET, POST, PUT, DELETE等)。

3.可寻址资源(Addressable Resources):在REST架构中,所有的东西都被认为是资源,并且每个资源都有一个唯一的标识符,通常是URI。

4.表示(Representation):资源可以有一个或多个表示形式,例如JSON, XML, HTML等。客户端和服务器通过这些表示形式交换资源状态。

5.客户端-服务器(Client-Server):REST应用遵循客户端-服务器架构。客户端负责用户界面和用户状态,而服务器负责存储数据和资源状态。

6.可缓存(Cacheable):REST服务的响应应该被明确标记为可缓存或不可缓存,以提高网络效率。

让我用更简单的话来解释一下什么是REST服务。

想象一下,你正在使用一个手机应用来查看天气。当你打开这个应用,它会向某个服务器发送一个请求,比如“请告诉我北京今天的天气”。这个请求通过互联网发送,服务器接收到后,就会查找北京今天的天气信息,并把这个信息以一种易于理解的格式(比如JSON)发送回你的手机应用。然后,你的应用就会展示这些天气信息。

在这个过程中,你的手机应用和天气信息服务器之间就是通过REST服务进行交互的。这里的关键点是:

1.请求和响应:你的应用发送一个请求,服务器回应这个请求。

2.无状态:每次请求都是独立的,服务器不需要记住之前的请求。每次请求都包含了服务器需要的全部信息。

3.简单的通信方式:这些请求通常通过HTTP(就是你在网址栏看到的http://那部分)完成,使用标准的方法,如GET(获取信息)、POST(发送新信息)、PUT(更新信息)和DELETE(删除信息)。

4.资源的标识:在REST服务中,每个可以获取的信息(比如天气信息)被视为一个资源,这些资源通过URI(统一资源标识符,类似网址)来识别。

所以,简单来说,REST服务就是一种规则,它定义了应用程序如何通过网络(比如互联网)发送和接收数据的方法。

REST服务由于其简洁性、易用性和可扩展性,在现代Web应用和微服务架构中非常受欢迎。