image.png

架构原理image.png

1、微服务系统在启动时将自己注册到服务注册中心,同时外发布Http接口供其他系统调用(一般都是基于SpringMVC)
2、 服务消费者基于Feign调用服务提供者对外发布接口,先对调用的本地接口加上注解@FeignClient,Feign会针对加了该注解的接口生成动态代理,服务消费者针对Feign生成的动态代理去调用方法时,会在底层生成Http协议格式的请求,类似/stock/deduct? productId=100
3、Feign最终会调用Ribbon从本地的Nacos注册表的缓存里根据服务名取出服务提供在机器的列表,然后进行负载均衡并选择一台机器出来,对选出来的机器IP的端口拼接之前生成的url请求,生成类似调用Http接口地址 http://192.168.0.60:9000/stock/deduct?productId=100,最后基于HTTPClient调用请求

缓存

https://www.yuque.com/docs/share/30069944-240e-4db8-b450-98d5e5b838a2?#fEUiQ

服务注册流程

引入的nacos-discovery jar包中有一个监听方法,监听Spring容器初始化完成后,会进行节点注册,会将该实例节点存储到一个双层Map中,第一个map的Key是命名空间,第二个map的key是group和serviceName,value就是service类该服务实例,没有的话进行创建。
之后要存储到内存注册列表操作,如果是临时节点key为该实例名+ephemeral字符串。进行存储前通过判断Key中是否有ephemeral字符串,如果不是临时节点就要持久化。这里有一个异步操作,能够提升性能。
源码精髓

  • 注册实例信息更新到内存注册表中
  • 同步实例信息到nacos server集群其他节点

内存注册表中更新数据使用了copyonwirte思想:内存注册表也是一个Map来存储服务,写操作会重新创建一个新的map,将旧的服务复制到新的map中,然后进行更新操作,新map替换旧map。

源码精髓
这种copyonwrite思想跟eureka对比优点:时效性高,eureka二级缓存需要等待微服务拉取最新数据才进行填充,而Nacos在更新完新map就与旧map进行合并操作

个人理解:
首先我们这个项目中会引入discovery,然后这里面有一个监听器,会监听项目的IOC是否初始化完,如果初始化完了,项目会发送一个HTTP请求给Nacos进行服务的注册,该实例节点会到这个双map中,第一个map是key的命名空间,第二个map的key是group和serviceName,value就是该服务的实例。

配置中心

https://blog.csdn.net/Zong_0915/article/details/113089265
image.png
image.png
Nacos Client采用的是pull的形式进行拉取,然后会发送信息到Nacos Server,这个时候会有一个等待期29.5,当在这个29.5的时候有更新的时候,立即发给Nacos Client如果,没有更新的话,会一直等到30s然后再发。

内存注册表是一个map集合,如何避免同一个服务实例注册覆盖问题?

使用了阻塞队列

如何判断实例是临时节点还是持久节点?

instance注册会存储到put中,key值中增加了一个ephemeral字符串,存储前会进行判断,如果key包含该字段表示注册的实例临时实例,没有则是持久化实例。

临时实例:则不会在Nacos服务端持久化存储,需要通过上报心跳的方式进行包活,如果一段时间内没有上报心跳,则会被Nacos服务端剔除,在被摘除后如果又开始上报心跳,则会重新将这个实例注册。

持久化实例: 则会持久化被Nacos服务端,此时即使注册实例的客户端进程不在,这个实例也不会从服务端删除,只会将健康状态设为不健康。