What is Nacos Discovery?
Service discovery is one of the most critical components in microservices architecture.
It would be very difficult to manually configure the service list of all service providers for each client, and it would be difficult to dynamically scale the service. Nacos Discovery helps users automatically register services with Nacos servers and dynamically sense and refresh the service list of a service instance.
In addition, Nacos Discovery registers some metadata information about the service instance itself, such as host, port, health check URL, home page, etc. – with Nacos.
For Nacos installation and startup, see Spring Cloud Alibaba: Nacos Installation and Use
This article will detail some technical practices for registering and discovering Nacos Discovery services.
Quick access to the
Add the dependent
Start the Nacos server. Then add dependencies to your project.
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Copy the code
A complete configuration of POM.xml is as follows:
<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 the 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>
Copy the code
Note: in the source code of this project, dependencies are managed by the dependencies module, and the dependencyManagement node is also configured in the dependencies module. The above example only demonstrates the necessary configuration items. There are some differences in the source code of this project.
Start the Provider service Provider
In Nacos Discovery service registration and Discovery, there are generally two roles, one is Provider service Provider and the other is Consumer service Consumer. They all need to register themselves with Naocs, a step called service registration. Service providers provide services externally, and service consumers invoke service providers in various ways to complete business functions. And a service can act as both a provider and a consumer.
1. Configuration application. Yml
To use Nacos, you need to configure some basic parameters in either application.yml or bootstrap.yml. As follows:
# Nacos parameters
nacos:
server-addr: 192.1689.17.: 8848
username: nacos
password: nacos
# namespace, used for environment isolation
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, used for environment isolation
namespace: ${nacos.namespace}
# Group, usually by project
group: SPRING_CLOUD_EXAMPLE_GROUP
# Custom metadata
metadata:
# version
version: 1.0
# region
region: hangzhou
Copy the code
The above configuration is complete. If you need to simplify the configuration, the configuration is as follows:
spring:
application:
name: nacos-discovery-provider
cloud:
nacos:
discovery:
server-addr: 192.1689.17.: 8848
Copy the code
2. Enable service discovery
Just add the annotation @enableDiscoveryClient to the project startup class. As follows:
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); }}Copy the code
3. Create a REST interface
Service providers need to provide interfaces for consumers to invoke, typically using RESTful HTTP interfaces. As follows:
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; }}Copy the code
4. Verify
After starting the Provider service Provider, I open the Nacos console and see that the service is registered in the dev namespace because I’m using the dev development environment namespace.
Start the Consumer service for consumers
The configuration of the Consumer’s dependencies is basically the same as that of the Provider service Provider, but a little more complex. The REST service on the Provider side needs to be called on the Consumer side. And there are many ways to call it.
1. The RestTemplate way
The dependency and configuration are consistent with those of the Provider.
Then create the RestTemplate configuration class. As follows:
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(a){
return newRestTemplate(); }}Copy the code
The Provider service Provider is then invoked. As follows:
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(a) {
// Use a combination of LoadBalanceClient and RestTemplate to access
// LoadBalanceClient provides load balancing and gets service instances from Nacos based on service names
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);
returnrestTemplate.getForObject(url, String.class); }}Copy the code
Start the project, open a browser requests: http://localhost:8080/echo
View the returned results for verification.
2. Feign way
First you need to add Feign dependencies as follows:
<! -- Spring Cloud Feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Copy the code
After adding dependencies, you need to add the @enableFeignClients annotation to the project startup class to enable functionality. As follows:
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); }}Copy the code
You then need to create an interface class, FeignService, that provides access methods for the service interfaces provided by the Provider service Provider. As follows:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/** * nacos-discovery-provider specifies the service name of the service provider */
@FeignClient("nacos-discovery-provider")
public interface FeignService {
Provider Specifies the REST interface for the service Provider@param message
* @return* /
@GetMapping("/echo/{message}")
public String echo(@PathVariable String message);
}
Copy the code
Call the FeignService interface in the Controller to implement the call to the Provider side. The code is as follows:
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(a) {
returnfeignService.echo(appName); }}Copy the code
Start the project, open a browser requests: http://localhost:8080/feign/echo
View the returned results for verification.
Multiple environment isolation
Nacos Discovery and Nacos Config have the same environment isolation, distinguished by namespace.
See the previous article: Spring Cloud Alibaba: Nacos Config Configuration Center
In real development, this is a very good way to isolate the various environments and avoid confusion in service management.
Combined with Sentinel fuse
Sentinel is an important component of Ali micro service ecosystem with many functions, which will be briefly introduced here. There will be a special topic for detailed research and practice.
This is combined, primarily, with Feign calls. If the call fails, a circuit breaker can be performed.
First you need to add a dependency, as follows:
<! -- Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
Copy the code
Configure in application.yml as follows:
nacos:
server-addr: 192.1689.17.: 8848
username: nacos
password: nacos
namespace: 904174a3-d51f-43ed-a456-c4fd7386ecb3
sentinel:
dashboard: 192.1689.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 service registration and discovery
discovery:
server-addr: ${nacos.server-addr}
namespace: ${nacos.namespace}
group: SPRING_CLOUD_EXAMPLE_GROUP
# Spring Cloud Alibaba Sentinel configuration
sentinel:
transport:
# Sentinel console
dashboard: ${sentinel.dashboard}
feign:
# Enable Feign support for Sentinel
sentinel:
enabled: true
Copy the code
Create a callback class FeignServiceFallback for the failure of FeignService interface methods:
public class FeignServiceFallback implements FeignService {
@Override
public String echo(String message) {
return "echo fallback, please try again."; }}Copy the code
When accessing the echo(String Message) method fails, this callback will return the data format you want.
In addition to this, we need to create a configuration class FeignConfig as follows:
import com.xingtuai.cloud.nacos.discovery.service.fallback.FeignServiceFallback;
import org.springframework.context.annotation.Bean;
public class FeignConfig {
@Bean
public FeignServiceFallback feignServiceFallback(a) {
return newFeignServiceFallback(); }}Copy the code
Add FeignServiceFallback and FeignConfig to @feignClient and modify the FeignService interface as follows:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/** * nacos-discovery-provider specifies the service name of the service provider */
@FeignClient(name = "nacos-discovery-provider", fallback = FeignServiceFallback.class, configuration = FeignConfig.class)
public interface FeignService {
Provider Specifies the REST interface for the service Provider@param message
* @return* /
@GetMapping("/echo/{message}")
public String echo(@PathVariable String message);
}
Copy the code
On normal access, the interface returns normal data, but when the interface fails, such as when the service provider goes offline and the access fails. The echo(String Message) method in FeignServiceFallback will be called and returned. This avoids returning an exception and instead returns a controlled piece of data that can be used as a service circuit breaker.
There is a lot of knowledge and practice related to Sentinel, which will be shared in the future. I will not repeat it here.
Project source code
GitHub – spring-cloud-example
For more technical articles, please visit my blog at JemGeek.com
Click to read the original article