title: Nacos服务注册和服务发现
tag: 笔记 微服务组件
Nacos服务注册和服务发现
启动了一个Nacos注册中心之后,我们就可以将项目注册到注册中心,这样该服务的接口就给微服务的其它提供服务或者调用其它服务的接口。
主要包括两个部分的内容:
- 服务注册
- 服务发现
我们这里使用一个购物车和商品的服务来作为实例:购物车服务需要调用商品服务的接口
服务注册
我们先将商品模块item-service注册到Nacos注册中心。
大致步骤如下:
- 引入依赖
- 配置Nacos地址
- 重启
添加依赖
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置Nacos
在item-service
的application.yml
中添加nacos地址配置:
spring:
application:
name: item-service # 服务名称
cloud:
nacos:
server-addr: 192.168.12.136:8848
启动服务实例
Nacos还支持一个服务多个实例的情况,我们可以配置两个item-service
的启动项。
然后我们启动两个服务,查看Nacos服务管理:
如此,我们就成功注册了一个服务到Nacos中。
服务发现
服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:
- 引入依赖
- 配置Nacos地址
- 发现并调用服务
引入依赖
服务发现除了要引入nacos依赖以外,由于还需要负载均衡,因此要引入SpringCloud提供的LoadBalancer依赖。
我们在cart-service
中的pom.xml
中添加下面的依赖:
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
可以发现,这里Nacos的依赖于服务注册时一致,这个依赖中同时包含了服务注册和发现的功能。因为任何一个微服务都可以调用别人,也可以被别人调用,即可以是调用者,也可以是提供者。
因此,等一会儿cart-service
启动,同样会注册到Nacos
配置Nacos地址
在cart-service
的application.yml
中添加nacos地址配置:
spring:
cloud:
nacos:
server-addr: 192.168.12.136:8848
发现并调用服务
接下来,服务调用者cart-service
就可以去订阅item-service
服务了。不过item-service有多个实例,而真正发起调用时只需要知道一个实例的地址。
因此,服务调用者必须利用负载均衡的算法,从多个实例中挑选一个去访问。常见的负载均衡算法有:
- 随机
- 轮询
- IP的hash
- 最近最少访问
- …
这里我们可以选择最简单的随机负载均衡。
另外,服务发现需要用到一个工具,DiscoveryClient
,SpringCloud
已经帮我们自动装配,我们可以直接注入使用:
private final RestTemplate restTemplate;
private final DiscoveryClient discoveryClient;
其中RestTemplate
可以通过请求提供服务的地址拿到数据。
下面是通过购物车的id去请求之前注册到Nacos的商品服务拿到对于的商品信息的逻辑:
private void handleCartItems(List<CartVO> vos) {
//干掉之后修改
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2.查询商品
//2.1 根据服务名称获取服务的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
if (CollUtil.isEmpty(instances)){
return;
}
//2.2 手写负载均衡,从实力列表中挑选一个实例
ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
//2.3 利用RestTemplate发起http请求,得到http响应
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(instance.getUri() + "/items?ids={ids}",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<ItemDTO>>() {
},
CollUtils.join(itemIds, ","));
//2.2 解析响应
if (!response.getStatusCode().is2xxSuccessful()){
//查询失败,直接结束
return;
}
List<ItemDTO> items = response.getBody();
}
这里我们通过discoveryClient
来获取商品服务的IP地址并通过restTemplate
发起请求拿到数据完成了一次远程调用。
测试
然后我们可以将两个商品服务和购物车服务一起启动:
然后我们通过PostMan发起请求:
[
{
"id": "7",
"itemId": "100000006163",
"num": 1,
"name": "巴布豆(BOBDOG)柔薄悦动婴儿拉拉裤XXL码80片(15kg以上)",
"spec": "{}",
"price": 67100,
"newPrice": null,
"status": 1,
"stock": 10,
"image": "https://m.360buyimg.com/mobilecms/s720x720_jfs/t23998/350/2363990466/222391/a6e9581d/5b7cba5bN0c18fb4f.jpg!q70.jpg.webp",
"createTime": "2023-05-20T21:07:09"
}
]
“image”: “https://m.360buyimg.com/mobilecms/s720x720_jfs/t23998/350/2363990466/222391/a6e9581d/5b7cba5bN0c18fb4f.jpg!q70.jpg.webp”,
“createTime”: “2023-05-20T21:07:09”
}
]
可以看到我们成功通过远程调用拿到了购物车中的商品信息。