天天看點

SpringCloudAlibaba之Nacos服務注冊與發現

寫在前面

本文參照Spring官方文檔,寫了相關代碼 (源碼位址),在此做下筆記;

官網關于

Nacos

的介紹是這樣的:“

Nacos

是一個易于使用的動态服務發現、配置和服務管理平台,用于建構雲本地應用程式”。一句話描述了

Nacos

能夠實作的功能:服務發現、配置、服務治理。

那麼,我們先從基礎的服務發現開始吧!

入門

因為後續我們将陸續使用到

Spring-Cloud-Alibaba

中的其它元件,是以,我們在頂層子產品中引入如下的

POM

管理:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
           

當然,不要忘了這個項目需要是

SpringBoot

項目,是以,我們之間讓這個頂層子產品歸于

Spring-Boot

下,添加如下:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
    </parent>
           

以上是整個大項目的 POM 檔案描述,以後各子子產品均在該項目下建立。現在,讓我們按學習的進度來建立各個子項目(子子產品)。

啟動 Nacos 服務

首先,我們需要 下載下傳 Nacos 服務,進入

/bin

目錄下,通過

startup.cmd

啟動它。啟動成功之後,通路

http://<ip>:8848/nacos

可檢視控制台:

官網在這裡描述為

http://ip:8848

,但你通路這個位址會 404。我看了

nacos-server.jar

包中的配置檔案,發現位址應為如上的形式。
SpringCloudAlibaba之Nacos服務注冊與發現

啟動 Provider 應用

建立一個

provider_app

子子產品,引入如下依賴:

<dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
           

并添加

application.yml

配置檔案:

application.yml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: provider-app
server:
  port: 18083
           

新增啟動類:

package com.duofei;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * 啟動類
 * @author duofei
 * @date 2020/7/22
 */
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProviderDemoApplication.class, args);
    }

    @RestController
    public class EchoController{
        @GetMapping("/echo/{string}")
        public String echo(@PathVariable String string){
            return "Hello Nacos Discovery " + string;
        }
    }
}
           

啟動應用程式,觀察

Nacos

的控制台:

SpringCloudAlibaba之Nacos服務注冊與發現

可以看出,我們剛運作的服務成功注冊。如果仔細留意應用程式的啟動日志,也能看見列印的注冊完成的資訊。

啟動 Consumer 應用

調用者服務稍微複雜一點,因為它需要調用提供者的

RESTful

服務。這裡使用最原始的

LoadBalanceClient

RestTemplate

來通路提供者提供的服務。

建立

consumer-app

項目,依賴不變,配置檔案稍作修改:

application.yml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: consumer-app
server:
  port: 18084
           

啟動類如下:

package com.duofei;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.sql.SQLOutput;

/**
 * 啟動類
 * @author duofei
 * @date 2020/7/22
 */
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApp.class, args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @RestController
    public class NacoController{

        @Autowired
        private LoadBalancerClient loadBalancerClient;
        @Autowired
        private RestTemplate restTemplate;

        @Value("${spring.application.name}")
        private String appName;

        @GetMapping("/echo/app-name")
        public String echoAppName(){
            ServiceInstance serviceInstance = loadBalancerClient.choose("provider-app");
            String path = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), appName);
            System.out.println("request path: " + path);
            return restTemplate.getForObject(path, String.class);
        }

    }
}
           

通路

http://192.168.3.18:18084/echo/app-name

,但在擷取服務執行個體時,發現擷取到的服務執行個體位址并不是

192.168.3.18

, 是以無法通路到注冊的服務。這是因為服務提供者的配置檔案并未配置 ip 位址,我們所拿到的 ip 位址是在啟動過程中通過 Java 原生的

NetworkInterface

擷取的。具體的底層執行代碼則是在

NacosDiscoveryProperties

類的

init

方法。

是以,我們修改服務提供者類的配置檔案,新增

ip

配置:

spring:
	cloud:
		nacos:
			discovery:
				ip: 192.168.3.18
           

然後重新通路

http://192.168.3.18:18084/echo/app-name

,就可以得到

Hello Nacos Discovery consumer-app

的響應了。

Nacos

的服務注冊與發現流程很簡單,但唯一讓我有點困惑的便是這

ip

擷取了。原因可能是因為我本地有建立過虛拟機,然後有比較多的虛拟網絡接口,而

