SpringCloud服务拆分:Nacos服务注册中心 + LoadBalancer服务负载均衡使用
SpringCloud中Nacos服务注册中心 + LoadBalancer服务负载均衡使用
- 前言
- Nacos
- 工作流程
- nacos安装
- docker安装
- window安装
- 运行nacos
- 微服务集成nacos
- 高级特性
- 1.服务集群
- 配置方法
- 效果图
- 模拟服务实例宕机
- 2.权重配置
- 3.环境隔离
- 如何启动集群节点
- 本地启动多个节点方法
- LoadBalancer
- 集成LoadBalancer
- LoadBalancer流程
- 源码跟踪
- 自定义负载均衡算法
- 使用自定义负载均衡算法
- 结语
😀大家好!我是向阳🌞,一个想成为优秀全栈开发工程师的有志青年!
📔今天来说一说SpringCloud中Nacos服务注册中心 + LoadBalancer服务负载均衡使用。
前言
本篇文章主要是使用Nacos来注册服务实例,使用Nacos来管理这些服务实例,然后使用LoadBalancer让服务消费方负载均衡调用服务提供方。
这里有一些代码准备,Contorller的代码我就不贴了,贴一个order服务远程调用user服务,获取订单对应的用户信息。
这里使用的是RestTemplate来进行调用远程服务,后续会用OpenFeign来进行替换优化。
@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;/*** 查询订单(携带用户信息)** @param orderId* @return*/@Overridepublic Order findOrderByOrderId(Long orderId) {Order order = orderMapper.findOrderByOrderId(orderId);User user = restTemplate.getForObject("http://ssgw-cloud-user/api/user/findUserByUserId/" + order.getUserId(),User.class);order.setUser(user);return order;}
}
Nacos
官方文档地址:Nacos文档地址
Nacos有多个特性,这里我们主要介绍的是他的服务发现和服务健康监测这个特性,他还有个我常用的特性,那就是动态配置服务,以后可能会说到。
我们把服务都注册到Nacos里面,Nacos会对服务进行实时的健康检查,阻止向不健康的主机或服务实例发送请求。
工作流程
通过注册中心可以对服务提供方和服务消费方进行解耦。具体的工作模式如下图所示:
工作流程说明:
- 服务提供方在启动的时候,会向注册中心注册自己服务的详情信息 (ip、端口号等) 。在注册中心中会维护一张服务清单,保存这些注册信息,注册中心需要以心跳的方式(30s,服务向注册中心发送心跳)去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。
- 服务消费方向服务注册中心咨询服务,并获取所有服务的实例清单,然后,按照指定的负载均衡算法从服务清单中选择一个服务实例进行访问。
- 每当服务提供方有节点不可用后,服务消费方会重新缓存可用的提供方信息(ip、端口号等)。
nacos安装
docker安装
直接在linux虚拟机中用docker进行以下命令即可。
# 拉取镜像
docker pull nacos/nacos-server:v2.2.2# 创建容器
docker run --name nacos -e MODE=standalone -p 8848:8848 -p 9848:9848 -d nacos/nacos-server:v2.2.2# nacos2.x的版本新增了一个客户端与服务端的gRpc的通讯端口号9848
window安装
不同的版本有不同的注意事项,可以去官方文档查阅,或者具体的细节可以查看其他博客,这里不详细赘述。
二进制包下载地址
运行nacos
docker的运行在上面已经提到了,docker run xxx就已经运行了。
Window版本的docker配置文件默认是单机模式启动,所以我们运行nacos要加上 standalone 这个命令。
startup.cmd -m standalone
运行成功的页面,nacos的默认端口是8848,我们访问:http://localhost:8848/nacos 即可访问到图形化界面,默认账号密码都是 nacos。
微服务集成nacos
在pom.xml中加入以下依赖:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在application.yml中加入以下配置:
spring:# 配置nacos注册中心的地址cloud:nacos:discovery:server-addr: localhost:8848 # 如果在虚拟机安装,则改成你对应的ip地址application: name: spzx-cloud-user # 每一个服务注册到nacos注册中心都需要提供一个服务名称,order微服务注册的时候需要更改微服务名称
加入对应的配置文件后,在nacos图形化界面就可以看到以下信息,这里我已经启动了3个user服务,所以 ssgw-cloud-user 的实例数为3。
高级特性
1.服务集群
在实际生产环境中,为了保证每一个服务的高可用,那么,此时就需要去构建服务集群,但是,并不是说把所有的服务都部署在一个机房里。而是将多个服务分散的部署到不同的机房中,每一个机房的服务可以看做成是一个集群。
微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群。例如:上海机房内的order微服务应该优先访问同机房的user微服务。
配置方法
配置yml文件:
spring:cloud:nacos:discovery:cluster-name: SH # 配置服务所属集群
集成nacos的负载均衡算法,也是在yml文件中配置,配置了之后,就会按照服务集群来进行访问对应的服务实例,访问默认是随机访问。
spring:cloud:loadbalancer:nacos:enabled: true
一个服务不同实例配置不同的集群方法和下面如何启动集群节点方法一样,这里贴个图。
我们这里用户服务,两个配置BJ,两个配置SH,订单服务配置了SH,根据上面的讲述,如果我们访问订单服务的接口,我们应该优先访问的是两个SH的用户服务。
配置了服务集群后,nacos的服务实例有所变化,如下面两张图。
效果图
我们访问订单的接口,查看用户服务的控制台,我们可以看到只有配置了SH的两个用户服务控制台信息有打印SQL语句,说明被只有这两个服务被调用了。
其余三个我就不贴图了…
模拟服务实例宕机
我们可以在nacos的图形化界面中下线按钮来下线对应的服务实例,这样就模拟了服务宕机场景,此时我们下线两个SH的用户服务实例,我们访问订单接口,此时访问就会访问两个BJ的服务实例,如下图所示。
此时只会调用在配置在BJ的两个服务实例中。
其余三个我就不贴图了…
2.权重配置
我们可以对不同的服务进行权重配置,比如性能好的服务器权重就可以大一点,性能差的服务器泉州就可以小一点。
这个我们可以直接在nacos图形化界面进行配置,点击编辑后,即可在弹出的弹窗进行权重配置。
我们还可以在yml文件中进行配置:
spring:cloud:nacos:discovery:weight: 0.1
3.环境隔离
在实际的开发过程中,可能会存在很多个软件环境:开发环境、测试环境、生产环境。
nacos也是支持多环境隔离配置的,在nacos中是通过namespace来实现多环境的隔离。
完整的服务注册数据存储结构如下所示:
namespace + group 才可以确定具体的微服务实例。默认情况下,所有service、group都在同一个namespace,名为public。
在nacos的图形化界面就可以进行namespace的添加。
给微服务添加名称空间的配置,来指定该微服务所属环境,这里修改order的application.yml文件,改为dev:
spring:# 配置nacos注册中心的地址cloud:nacos:discovery:namespace: dev # 配置服务实例所属名称空间
这个时候order和其他的user实例已经不在同一个namespace命名空间下了,这个时候我们再次访问接口就会报错,因为访问不到了。
控制台报错找不到对应的实例:
我们也可以分配组,在yml配置文件中进行配置:
spring:# 配置nacos注册中心的地址cloud:nacos:discovery:namespace: dev # 配置服务实例所属名称空间group: ORDER_GROUP
如何启动集群节点
我们启动多个user节点,让order服务负载调用user节点。
本地启动多个节点方法
我们对原本的user服务右键点击,选择Copy Configuration来拷贝配置,进而修改新的配置,我们这里修改端口,防止端口冲突启动不起来。
服务名称可改可不改使用默认的也可以,但是一定要覆盖配置文件中的端口号。
选择Override configuration properties后,添加以下配置来覆盖原有的配置,约定大于配置,走的就是我们这里配置的端口。
配置完毕后,启动就是下图所示的结果。
LoadBalancer
集成LoadBalancer
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
Spring Cloud LoadBalancer 是Spring Cloud中负责客户端负载均衡的模块,其主要原理是通过选择合适的服务实例来实现负载均衡。
客户端负载均衡:就是负载均衡算法由客户端提供,默认是轮询负载均衡,就是每个服务被依次调用。
我们多此访问我们项目的接口,可以从控制台中发现,三个用户服务的控制台中各有一条SQL查询信息,说明每个都被调用了一次。
http://localhost:10200/api/order/findOrderByOrderId/101
LoadBalancer流程
Spring Cloud LoadBalancer的底层采用了一个拦截器【LoadBalancerInterceptor】,拦截了RestTemplate发出的请求,对地址做了修改。
执行流程说明:
-
通过 LoadBalancerInterceptor 请求拦截器拦截我们的 RestTemplate请求:http://ssgw-cloud-user/api/user/findUserByUserId/1
-
获取请求的url,然后,从请求的url中获取服务提供方的主机名称(ssgw-cloud-user)
-
然后,调用LoadBalancerClient中的execute方法,将服务提供方的名称传递过去
-
在LoadBalancerClient的choose方法中通过ReactiveLoadBalancer.Factory从Nacos注册中心中获取服务列表以及负载均衡算法实例对象
-
通过ReactiveLoadBalancer从服务列表中选择一个服务实例地址,然后,发起远程调用
源码跟踪
首先我们进入到 LoadBalancerInterceptor 的 intercept 方法,可以看到我们调用远程服务的uri和服务名称serviceName。
紧接着进入到 LoadBalancerClient 的 execute 方法,这个方法主要来处理服务id和用户请求,我们主要看他的 choose 方法。
我们从choose方法可以看出来,我们的负载均衡器是我们在配置文件中配置的 NacosLoadBalancer 负载均衡器。
紧接着调用负载均衡器的 choose 方法,从服务列表中选择一个服务实例对象。
如果我们注释掉配置文件中的集成nacos的负载均衡算法,我们可以得到负载均衡器变成了默认的RR负载均衡器也就是轮询调度负载均衡器(RoundRobinLoadBalancer)。
自定义负载均衡算法
详细注释在代码中都有,这里不多赘述。
public class CustomLoadBalancerConfiguration {/*** @param environment: 用于获取环境属性配置,其中LoadBalancerClientFactory.PROPERTY_NAME表示该负载均衡器要应用的服务名称。* @param loadBalancerClientFactory: 是Spring Cloud中用于创建负载均衡器的工厂类,通过getLazyProvider方法获取ServiceInstanceListSupplier对象,以提供可用的服务列表。* ServiceInstanceListSupplier:用于提供ServiceInstance列表的接口,可以从DiscoveryClient或者其他注册中心中获取可用的服务实例列表。* @return*/@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}
使用自定义负载均衡算法
这里使用的是 RestTemplate 来远程调用其他的服务接口(后期会换成 OpenFeign),所以我们在 RestTemplateConfiguration 类上面加上 @LoadBalancerClients 注解来指定我们要调用哪个服务实例,指定使用我们自定义的负载均衡算法来进行调用。
@Configuration
@LoadBalancerClients(value = {@LoadBalancerClient(name = "ssgw-cloud-user", configuration = CustomLoadBalancerConfiguration.class)
})
public class RestTemplateConfiguration {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
结语
至此我们就完成了我们的主题《SpringCloud服务拆分:Nacos服务注册中心 + LoadBalancer服务负载均衡使用》,更多的细节和使用方法还等着我们去探索,加油吧👍!
——👦[作者]:向阳256
——⏳[更新]:2025.5.8
——🥰本人技术有限,如果有不对指正需要更改或者有更好的方法,欢迎到评论区留言。