Spring Cloud——Spring Cloud LoadBalancer
一、负载均衡
1.1 问题回顾
在上一篇文章中说到,在进行远程调用时,下面的这种写法会出现一些问题:
由于每一个微服务都可能是一个集群,这会导致订单服务的所有请求都发送到同一台服务器,而其它服务器收不到请求 ,下面我们来模拟一下这种情况:
1> 再启动2个product-service实列
首先,点击services
选中要启动的服务,点击Copy Configuration...
选择Modify options ->Add VM options
添加 VM options :-Dserver.port=9091
Service窗口就会多出来一个启动配置,右键启动服务
然后进行相同的操作,再启动一个服务
2> 运行所有服务,访问接口
观察Eureka,可以看到实例数:
访问12次 http://127.0.0.1:8080/order/1,观察程序控制台:
可以看到,所有的请求都被端口号9091的服务接收 ,而其它服务没有接收到请求
1.2 什么是负载均衡
将用户请求智能分发到多个相同服务的实例上,避免单点压力。核心目标:提升吞吐量、增强容错性、实现水平扩展
1.3 负载均衡的种类
1.3.1 服务端负载均衡
即在服务端进行负载均衡算法分配
比较有名的服务端负载均衡器是Nginx。请求先到达Nginx负载均衡器,然后通过负载均衡算法,在多个服务器之间选择⼀个进行访问。
1.3.2 客户端负载均衡
客户端进行负载均衡算法分配
比如Spring Cloud提供的负载均衡器Spring Cloud LoadBalancer就是一个客户端负载均衡器
二、Spring Cloud LoadBalancer
现在我们来学习使用Spring Cloud LoadBalancer来解决前面请求分配不合理的问题
2.1 使用方法
使用Spring Cloud LoadBalancer,需要:
(1)在声明RestTemplate对象的方法上添加注解@LoadBalanced;
(2)修改远程调用代码(将url中的IP、端口号用服务名称代替)
代码如下:
@Configuration
public class BeanConfig {@Bean@LoadBalanced//表示启用spring cloud loadbalancer组件public RestTemplate restTemplate(){return new RestTemplate();}
}
public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);//int index = count.getAndIncrement() % instances.size();//String uri = instances.get(index).getUri().toString();//String url = uri + "/product/" + orderInfo.getProductId();String url = "http://product-service/product/" + orderInfo.getProductId();log.info("远程调用url:" + url);ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
接下来,重启订单服务,再次访问12次 http://127.0.0.1:8080/order/1:
可以看到,3个服务都接收到4个请求,这样请求就被合理分配到不同的服务器了
2.2 负载均衡策略
Spring Cloud LoadBalancer 支持两种负载均衡策略:
1. 轮询(Round Robin):轮询策略是指服务器轮流处理用户的请求。这是一种实现最简单,也最常用的策略。生活中也有类似的场景,比如学校轮流值日,或者轮流打扫卫生。
2. 随机选择(Random):随机选择策略是指随机选择一个后端服务器来处理新的请求。
Spring Cloud LoadBalancer 默认使用的就是轮询策略,如果需要更改,可以自定义负载均衡策略
2.3 自定义负载均衡策略
1. 定义随机算法对象,通过@Bean将其加载到Spring容器中,这里的代码时直接从Spring官网Spring Cloud LoadBalancer :: Spring Cloud Commons中获取的:
public class CustomLoadBalancerConfiguration {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}
2. 使用 @LoadBalancerClient 或者 @LoadBalancerClients 注解
@Configuration
@LoadBalancerClient(name = "product-service",
configuration = CustomLoadBalancerConfiguration.class)//参数name表示对哪个服务生效,configuration表示使用哪种负载均衡策略
public class BeanConfig {@Bean@LoadBalanced//表示启用spring cloud loadbalancer组件public RestTemplate restTemplate(){return new RestTemplate();}
}
配置好后,重启订单服务,多次访问接口就会发现请求被不均匀分配到不同的服务器上了