nacos

的篩選方式也比較簡單粗暴,直接取了第一個符合條件的網絡接口。

不過,在後續發現,可以在配置檔案中指定網絡接口的名稱:

spring:
	cloud:
		nacos:
			discovery:
				network-interface: eth9
           

上面這個網口名稱對應了我的

192.168.3.18

的 ip 位址,這樣也可以正常注冊 ip 位址。

服務發現端點

Nacos Discovery

在内部提供了一個具有

nacos-discovery

端點 id 的端點。

端點暴露的

json

内容為:

  1. subscribe: 展示了目前的服務訂閱資訊;
  2. NacosDiscoveryProperties

    : 展示了目前服務的

    Nacos

    配置;

想要通路

/nacos-discovery

這個端點路徑,需要引入

spring-boot-starter-actuator

元件,并在配置檔案中新增如下内容:

management:
  endpoints:
    web:
      exposure:
        include: nacos-discovery
           

如上的修改,我們将它應用到了前面的服務提供者和服務調用者子子產品中,然後,通路

http://192.168.3.18:18083/actuator/nacos-discovery

路徑或者是将端口改為服務調用者的端口路徑:

/actuator 這個基礎路徑,可以通過

management.endpoints.web.base-path

修改。
SpringCloudAlibaba之Nacos服務注冊與發現

可以看到暴露的内容正是

NacosDiscoveryProperties

subscribe

但為什麼

subscribe

的内容為空呢?這是因為,訂閱資訊需要主動去訂閱。在我們的

consumer-app

的啟動類中增加如下代碼:

@Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;
	// 實作 InitializingBean 接口
	@Override
    public void afterPropertiesSet() throws Exception {
        NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
        namingService.subscribe("provider-app", event -> {
            System.out.println(event);
        });
    }
           

需要注意的是,注冊好該監聽器,會在啟動後直接觸發一次。現在,讓我們重新通路端點,擷取到如下資訊:

SpringCloudAlibaba之Nacos服務注冊與發現

我們可以在

nacos

的控制台,修改訂閱的服務資訊,也會觸發該事件。但檢視該事件的實作類隻有一個,是以很難确定具體的事件行為是什麼。

服務發現的配置

服務發現的配置可以參考

NacosDiscoveryProperties

類。大多配置都見名知意,可一切還是要以代碼的執行結果為準,多思考為什麼,切記不要先入為主。

因為我自己在這裡就犯了一個先入為主的錯誤。我打算配置一個

namespace

,第一步是在

nacos

控制台上建立了一個命名空間,命名空間名為

demo

,意為測試代碼運作時使用的命名空間。緊接着,第二步,我在

consumer-app

配置檔案中新增了如下配置:

spring:
  cloud:
    nacos:
      discovery:
        namespace: demo
           

可結果并不如我所願,

consumer-app

始終無法注冊到"demo"的命名空間。然後,我開始跟蹤源碼,結果發現在底層,

namespace

最終對應的是

namespaceId

。是以,這裡其實是需要一個命名空間 id 的。而該 id 值在你建立好命名空間後就可以得到。這個地方的值修改為命名空間 id 後,一切就正常了。

consumer-app

項目修改完命名空間後,記得将

provider-app

也修改為對應的命名空間,否則

consumer-app

無法通路到

provider-app

總結

nacos

的服務發現與注冊真的比較簡單。我這裡整個配置項也就使用了三個,這可能是因為還沒有內建

Dubbo

或者其它的

RPC

架構。

這裡還有一點沒有提到,那就是負載均衡。不過,你可以發現

nacos-discovery

使用了

Ribbon

。那麼,

nacos-discovery

自然會使用

ribbon

來實作負載均衡政策。想了解更多的可以去檢視

ribbon

文檔,還有其它疑問的也可以看下

nacos-discovery

ribbon

包中的源碼。

文檔中的内容也需要持懷疑的态度,代碼才是檢驗“真理”的标準!

并不是指文檔中的内容有錯,而是說文檔中的内容簡潔,容易讓我們剛入門的小白造成了解上的誤差!

我與風來

認認真真學習,做思想的産出者,而不是文字的搬運工。

SpringCloudAlibaba之Nacos服務注冊與發現

但行善事,莫問前程。

繼續閱讀