SA实战 ·《SpringCloud Alibaba实战》第8章(一)

Pike_Chen
发布于 2022-5-31 16:38
浏览
0收藏

 

大家好,我是冰河~~

在《SpringCloud Alibaba实战》专栏的《SA实战 ·《SpringCloud Alibaba实战》服务治理:实现服务的自动注册与发现》一文中,我们实现了服务的自动注册与发现功能。

 

但是还存在一个很明显的问题,那就是如果用户微服务和商品微服务在服务器上部署多份的话,之前的程序无法实现服务调用的负载均衡功能。本文就带着大家一起实现服务调用的负载均衡功能。

负载均衡
在正式优化程序代码之前,我们先来看看什么是负载均衡。说的直白点,负载均衡就是将原本由一台服务器处理的请求根据一定的规则分担到多台服务器上进行处理。目前,大部分系统都实现了负载均衡的功能。

负载均衡根据发生的位置,可以分为服务端负载均衡和客户端负载均衡。

服务端负载均衡
服务端负载均衡指的是在服务端处理负载均衡的逻辑,如下图所示。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

负载均衡在服务端进行处理,当客户端访问服务端的服务A时,首先访问到服务端的负载均衡器,由服务端的负载均衡器将客户端的请求均匀的分发到服务端部署的两个服务A上。

客户端负载均衡
客户端负载均衡指的是在客户端处理负载均衡的逻辑,如下图所示。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

负载均衡逻辑在客户端一侧,客户端应用调用服务端的应用A时,在向服务端发送请求时,就已经经过负载均衡的逻辑处理,并直接向服务端的某个服务发送请求。

启动多服务
为了实现服务调用的负载均衡功能,我们在本地的IDEA环境中分别启动两个用户微服务进程和两个商品微服务进程。

启动多个用户微服务
这里,我们在IDEA开发环境中启动多个用户微服务,其实也就是在同一台机器(服务器)上启动多个用户微服务。启动用户微服务时,默认监听的端口为8060,主要由如下配置决定。

server:
  port: 8060

在同一台机器(服务器)上启动多个用户微服务时,只需要保证启动的多个用户微服务监听的端口号不同即可。

IDEA中可以通过配置不同的端口号来启动多个相同的服务,如下所示,再配置一个用户微服务,使其端口号为8061。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

按照上图所示,在Name一栏输入UserStarter2,点击Main class一栏后面的弹出框按钮,选择用户微服务的启动类io.binghe.shop.UserStarter,最重要的就是在VM options一栏后面添加JVM启动参数-Dserver.port=8061,将新添加的用户微服务的监听端口设置为8061。

配置好之后,在IDEA中分别启动端口为8060和8061的两个用户微服务,启动后打开Nacos的服务列表,如下所示。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

可以看到,在服务列表中出现了两个用户微服务的实例,说明两个用户微服务都启动成功了。

启动多个商品微服务
与用户微服务类似,在IDEA中再次配置一个端口号为8071的商品微服务,如下所示。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

接下来,分别启动端口为8070和8071的两个商品微服务,启动后查看Nacos的服务列表,如下所示。

SA实战 ·《SpringCloud Alibaba实战》第8章(一)-鸿蒙开发者社区

 

可以看到,端口为8070和8071的两个商品微服务,也成功启动啦。

实现自定义负载均衡
这里,我们通过修改订单微服务的代码来实现自定义负载均衡,由于在整个项目中,订单微服务作为客户端存在,由订单微服务调用用户微服务和商品微服务,所以,这里采用的是客户端负载均衡的模式。

修改订单微服务代码
此处实现的逻辑在订单微服务的io.binghe.shop.order.service.impl.OrderServiceV3Impl类中,并且在OrderServiceV3Impl类上会标注@Service("orderServiceV3")注解。订单微服务的代码结构如下所示。

├─shop-order
│  │  pom.xml
│  │  shop-order.iml
│  │
│  └─src
│      └─main
│          ├─java
│          │  └─io
│          │      └─binghe
│          │          └─shop
│          │              │  OrderStarter.java
│          │              │
│          │              └─order
│          │                  ├─config
│          │                  │      LoadBalanceConfig.java
│          │                  │
│          │                  ├─controller
│          │                  │      OrderController.java
│          │                  │
│          │                  ├─mapper
│          │                  │      OrderItemMapper.java
│          │                  │      OrderMapper.java
│          │                  │
│          │                  └─service
│          │                      │  OrderService.java
│          │                      │
│          │                      └─impl
│          │                              OrderServiceV1Impl.java
│          │                              OrderServiceV2Impl.java
│          │                              OrderServiceV3Impl.java
│          │
│          └─resources
│              │  application.yml
│              │
│              └─mapper
│                      OrderItemMapper.xml
│                      OrderMapper.xml

首先,在OrderServiceV3Impl类中修改getServiceUrl()方法,使其能够在多个服务地址中随机获取一个服务地址,而不总是获取第一个服务地址。

修改前的代码如下所示。

private String getServiceUrl(String serviceName){
    ServiceInstance serviceInstance = discoveryClient.getInstances(serviceName).get(0);
    return serviceInstance.getHost() + ":" + serviceInstance.getPort();
}

修改后的代码如下所示。

private String getServiceUrl(String serviceName){
    List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
    int index = new Random().nextInt(instances.size());
    ServiceInstance serviceInstance = instances.get(index);
    String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
    log.info("负载均衡后的服务地址为:{}", url);
    return url;
}

在getServiceUrl()方法中,首先通过服务的名称在Nacos中获取到所有的服务实例列表,然后使用随机函数随机生成一个0到服务列表长度减1的整数,而这个随机生成的整数恰好在服务实例列表的下标范围内,然后以这个整数作为下标获取服务列表中的某个服务实例。从而以随机的方式实现了负载均衡,并从获取到的服务实例中获取到服务实例所在服务器的IP地址和端口号,拼接成IP:PORT的形式返回。

接下来,将io.binghe.shop.order.controller.OrderController类中的OrderService修改为注入beanName为orderServiceV3的OrderService对象,如下所示。

@Autowired
@Qualifier(value = "orderServiceV3")
private OrderService orderService;

至此,订单微服务的代码修改完成。

测试负载均衡效果
启动订单微服务,并在浏览器或其他测试工具中多次访问链接http://localhost:8080/order/submit_order?userId=1001&productId=1001&count=1,在订单微服务输出的日志信息中会存在如下所示的日志。

负载均衡后的服务地址为:192.168.0.27:8061
负载均衡后的服务地址为:192.168.0.27:8071
负载均衡后的服务地址为:192.168.0.27:8060
负载均衡后的服务地址为:192.168.0.27:8070
负载均衡后的服务地址为:192.168.0.27:8060
负载均衡后的服务地址为:192.168.0.27:8071
负载均衡后的服务地址为:192.168.0.27:8061
负载均衡后的服务地址为:192.168.0.27:8070

其中,端口为8060和8061的微服务为用户微服务,端口为8070和8071的微服务为商品微服务。初步实现了订单微服务调用用户微服务和商品微服务的负载均衡。

使用Ribbon实现负载均衡
Ribbon是SpringCloud提供的一个能够实现负载均衡的组件,使用Ribbon能够轻松实现微服务之间调用的负载均衡。

修改订单微服务代码
在订单微服务中的io.binghe.shop.order.config.LoadBalanceConfig 类的 restTemplate()方法上添加@LoadBalanced注解,如下所示。

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

 

文章转自公众号:冰河技术

分类
已于2022-5-31 16:38:46修改
收藏
回复
举报
回复
    相关推荐