目录
一.概念
服务提供者:服务的被调用方(为其他微服务提供接口的微服务) Server
服务消费者:服务的调用方(调用其他微服务接口的微服务) Client
这两者的界限并不是特别明显,服务提供者也可能在某个场景是服务消费者。
二.应用场景
以微服务互相调用为前提,有服务A和B,假设有一业务A调用B,之后需求更改,服务B的地址需要改变,那该怎么办?
首先想到一个模型来解决这个服务之间调用的问题。在数据库中可以表示为:
id | server_name | ip | port | status |
---|---|---|---|---|
1 | user_center | 192.168.1.1 | 8080 | UP |
2 | aply_center | 192.168.1.2 | 8084 | UP |
在代码中可以通过user_name来获取ip等其他信息,构造url访问其他微服务。
但是这个服务发现有以下问题:
每次调用都需要访问这张表,如果此数据库数据挂了,会导致全部微服务都调用不了。
所以需要由一个服务注册中心,将服务全部注册到一个地方,本地将服务缓存到本地,定时刷新缓存。
这样就可以直接去访问其他微服务,即使服务发现组件崩溃,也可以使用本地缓存区访问,只是缓存不会刷新。
微服务通过向服务发现组件发送心跳(证明自己运行正常)来保证程序运行正常,如果长时间不发送,数据库模拟中会将status标记为down,在服务发现组件中,也会将微服务状态设置为不可用。
三.Nacos(Nacos文档)
1.什么是Nacos
是一个服务发现组件,同时也是一个配置服务器。
他解决了服务A如何找到服务B的问题,管理服务的配置。
每个微服务都需要引入Nacos client,将自己注册到Nacos Server。
2.搭建Nacos
下载Nacos:Nacos下载地址
如何下载兼容版本Nacos:Spring Cloud学习笔记
第三点第一个小点有找到对应版本模块的技巧。
下载好后看连连接:Nacos搭建
### 流程:(我的是Windows)
### 进入bin目录执行命令:cmd startup.cmd -m standalone (端口默认是8848 (珠穆朗玛峰)),不要关闭黑窗口
### 访问 localhost:8848/nacos
### 账号密码都是 nacos
这样本地的搭建就完成了。
3.将应用注册到Nacos
# 加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
#写注解 (没有注解)(早期版本需要在启动类上添加@EnableDiscoryClient注解)
#写配置(这样一个user-center的应用就会被注册到本地的nacos,在nacos界面的服务列表可以找到对应的实例)
spring:
cloud:
nacos:
discovery:
#指定nacos server的地址,这里前面不用加协议(http://),ip或者域名都可以
server-addr: localhost:8848
#下面的配置一个是命名空间,一个是集群名,有其他作用,基础功能不需要配置,所以加了注释,Namespace需要在nacos的控制台先创建,然后获取这个uuid
#namespace: 56aaff56-003a-4f0e-977d-5503408a2f30
#cluster-name: GZ
#配置元数据
#metadata:
#k: v
application:
#服务名称尽量用 - 不要用 _ 更不要用特殊字符
name: user-center
按照上面的 加依赖 → 写注解 → 写配置 三个步骤可以把很多应用集成到nacos里,为后续微服务互相调用做准备。
4.测试是否可以微服务之间访问
#按照上面的步骤,提前将一个名为 content-center 的应用注册到了微服务
#在应用 user-center 编写测试类(这是另外一个微服务了)
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestController {
private final DiscoveryClient discoveryClient;
/*返回所有实例信息*/
@RequestMapping("/test2")
public List<ServiceInstance> test2(){
return discoveryClient.getInstances("content-center");
}
}
#以端口8084启动 user-center应用,访问 localhost:8084/test2,得到如下结果(这里用了json格式化工具:Json格式化插件)
#如果启动多个content-center实例,会得到多个实例
启动多个实例方法:配置启动项,勾选Allow parallel run,然后再启动应用即可(这里需要修改端口,以免出现端口占用问题)
#再次访问,得到结果
#以上就可以证明,微服务之间能够互相发现了
5.实际场景应用
下面是Service层代码的一个方法,可以通过获取实例,接着获取url和端口来拼接整体的访问路径,之后用ResTemplate 来实现服务之间的通信。
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ShareService {
private final ShareMapper shareMapper;
private final RestTemplate restTemplate;
private final DiscoveryClient discoveryClient;
public ShareDTO findById(Integer id){
Share share = shareMapper.selectByPrimaryKey(id);
Integer userId = share.getUserId();
//用户中心所有实例信息
List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
//随机获取一个拼接好的实例
List<String> targetUrlS = instances.stream()
.map(instance -> instance.getUri().toString()+"/users/{id}")
.collect(Collectors.toList());
int i = ThreadLocalRandom.current().nextInt(targetUrlS.size());
String targetUrl = targetUrlS.get(i);
UserDTO userDTO = restTemplate.getForObject(
targetUrl,
UserDTO.class,
userId);
ShareDTO shareDTO = new ShareDTO();
BeanUtils.copyProperties(share,shareDTO);
shareDTO.setWxNickName(userDTO.getWxNickname());
return shareDTO;
}
}
6.Nacos服务发现的领域模型
Namespace 命名空间(主要用来实现隔离,如dev,prod,默认是public ,拥有不同的NameSpace的服务之间不可以相互访问)
Group 分组 (可以把不同的微服务划分到同一个组,方便管理,默认是DEFAULT_GROUP)
Service 微服务 (如上面的user-center,content-center等等,也就是我们的微服务的划分)
Cluster 集群(即一个微服务也可以有很多实例,部署在不同的机器用来做负载,容灾,还可以实现微服务调用更近的其它微服务(同一集群下))
instance 实例
7.元数据
#什么是元数据:Nacos概念
#元数据的作用:描述微服务,实现版本控制
#如何为微服务设置元数据:(key=value的形式即可)
##控制台设置
##配置文件设置 (本文第三章第三小节的配置注释中)