引言
本篇博客简单介绍微服务负载均衡的概念,并通过 IDEA 多端口启动应用的方式,模拟多个应用实例,使用自定义和 Ribbon 两种方式实现基本的负载均衡策略。
微服务代码以《Spring Cloud Alibaba——Nacos实现服务治理》为基础。
一、什么是负载均衡
负载指的是系统接收请求的压力,通常来讲,单体应用如果接收的请求量过多,会对应用本身造成一定的并发困扰,导致逻辑出错,甚至是服务瘫痪。
为了解决单个应用访问量过大的情况,人们很自然的想到将一个单体应用克隆多份,来分摊请求量,均衡负载。
负载均衡就是将负载(工作任务、访问量)进行分摊到多个操作单元(服务器、组件)上执行的一套技术。
根据负载均衡发生的位置不同,一般分为:服务端负载均衡、客户端负载均衡。
1、服务端负载均衡指的是分摊工作发生在服务提供者一方,比如常见的 Nginx 。
2、客户端负载均衡则恰好相反,它指的是分摊工作发生在服务请求的一方,即在发送请求之前就已经选好了由具体的哪一个实例处理请求。如下图所示:
一般在微服务中,都是使用客户端负载均衡。
二、IDEA 中模拟多个微服务实例
使用 idea 可以轻松的为一个 spring boot 服务创建多个微服务实例。以《Spring Cloud Alibaba——Nacos实现服务治理》的代码用例为例,这里简单回顾一下 Demo 用例。
我们创建了一个电商系统,有三个微服务:shop-user 用户微服务、shop-product 商品微服务、shop-order 订单微服务,我们使用 Nacos 实现了服务的注册发现,并实现了完整的用户下单——>查询商品——>返回订单的微服务调用逻辑,如下图所示:
但上述案例只涉及到了一个订单微服务实例对应另一个商品微服务实例,并没有任何负载均衡的效果,为了演示负载均衡,我们可以通过 idea 将shop-product 微服务启动多个实例。
方法是,在启动项中添加多个:
配置好第二个商品微服务实例之后,我们启动 ProductApplication 和 ProductApplication2,可以在 Nacos 中看到注册的商品服务实例有 2 个(关于Nacos 的相关知识参考《Spring Cloud Alibaba——Nacos实现服务治理》):
三、自定义负载均衡
最简单的负载均衡机制就是通过随机数,根据服务提供者(商品服务)的实例数量,来随机生成服务序号,从而确定访问的实例。
我们在订单微服务中加入随机数代码:
以下是完整代码:
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate OrderService orderService;/**** 下单* @param pid* @return*/@GetMapping("/prod/{pid}")public Order order(@PathVariable("pid") Integer pid) {log.info("接收到{}号商品的下单请求,准备调用商品微服务", pid);// 获取服务实例列表List<ServiceInstance> serviceList = discoveryClient.getInstances("service-product");// 生成随机下标 0 1int index = new Random().nextInt(serviceList.size());// 获取实例对象ServiceInstance productService = serviceList.get(index);// 调用商品微服务,查询商品信息Product prod = restTemplate.getForObject("http://" + productService.getHost() + ":" + productService.getPort() + "/product/" + pid, Product.class);log.info("查询到{}号商品信息,内容是:{}", pid, JSON.toJSONString(prod));// 下单(即创建订单并保存)Order order = new Order();order.setUid(1);order.setUsername("测试用户");order.setPid(pid);order.setPname(prod.getPname());order.setPprice(prod.getPprice());order.setNumber(1);// 订单入库orderService.createOrder(order);log.info("创建订单成功,订单信息为:{}", JSON.toJSONString(order));return order;}
}
启动 OrderApplication ,并调用下单接口,观察每次请求时,商品微服务后台日志的打印情况:
总共请求了四次,商品实例1调用了3次,商品实例2调用了1次,随机数负载均衡成功。
四、Ribbon 实现负载均衡
Ribbon 是 Spring Cloud 的一个组件,它可以让我们使用一个注解就能轻松搞定负载均衡。Ribbon 的默认负载均衡策略是轮询。
整合方法只需两步:
1、在 RestTemplate 注入的时候,添加 @LoadBalanced 注解:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {return new RestTemplate();
}
2、修改服务调用的方法,以服务名称直接代替 ip 和 端口号:
@GetMapping("/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {log.info("接收到{}号商品的下单请求,准备调用商品微服务", pid);// 调用商品微服务,查询商品信息Product prod = restTemplate.getForObject("http://service-product/product/" + pid, Product.class);log.info("查询到{}号商品信息,内容是:{}", pid, JSON.toJSONString(prod));...return ...;
}
(演示效果略)
Ribbon 的常用负载均衡策略有三个:
RoundRobinRule | 轮询选择 service instance | 轮询 index,选择索引对应的服务实例 |
RandomRule | 随机选择一个 instance | 在 index 上随机,选择对应位置的服务实例 |
BestAvailableRule | 选择一个最小的并发请求的 instance | 考察每个实例,如果实例被 tripped 了,则忽略。再选择其中 ActiveRequestsCount最小的实例 |
修改 Ribbon 的负载均衡策略非常简单,只需要在配置文件中指定即可:
# 调用的服务名称
service-product:ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
演示效果同第三节。
总结
项目的代码以《Spring Cloud Alibaba——Nacos实现服务治理》基础,可能缺少一些中间环境,建议结合阅读。
负载均衡的作用是分摊流量,避免某一个服务因为请求压力而瘫痪。
负载均衡的模式一般有两种,客户端负载均衡和服务端负载均衡。一般在微服务调用中,都是使用客户端负载均衡。
Ribbon是实现负载均衡的重要组件,它的负载均衡策略主要有三个:轮询(默认)、随机、最小并发。