我们都知道微服务的时代,就是将传统的单体架构拆分成独立的服务进行部署
但是微服务与微服务之间的调用 存在什么问题 需要用到什么技术
或者说用什么来技术来管理微服务
我有2个微服务 一个user 一个order
现在需要的是user--->> 可以调用到order 我们通常会想到这种模型
但是nacos 给我们解决了什么问题??或者说nacos 做了什么??
我们通过user---->>order 的技术无非就是通过http 来调用
这类的技术很多 spring的restTemplate ,apache的Okhttp
等等 此时完全不必要上sprigncloud的架构
第一个问题 首先此时代码中我们的
String url = "http://localhost:8081/";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
// 此时的url 是写死的 ,如果在下游服务横向扩展的时候此时是没办法调用的,也就是说我客户端的要有个负载均衡
也就是说我们客户端需要有一个客户端负载均衡能力,从List中选中
一个并且发起请求去调用
其次 比如说下游有2个Order服务,客户端还需要感知2个服务是可用的
比如说我Order1 挂了,我就不能再调用他了 ,也就是说某个节点出现问题了 我要吧他从列表中踢出
这些都的要依赖我们注册中心去解决
假设我们自己实现一个注册中心 又会有什么思路呢,微服务中,
我们可以用mysql 表来存储服务的信息
注册中心的功能 可以记录 每一个节点的ip:端口 存货状态
我可以在我服务启动的时候往mysql中Insert 一条数据 代表我此时是up,之后在我发起调用的时候我就做一次mysql 的select 查询
然后缓存起来~, 然后再发http请求的时候 我直接读缓存就可以了
呢么 状态什么时候是up 什么时候是down 这个怎么做
这就关系到心跳机制 涉及一个名词叫做服务续约
客户端向服务端定时发心跳 服务端接受到心跳 要修改服务的续约时间
关于注册中心的功能
1> 服务注册 insert
2> 服务查询 select --->> 客户端缓存 ~
3> 服务注销 delete
4> 心跳接口 update [比如说每15s客户端发送一个心跳 我服务端收到心跳 之后 update 最新时间]
// 服务端自己
服务端服务踢出 currentTime-最后续约的时间>15s update 存活状态 改成down 【网络抖动问题 有可能等他网络好的时候给他恢复】
服务端服务踢出 currentTime-最后续约的时间>30s delete 直接删除
心跳
服务的续约
客户端向服务端定时发心跳 服务端接受到心跳 要修改服务的续约时间
还有一个阈值保护 当服务的状态是是down的节点/All节点 <0.75 的话 就不会去踢出了~,他也会吧有问题的down 状态的 发给调用方也就是说此时的会员服务. 因为此时只是服务和注册中心连不上了(可能是服务和注册中心不在一个机房或者 网络抖动的话),但是此时服务和服务还是可以Ping通过 . 有的注册中心这样设计的
当我们启动nacos的时候,他会提示我们此时nacos 注册在8848 端口上,使用的是内嵌数据库(derby ),单机模式启动的
然后我们看看nacos 的基本架构在官网上看 有个namingService 还有一个configService
其实说白了就是配置中心和注册中心
NamingService 可以在idea 中搜, 基本上就是一些与服务有关的相关接口 我们看下他的注册
registerInstance 这个接口 注册一个实例
我们其实可以看到当他注册一个服务的时候 其实是往service发一个请求 我们debug看下请求的url是 /nacos/v1/ns/instance
其实官网上也有,也就是说nacos 吧关于服务相关的api 暴露出来了。 支持异构,同时也支持用postman输入参数可以注册一个服务
注册服务 url, 请求方式 请求参数 相应参数
接下来我们可以看看服务端与namespace有关的代码 看看他到底是怎么注册的
``
注册源代码如上
/**
* Map(namespace, Map(group::serviceName, Service)).
*/
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
我们追踪源代码不难发现 他这个他这个serviceMap的结构‘=
其实nacos底层是这么排序的
命名空间---》组---》服务---》集群---》实例 范围从大到小
是上面的结构
https://blog.csdn.net/qq_43631716/article/details/121333247 这个细节看看大佬的博客
注册中心版本的演进 V1
第一个版本就是通过我们发请求 是通过restTemplate来调用下一个服务 这样做的缺点就是商品服务的ip 或者port 改了 我此时 订单服务需要改代码重启应用
V2 我此时服务发起方维护一个 ip列表, 调用的时候我从列表中随机去取一个ip 然后发起调用
这样的做法的缺点就是 如果我商品服务增加一个机子,或者减少一个机子 我此时还得 手动修改代码 然后去重启,
而且 我商品服务有一个服务要是挂了, 我此时订单服务在发起调用的时候还是会选择到这一台机子的的
故而引进注册中心的概念
我服务注册的时候 我直接insert一条语句,服务发现的时候 我直接selelct 下
接下来就是下面的注册中心的功能~
注册中心对外提供的接口 或者说该有的功能
1.insert 服务注册 ---> 注册接口
2.select 服务查询 ----> 服务获取接口
3. heart ---->心跳接口----> update 每隔15s 发送一个心跳 更改最新时间 代表此时我的微服务还存活
4. delete 注销接口 微服务关闭 就得delete
5. 如果没有服务续约 我就给update 为down
---------------------------------------------------------------->>
再讲下nacos的核心架构图
namespace 是用来做环境隔离的 比如说你namespace 分生产,开发,测试
意思是 开发环境注册到开发环境的nacos
意思是 生产环境注册到生产环境的nacos
我生产环境的订单服务不可能调用到我开发环境的 用户服务
group 是用来做分组的隔离的 我可以做到不同的分组是不能进行调用的
比如说我上面的支付服务是不能调用你物流服务的接口的 因为我物流服务的接口要对你屏蔽掉
不对你进行开放,
我物流服务本来不会对你暴露的
你现在不分组的话 你可以访问其他服务---》 我物流可以调用你的支付服务
我避免微服务之间 不相关的微服务之间进行相互调用 我此时可以做到隔离
集群 比如说我订单服务 部署2套 南京机一套 一个是北京机房一套
我虽然可以跨集群调用 比如说 我南京机房的订单 调用北京机房的商品 但是我要避免这种情况的发生
我要 避免跨集群调用 最好同机房调用
让他优先同集群 因为 网络延迟的问题