Nacos Discovery
是什麼?html
服務發現是微服務架構體系中最關鍵的組件之一。若是嘗試着用手動的方式來給每個客戶端來配置全部服務提供者的服務列表是一件很是困難的事,並且也不利於服務的動態擴縮容。Nacos Discovery 能夠幫助用戶將服務自動註冊到 Nacos 服務端而且可以動態感知和刷新某個服務實例的服務列表。java
除此以外,Nacos Discovery 也將服務實例自身的一些元數據信息,例如 host,port,健康檢查URL,主頁等-註冊到 Nacos 。
關於 Nacos 的安裝及啓動請查看文章:Spring Cloud Alibaba:Nacos 安裝及使用
本篇將詳細介紹Nacos Discovery
服務註冊與發現的一些技術實踐。git
啓動好 Nacos 服務端。而後在項目中添加依賴。github
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
一個完整的 pom.xml
的配置以下:web
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xingtuai.example</groupId> <artifactId>nacos-discovery-test</artifactId> <version>1.0-SNAPSHOT</version> <name>nacos-discovery-test</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring.boot.version}</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
注:在本項目的源代碼中,依賴統一使用dependencies
模塊管理,且其中dependencyManagement
節點也在dependencies
模塊中配置,上例僅演示必要的配置項,在項目源代碼中有些許區別。
Nacos Discovery 服務註冊與發現中,通常有兩個角色,一個是 Provider 服務提供者,一個是 Consumer 服務消費者。他們都須要將自身註冊到 Naocs 中,這一步叫服務註冊。服務提供者向外提供服務,服務消費者經過各類方式調用服務提供者完成業務功能。且一個服務,既能夠做爲提供者,同時也能夠做爲消費者。
1. 配置 application.yml
要使用 Nacos ,須要在 application.yml
或者 bootstrap.yml
中配置一些基本參數。以下所示:spring
# Nacos 相關參數 nacos: server-addr: 192.168.9.17:8848 username: nacos password: nacos # 命名空間,用做環境隔離 namespace: 904174a3-d51f-43ed-a456-c4fd7386ecb3 spring: application: name: nacos-discovery-provider main: allow-bean-definition-overriding: true cloud: nacos: # 權限認證,nacos.core.auth.enabled=true 時須要添加 username: ${nacos.username} password: ${nacos.password} discovery: server-addr: ${nacos.server-addr} # 命名空間,用做環境隔離 namespace: ${nacos.namespace} # 分組,通常按照項目進行分組 group: SPRING_CLOUD_EXAMPLE_GROUP # 自定義元數據 metadata: # 版本 version: 1.0 # 地域 region: hangzhou``` 上述配置比較完善,若是須要簡化配置,則以下所示:
spring:
application: name: nacos-discovery-provider cloud: nacos: discovery: server-addr: 192.168.9.17:8848 `
2. 開啓服務發現
在項目啓動類上添加註解 @EnableDiscoveryClient
便可。以下所示:apache
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class NacosDiscoveryProviderApplication { public static void main(String[] args) { SpringApplication.run(NacosDiscoveryProviderApplication.class, args); } }
3. 建立 REST 接口
服務提供者須要提供接口以供消費者進行調用,通常使用 RESTful 風格的 HTTP 接口。以下所示:bootstrap
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping public class TestController { @GetMapping("/echo/{message}") public String echo(@PathVariable String message) { return "Hello Nacos Discovery " + message; } }
4. 驗證
啓動 Provider 服務提供者後,打開 Nacos 控制檯,能夠看到服務已經註冊上去了,由於我使用的是 dev
開發環境的命名空間,因此服務註冊在 dev
的命名空間內。瀏覽器
Consumer 服務消費者的依賴的配置基本與 Provider 服務提供者相同,可是卻要比它更復雜一點。由於在 Consumer 端須要去調用 Provider 端的 REST 服務。而調用方式也有不少種。
1. RestTemplate 方式
依賴、配置與 Provider 一致。
而後建立 RestTemplate
配置類。以下所示:架構
import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @Component public class RestTemplateConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
而後調用 Provider 服務提供者。以下所示:
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @Slf4j @RestController @RequestMapping public class BaseTestController { @Resource private LoadBalancerClient loadBalancerClient; @Resource private RestTemplate restTemplate; @Value("${spring.application.name}") private String appName; @GetMapping("/echo") public String echoAppName() { // 使用 LoadBalanceClient 和 RestTemplate 結合的方式來訪問 // LoadBalanceClient 提供負載均衡的功能,並從 Nacos 中根據服務名獲取服務實例 ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-discovery-provider"); String url = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), appName); log.info("request url: {}", url); return restTemplate.getForObject(url, String.class); } }
啓動項目後,打開瀏覽器請求:http://localhost:8080/echo
查看返回結果進行驗證。
2. Feign 方式
首先須要添加 Feign
的依賴,以下所示:
<!-- Spring Cloud Feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
添加完依賴之後,須要在項目啓動類中添加 @EnableFeignClients
註解以開啓功能。以下所示:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class NacosDiscoveryConsumerApplication { public static void main(String[] args) { SpringApplication.run(NacosDiscoveryConsumerApplication.class, args); } } ``` 而後須要建立一個接口類 `FeignService`,在類中爲 Provider 服務提供者提供的服務接口提供對應的訪問方法。以下所示:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
*/@FeignClient("nacos-discovery-provider")
public interface FeignService {
/* 接口定義
public String echo(@PathVariable String message);
}
在 Controller 中調用 `FeignService` 接口實現對 Provider 端的調用。代碼以下:
import com.xingtuai.cloud.nacos.discovery.service.FeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Slf4j
@RestController
@RequestMapping("feign")
public class FeignTestController {
@Resource private FeignService feignService;
@Value("${spring.application.name}")
private String appName;
@GetMapping("/echo")
public String echoAppName() {
return feignService.echo(appName);
}
}
啓動項目後,打開瀏覽器請求:[http://localhost:8080/feign/echo](http://localhost:8080/feign/echo) 查看返回結果進行驗證。 ## 多環境隔離 `Nacos Discovery` 與 `Nacos Config` 的環境隔離是同樣的,都是經過命名空間 `namespace` 進行區分。 具體請參考以前的文章:[Spring Cloud Alibaba:Nacos Config 配置中心](http://jemgeek.com/archives/2020/spring-cloud-nacos-config.html) 在實際開發中,經過這種方式能夠很是好的對各類環境進行隔離區分,避免服務管理的混亂。 ## 結合 Sentinel 熔斷 `Sentinel` 是阿里微服務生態中一個比較重要的組件,功能也比較多,在此僅簡單介紹。後續會有專題對其進行詳細的研究實踐。 此處結合,主要是在 Feign 調用的時候,進行處理。在調用失敗時,能夠進行熔斷。 首先須要添加依賴,以下所示:
<!-- Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在 `application.yml` 中進行配置,以下所示:
nacos:
server-addr: 192.168.9.17:8848 username: nacos password: nacos namespace: 904174a3-d51f-43ed-a456-c4fd7386ecb3sentinel:
dashboard: 192.168.9.17:8883 spring:
application: name: nacos-discovery-sentinel main: allow-bean-definition-overriding: true cloud: nacos: # 權限認證,nacos.core.auth.enabled=true 時須要添加
username: ${nacos.username} password: ${nacos.password} # Nacos 服務註冊與發現
discovery: server-addr: ${nacos.server-addr} namespace: ${nacos.namespace} group: SPRING_CLOUD_EXAMPLE_GROUP # Spring Cloud Alibaba Sentinel 配置
sentinel: transport: # Sentinel 控制檯
dashboard: ${sentinel.dashboard}
feign:
# 開啓 feign 對 sentinel 的支持
sentinel: enabled: true`
建立一個 FeignService
接口方法失敗時的回調類 FeignServiceFallback
,代碼以下:
public class FeignServiceFallback implements FeignService { @Override public String echo(String message) { return "echo fallback, please try again."; } }
當訪問 echo(String message)
方法失敗時,將會進入此回調,返回你須要的數據格式。
除此以外還須要建立一個配置類 FeignConfig
,代碼以下:
import com.xingtuai.cloud.nacos.discovery.service.fallback.FeignServiceFallback; import org.springframework.context.annotation.Bean; public class FeignConfig { @Bean public FeignServiceFallback feignServiceFallback() { return new FeignServiceFallback(); } }
而後須要改造一下 FeignService
接口,將 FeignServiceFallback
及 FeignConfig
設置在註解 @FeignClient
中,改造以下:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * nacos-discovery-provider 爲服務提供者的服務名 */@FeignClient(name = "nacos-discovery-provider", fallback = FeignServiceFallback.class, configuration = FeignConfig.class) public interface FeignService { /** * 接口定義 * Provider 服務提供者對應的 REST 接口 * * @param message * @return */ @GetMapping("/echo/{message}") public String echo(@PathVariable String message); }
正常訪問時,接口將返回正常的數據,可是當接口出現異常,好比服務提供者下線了,訪問失敗的話。那麼將會調用 FeignServiceFallback
中的 echo(String message)
方法並返回。這樣就避免返回異常,而是返回一個可控的數據,能夠用作服務熔斷。
Sentinel 相關的知識與實踐還有不少,後續會作專題分享,在此再也不贅述。
更多技術文章歡迎關注個人博客主頁:http://JemGeek.com