为了实现多个微服务之间的调用,咱们除了须要Feign这种调用组件外还得依赖服务发现组件。主要的缘由是每一个微服务所在的机器ip并不是老是固定的,而且每一个微服务均可能部署多个实例在不一样的机器上,因此咱们不能把依赖的微服务ip地址写在代码或配置文件里,咱们须要有个组件去动态的管理,这就是为何微服务架构里服务发现功能是必须的。html
那么服务发现组件是怎么实现服务发现的呢?咱们以你们比较熟悉的MySQL来作类比,经过MySQL简单说明一下服务发现机制的实现。以下图:java
简单说明一下什么是服务提供者与服务消费者:git
当微服务启动的时候会向服务发现组件注册自身信息,在上图中就相似于向MySQL发送一条insert语句,将服务的元数据如服务名称、ip地址及服务状态等信息插入到MySQL中,如上图的registry表数据所示,这个过程称之为服务注册,因此服务发现组件内部会都维护相似于这样的一张注册表。github
微服务在注册完成后,会读取服务发现组件中保存的其余微服务的元数据并缓存一份到本地,就相似于向MySQL发送一条select all语句。这样在调用其余服务的时候,就不须要每次都去服务发现组件上查询,而是从本地缓存去查找调用地址,这样能够减轻服务发现组件的压力。因此上图中的调用箭头并无指向服务发现组件,而是直接指向服务提供者。这样的好处是哪怕是服务发现组件挂掉了,还能从本地缓存中获取其余微服务的调用地址。到这一步微服务之间就能够互相发现了,即完成基本的服务发现spring
但微服务有可能会挂掉或下线,此时其余服务不该该去发现一个不存在的服务。因此每一个服务启动且向服务发现组件注册完成以后,都会经过心跳机制告知存活状态。上图中用last_heartbeat字段表示,若某个服务在超过必定的时间都没有发送心跳包的话,就会被服务发现组件检测到,此时就会删除注册表里该服务的注册信息,并通知其余服务更新本地缓存(如有新注册的服务也会通知其余服务更新本地缓存)。json
关于什么是Nacos,官方文档已经描述得很详细了,Nacos官方文档地址以下:浏览器
因此这里只是简单概述一下,Nacos与Eureka同样,是服务发现组件,同时也是配置中心。Nacos解决了两个问题,一是服务A如何找到服务B;二是管理微服务的配置,让一个微服务的全部实例的配置都统一,而且能够实现配置修改后自动刷新等。服务器
理论介绍也说得差很少了,本小节咱们来动手搭建一个Nacos Server。过程很简单首先须要下载一个Nacos,下载地址以下:架构
而后咱们须要选择一个合适的版本下载,即Nacos Server版本应尽可能与Client端的版本对应。至于Client的版本咱们能够到工程的pom.xml文件中找到Spring Cloud Alibaba的依赖管理项点击进去便可查看到:
以下能够看到Nacos Client的版本为1.0.0,因此与之对应选择1.0.0版本的Nacos Server进行下载:
注:我这里使用的Spring Cloud版本是Greenwich.SR1,Spring Cloud Alibaba的版本是0.9.0.RELEASE
因为不是生产环境所用,其实也无需严格选择对应的版本,只要能用就能够了,因此我这里选择下载最新的1.1.0版本(通过测试可用):
下载并解压后进入bin目录,双击startup.cmd,或在命令行中输入cmd startup.cmd便可运行Nacos Server:
启动成功:
使用浏览器访问localhost:8848
进入Nacos Server的管理页面,此时须要输入帐户密码,默认的帐户密码都是nacos:
登陆成功后,页面以下:
该管理页面支持中英文,可在右上角点击切换:
官方文档以下:
在上一小节中,咱们已经完成了Nacos Server的搭建,而这一小节将演示如何将微服务注册到Nacos。我如今有一个用户中心微服务,其pom.xml文件以下,包含了Spring Cloud Alibaba及Nacos Client依赖,Spring Boot版本为2.1.6.RELEASE:
<dependencies> ... <!-- Nacos Client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <!--整合Spring Cloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--整合Spring Cloud Alibaba--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>0.9.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
在配置文件中配置一下nacos server的地址及端口:
spring: cloud: nacos: discovery: # 指定nacos server的地址 server-addr: 127.0.0.1:8848 application: # 服务名称,必须的配置项,不然不会向nacos注册 name: user-center ...
配置完成后启动项目,而后到nacos server的管理页面的服务列表上查看是否注册成功,注册成功的话会显示在服务列表里,以下:
点击详情能够看到详细信息:
通过以上这几个步骤,就能够很是简单地整合Nacos Client,并将微服务注册到Nacos Server上。经过一样的步骤,我将另外一个内容中心微服务也注册到Nacos Server上。咱们来写一个简单的测试用例,看看在内容中心上是否能发现用户中心,代码以下:
@Slf4j @SpringBootTest @RunWith(SpringRunner.class) public class DiscoveryClientTests { @Autowired private DiscoveryClient discoveryClient; /** * 测试服务发现,证实内容中心能找到用户中心 */ @Test public void getServiceInstancesTest(){ // 获取用户中心微服务的全部实例信息 List<ServiceInstance> instances = discoveryClient.getInstances("user-center"); // 以json格式打印出来 log.info(JsonUtil.obj2JsonPretty(instances)); } }
控制台输出的json信息以下,证实经过服务发现组件能让内容中心老是能找到用户中心:
[ { "serviceId" : "user-center", "host" : "192.168.190.1", "port" : 8080, "secure" : false, "metadata" : { "nacos.instanceId" : "192.168.190.1#8080#DEFAULT#DEFAULT_GROUP@@user-center", "nacos.weight" : "1.0", "nacos.cluster" : "DEFAULT", "nacos.healthy" : "true", "preserved.register.source" : "SPRING_CLOUD" }, "uri" : "http://192.168.190.1:8080", "scheme" : null, "instanceId" : null } ]
下图整理了Nacos服务发现的领域模型,咱们将围绕该图进行介绍:
一、上图最外层的是Namespace,对应管理界面的命名空间,以下:
Namespace主要用做隔离,默认为public,例如咱们有三个环境:开发、测试及生产环境,那么就能够建立三个Namespace,不一样的Namespace之间是互相隔离的。
举个例子,咱们能够来建立一个开发环境专用的命名空间:
建立完成后能够看到每一个命名空间都会有本身的惟一命名空间id:
那么微服务要如何注册到指定的命名空间呢?很简单,在配置文件中经过namespace配置项指定便可:
spring: cloud: nacos: discovery: # 指定nacos server的地址 server-addr: 127.0.0.1:8848 # 配置命名空间 namespace: 4a557407-c2c8-4524-97a0-17aa3c836407 ...
配置完成后重启项目,此时该服务再也不是注册到以前的public命名空间,而是注册到咱们刚刚建立的dev命名空间,此时在dev下的微服务是看不到public下的微服务的,即实现了环境隔离了:
二、在Namespace之下是Group服务分组,默认的Group是DEFAULT_GROUP。咱们能够在服务列表中看到:
Group能够将不一样的微服务划分到同一个分组里,Group可让咱们方便去分组管理微服务。但须要注意的是,在目前的Spring Cloud Alibaba版本,并无用上这个Group,应该会在将来的版本上支持。
三、而Group下面是Service,Service既是微服务,例如用户微服务、订单微服务等。每一个Service能够包含多个Cluster(集群),Cluster是对指定微服务的一个虚拟划分,默认为DEFAULT。比方说公司内有北京机房、上海机房的服务器,那么为了异地容灾,用户中心微服务就可能会被同时部署在北京机房和上海机房。这时候咱们就能够为北京机房的用户中心微服务实例划分到一个集群里而且起一个集群名称,而上海机房的用户中心微服务实例同理。将微服务实例划分到一个集群后,咱们还能够实现相似于让上海机房里的微服务尽可能调用同机房内的其余微服务,这样在容灾的同时还能够提高性能。
关于集群咱们能够直接在配置文件中配置,而不用像命名空间那样须要提早建立,以下:
spring: cloud: nacos: discovery: # 指定nacos server的地址 server-addr: 127.0.0.1:8848 # 配置集群名称,名称能够任意 cluster-name: BJ ...
配置完成后重启项目,此时能够看到该微服务实例处于BJ集群下,而不是处于以前默认的DEFAULT集群下:
四、Cluster里是Instance,即上面所提到的微服务实例
关于这些概念的官方文档地址以下:
什么是Nacos元数据,官方文档描述以下:
Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各类自定义标签 (label),从做用范围来看,分为服务级别的元信息、集群的元信息及实例的元信息。
- 服务级别的元信息在服务详情中展现
- 集群的元信息在集群配置中展现
- 实例的元信息在集群实例表内展现
元数据做用:
配置元数据的两种方式:
在Nacos Server的管理页面设置;以服务的元数据示例,在服务详情页面点击编辑服务后,在元数据这栏输入json格式的元数据便可:
spring: cloud: nacos: discovery: # 指定nacos server的地址 server-addr: 127.0.0.1:8848 # 这种方式配置的是实例级别的元数据 metadata: # k-v形式,k和v均可以自定义 instance: c test: a version: v1
配置完成后重启项目,能够看到配置文件中所配置的实例级别元数据: