多机部署, 负载均衡-LoadBalance

目录

1.负载均衡介绍

1.1问题描述

1.2什么是负载均衡

1.3负载均衡的一些实现

服务端负载均衡

客户端负载均衡

[2.Spring Cloud LoadBalancer](#2.Spring Cloud LoadBalancer)

2.1快速上手实现负载均衡

2.2负载均衡策略

自定义负载均衡策略

3.服务部署(Linux)

3.1服务构建打包

3.2启动服务


承接上文服务注册/服务发现-Eureka

1.负载均衡介绍

1.1问题描述

观察上个章节远程调用的代码

java 复制代码
 List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
 //服务可能有多个, 获取第⼀个
 EurekaServiceInstance instance = (EurekaServiceInstance) instances.get(0);

1.根据应用名称获取了服务实例列表

2.从列表中选择了一个服务实例

**思考:**如果一个服务对应多个实例呢?流量是否可以合理的分配到多个实例

现象观察:

我们再启动2个product-service实例

选中要启动的服务,右键选择Copy Configuration

在弹出的框中选择 Configuration -> VM options

添加VM options: -Dserver.port=9091

9091为服务启动的端口号,根据自己的情况进行修改

java 复制代码
 11:46:05.684+08:00 INFO 23128 --- [nio-8080-exec-1] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 11:46:06.435+08:00 INFO 23128 --- [nio-8080-exec-2] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 11:46:07.081+08:00 INFO 23128 --- [nio-8080-exec-3] 
com.bite.order.service.OrderService : LUCF:product-service:9090

先启动Eureka后启动所有实例

观察Eureka,可以看到product-service下有三个实例

访问:http://127.0.0.1:8080/order/1

访问结果:

java 复制代码
 11:46:05.684+08:00 INFO 23128 --- [nio-8080-exec-1] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 11:46:06.435+08:00 INFO 23128 --- [nio-8080-exec-2] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 11:46:07.081+08:00 INFO 23128 --- [nio-8080-exec-3] 
com.bite.order.service.OrderService : LUCF:product-service:9090

通过日志可以观察到,请求多次访问,都是同一台机器。

这肯定不是我们想要的结果,启动多个实例,是希望可以分担其他机器的负荷,那么如何实现呢?

解决方案:

我们可以对上述代码进行简单修改:

java 复制代码
import com.example.orderservice.mapper.OrderMapper;
import com.example.orderservice.model.OrderInfo;
import com.example.orderservice.model.ProductInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;


    private static AtomicInteger atomicInteger = new AtomicInteger(1);
        public OrderInfo selectOrderById(Integer orderId){
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
//      String url = "http://127.0.0.1:9090/product/"+orderInfo.getProductId();
        //从Eureka中获取服务列表
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        String uri = instances.get(atomicInteger.getAndIncrement() % instances.size()).getUri().toString();

        String url = uri+"/product/"+orderInfo.getProductId();
        log.info("远程调用url:{}", url);
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

观察日志:

java 复制代码
 12:02:13.245+08:00 INFO 1800 --- [nio-8080-exec-1] 
com.bite.order.service.OrderService : LUCF:product-service:9091
 12:02:15.723+08:00 INFO 1800 --- [nio-8080-exec-2] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 12:02:16.534+08:00 INFO 1800 --- [nio-8080-exec-3] 
com.bite.order.service.OrderService : LUCF:product-service:9092
 12:02:16.864+08:00 INFO 1800 --- [nio-8080-exec-4] 
com.bite.order.service.OrderService : LUCF:product-service:9091
 12:02:17.078+08:00 INFO 1800 --- [nio-8080-exec-5] 
com.bite.order.service.OrderService : LUCF:product-service:9090
 12:02:17.260+08:00 INFO 1800 --- [nio-8080-exec-6] 
com.bite.order.service.OrderService : LUCF:product-service:9092
 12:02:17.431+08:00 INFO 1800 --- [nio-8080-exec-7] 
com.bite.order.service.OrderService : LUCF:product-service:9091

通过日志可以看到,请求被均衡的分配在不同的实例上,这就是负载均衡

1.2什么是负载均衡

负载均衡(Load Balance,简称LB),是高并发,高可用系统必不可少的关键组件.

当服务流量增大时,通常会采用增加机器的方式进行扩容,负载均衡就是用来在多个机器或者其他资源中,按照一定的规则合理分配负载.

一个团队最开始只有一个人,后来随着工作量的增加,公司又招聘了几个人.负载均衡就是:如何把工作量均衡的分配到这几个人身上,以提高整个团队的效率

1.3负载均衡的一些实现

上面的例子中,我们只是简单的对实例进行了轮询,但真实的业务场景会更加复杂.比如根据机器的配置进行负载分配,配置高的分配的流量高,配置低的分配流量低等. 类似企业员工:能力强的员工可以多承担一些工作。

服务多机部署时,开发人员都需要考虑负载均衡的实现,所以也出现了一些负载均衡器,来帮助我们实现负载均衡.

负载均衡分为服务端负载均衡客户端负载均衡.

服务端负载均衡

在服务端进行负载均衡的算法分配

比较有名的服务端负载均衡器是Nginx.

请求先到达Nginx负载均衡器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问.

客户端负载均衡

在客户端进行负载均衡的算法分配.

把负载均衡的功能以库的方式集成到客户端,而不再是由一台指定的负载均衡设备集中提供.
比如SpringCloud的Ribbon,请求发送到客户端,客户端从注册中心(比如Eureka)获取服务列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问.
Ribbon是SpringCloud早期的默认实现,由于不维护了,所以最新版本的Spring Cloud负载均衡集成的是SpringCloud LoadBalancer(SpringCloud官方维护)


客户端负载均衡和服务端负载均衡最大的区别在于服务清单所存储的位置

2.Spring Cloud LoadBalancer

2.1快速上手实现负载均衡

1.给RestTemplate这个Bean添加@LoadBalanced注解

java 复制代码
@Configuration
public class BeanConfig {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

2.修改IP端口号为服务名称

java 复制代码
    public OrderInfo selectOrderById(Integer orderId) {
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        //String url = "http://127.0.0.1:9090/product/"+ orderInfo.getProductId();
        String url = "http://product-service/product/" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;

    }

3.启动多个product-service实例


4.测试负载均衡
连续多次发起请求: http://127.0.0.1:8080/order/1
观察product-service的日志, 会发现请求被分配到这3个实例上了

2.2负载均衡策略

负载均衡策略是一种思想,无论是哪种负载均衡器,它们的负载均衡策略都是相似的.

Spring Cloud LoadBalancer仅支持两种负载均衡策略:轮询策略和随机策略

  • **轮询(Round Robin):**轮询策略是指服务器轮流处理用户的请求.这是一种实现最简单,也最常用的 策略.生活中也有类似的场景,比如学校轮流值日,或者轮流打扫卫生.
  • 随机选择(Random) :随机选择策略是指随机选择一个后端服务器来处理新的请求.

自定义负载均衡策略

Spring Cloud LoadBalancer默认负载均衡策略是轮询策略,实现是RoundRobinLoadBalancer,如果服务的消费者如果想采用随机的负载均衡策略,也非常简单.
参考官网:Spring Cloud LoadBalancer :: Spring Cloud Commons
1.定义随机算法对象,通过@Bean将其加载到Spring容器中
此处使⽤Spring Cloud LoadBalancer提供的 RandomLoadBalancer

java 复制代码
    public class CustomLoadBalancerConfiguration {
        @Bean
        ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                                LoadBalancerClientFactory loadBalancerClientFactory) {
            String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
            return new RandomLoadBalancer(loadBalancerClientFactory
                    .getLazyProvider(name, ServiceInstanceListSupplier.class),
                    name);
        }
    }

**注意:**该类需要满足

  1. 不用@Configuration注释
  2. 在组件扫描范围内
    2.使用@LoadBalancerClient或者@LoadBalancerClients注解
    在RestTemplate配置类上方,使用@LoadBalancerClient或@LoadBalancerClients注解,可以对不同的服务提供方配置不同的客户端负载均衡算法策略.
    由于咱们项目中只有一个服务提供者,所以使用@LoadBalancerClient
java 复制代码
@LoadBalancerClient(name = "product-service",configuration = CustomLoadBalancerConfiguration.class)
@Configuration
public class BeanConfig {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

@LoadBalancerClient注解说明:

  • name:该负载均衡策略对哪个服务生效(服务提供方)
  • configuration:该负载均衡策略用哪个负载均衡策略实现.

3.服务部署(Linux)

3.1服务构建打包

采用Maven打包,需要对3个服务分别打包:

eureka-server,order-service,product-service

1.打包方式和SpringBoot项目一致,依次对三个项目打包即可.

3.2启动服务

bash 复制代码
 #后台启动eureka-server, 并设置输出⽇志到logs/eureka.log
 nohup java -jar eureka-server.jar >logs/eureka.log &

 #后台启动order-service, 并设置输出⽇志到logs/order.log
 nohup java -jar order-service.jar >logs/order.log &

 #后台启动product-service, 并设置输出⽇志到logs/order.log
 nohup java -jar product-service.jar >logs/product-9090.log &

再多启动两台product-service实例

bash 复制代码
 #启动实例, 指定端⼝号为9091
 nohup java -jar product-service.jar --server.port=9091 >logs/product-9091.log &

 #启动实例, 指定端⼝号为9092
 nohup java -jar product-service.jar --server.port=9092 >logs/product-9092.log &
相关推荐
李少兄44 分钟前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
宁zz1 小时前
乌班图安装jenkins
运维·jenkins
此木|西贝1 小时前
【设计模式】原型模式
java·设计模式·原型模式
可乐加.糖1 小时前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
s9123601011 小时前
rust 同时处理多个异步任务
java·数据库·rust
9号达人1 小时前
java9新特性详解与实践
java·后端·面试
大丈夫立于天地间1 小时前
ISIS协议中的数据库同步
运维·网络·信息与通信
cg50171 小时前
Spring Boot 的配置文件
java·linux·spring boot
啊喜拔牙1 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala
rainFFrain2 小时前
单例模式与线程安全
linux·运维·服务器·vscode·单例模式