Application practice of 04 Nacos service registry

Posted by SergiuGothic on Mon, 27 Dec 2021 17:44:50 +0100

Introduction to registration center



Background analysis

In microservices, the first problem we need to face is how to find services (software is a service), and the second is how to communicate between different services? How to manage each service in the application better and more conveniently, and how to establish the link between various services, so that the registration center was born (for example, Taobao sellers provide services and buyers invoke services).
Zookeeper (Yahoo, APACHE), Eureka (Netfix), Nacos (Alibaba) and Consul (Google) are commonly used registration centers in the market. What are their characteristics and how do we select them? We mainly consider community activity, stability, function and performance For this microservice learning, we chose Nacos, which well supports Ali's double 11 activities. It can not only be used as a registration center, but also as a configuration center. It has good stability and performance.

Nacos overview

Nacos (dynamic naming and configuration service) is a platform for service registration, discovery and configuration management. It was incubated in Alibaba and grew up in the peak test of double 11 in the past decade. It has precipitated its core competitiveness of simplicity, ease of use, stability and reliability and excellent performance. Its official website address is as follows:

https://nacos.io/zh-cn/docs/quick-start.html

Building Nacos services



preparation

First: make sure your computer is configured with JAVA_HOME environment variable (required when Nacos is started), for example:

Second: make sure your MySQL version is above 5.7 (above MariaDB 10.5), for example



Download and install

Step 1: to download Nacos, you can directly enter the following address in the browser:

https://github.com/alibaba/nacos/releases

Step 2: select the corresponding version and download it directly, as shown in the figure:

1.nacos-server-1.4.2.tar.gz# is Linux/Unix/Mac

2.nacos-server-1.4.2.zip is

Step 3: decompress Nacos (preferably not to the Chinese directory), and its directory structure is as follows:

Initialize configuration

Step 1: log in to mysql and execute the sql script. For example, we can use the built-in client of mysql. First log in to mysql on the command line, and then execute the following instructions:

The instruction format here is: script path / Nacos mysql sql

source d:/nacos-mysql.sql 

After successful execution, a Nacos will be created_ Config database. When you open the database, you will see some tables, such as

Note: when executing this file, the version of mysql must be greater than 5.7 (MariaDB is better than 10.5.11), otherwise the following error will occur:


Step 2: configure nacos and open nacos / conf / application Open the default configuration in properties, configure the database to be connected based on your current environment, and the user name and password to be used when connecting to the database (if there is "#" in front, remove it):

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
 spring.datasource.platform=mysql

### Count of DB:
 db.num=1

### Connect URL of DB:
 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
 db.user.0=root        #Database user name
 db.password.0=root    #Database password

Service startup and access

Step 1: start the Nacos service.

Execute cmd in the bin directory of nacos to open the command window.  

Linux/Unix/Mac startup command (standalone stands for stand-alone mode, non cluster mode):

./startup.sh -m standalone


Windows startup command (standalone stands for stand-alone mode, non cluster mode):

startup.cmd -m standalone

explain:
1) When executing the execution command, either configure the environment variable or execute it directly in the nacos/bin directory
2) When Nacos starts, Java needs to be configured in the local environment variable_ Home (corresponding to the jdk installation directory),
3) Make sure that the database you connect to (nacos_config) exists
4) If all configurations are correct and can not be connected, check how many databases you have (mysql,...)

Step 2: access the Nacos service.

Open the browser and enter http://localhost:8848/nacos Address, the following landing page appears:

The default account password is nacos/nacos

Introduction to service registration and invocation (key points)



Business description

Create two project modules: service providers and service consumers (if they already exist, they do not need to be created). Both of them should be registered in the NacosServer (the server is essentially a web service, and the port is 8848 by default). Then the service provider can provide remote calling services for the service consumers (for example, the payment service is the service provider, and the order service is the service consumer), As shown in the figure:

Producer services creation and registration

Step 1: create a service provider project (the module name is SCA provider, if it already exists, there is no need to create it), inherit the parent project (01 SCA), and its POM The contents of the XML file are as follows:

<?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">
    <parent>
        <artifactId>01-sca</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>sca-provider</artifactId>
    <dependencies>
        <!--Web service-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Registration and discovery of services(We're going to talk about service registration nacos)-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

Step 2: create and modify the configuration file application YML (or application.properties) to realize service registration. The key codes are as follows:

server:
   port: 8081
spring:
  application:
    name: sca-provider #Service name must be configured for service registration
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

Note: do not use underscores ("") for service names, A bar ("-") should be used, which is the rule.
Step 3: create a startup class (if it already exists, it does not need to be defined). The key codes are as follows:

package com.jt;

@SpringBootApplication
public class ProviderApplication {

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

Step 4: start the startup class, and then brush the nacos service to check whether the service registration is successful, as shown in the figure:

Step 5: stop the SCA provider service, and then constantly refresh the nacos service list to check the health status of the service.

Consumer service discovery and invocation

Step 1: create a service provider object in the SCA provider project and provide external services based on this object, for example:

    package com.jt.provider.controller;
    /**Define the Controller object (this object is defined as handler in spring mvc),
     * Process client requests based on this object*/
    @RestController
    public class ProviderController{
        //@Value reads the content configured in the project configuration file by default
        //8080 means the server is not read Port, the given default value
        @Value("${server.port:8080}")
        private String server;
        //http://localhost:8081/provider/echo/tedu
        @GetMapping("/provider/echo/{msg}")
        public String doRestEcho1(@PathVariable String msg){
            return server+" say hello "+msg;
        }
    }

Step 2: create a service consumer project (the module name is SCA consumer, if it already exists, it does not need to be created), inherit the parent project (01 SCA), and the contents of its pom.xml file are as follows:

<?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">
    <parent>
        <artifactId>01-sca</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>sca-consumer</artifactId>
    
   <dependencies>
    <!--Web service-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--Registration and discovery of services(We're going to talk about service registration nacos)-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    </dependencies>
</project>

Step 3: create the configuration file application. In the SCA consumer service YML, the key codes are as follows:

server:
  port: 8090
spring:
  application:
    name: sca-consumer #When registering a service, the service name must be configured
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Where to find the service

Step 4: create a consumer startup class and realize service consumption. The key codes are as follows:

package com.jt;
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

Step 5: add the following method to SCA consumer startup class to create RestTemplate object  

@Bean
public RestTemplate restTemplate(){//Implement remote service invocation based on this object
    return new RestTemplate();
}

Step 6: define the consumer Controller of SCA consumer service and implement the remote service call within this object method

package com.jt.consumer.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


/**
 * Define the service consumer Controller in this Controller object
 * Implement the call to the remote service SCA provider
 */
@RestController
public class ConsumerController {
    /**
     * Get a RestTemplate object from the spring container,
     * Implement remote service invocation based on this object
     */
    @Autowired
    private RestTemplate restTemplate;
    /**
     * In this method, the service in the remote SCA provider is called through a RestTemplate object
     * @return
     * URL to access this method: http://localhost:8090/consumer/doRestEcho1
     */
    @GetMapping("/consumer/doRestEcho1")
    public String doRestEcho01(){
        //1. Define the url of the remote service to be called
        String url="http://localhost:8081/provider/echo/8090";
        //2. Call the service based on the relevant methods in the restTemplate object
        return restTemplate.getForObject(url, String.class);
    }

}

Step 7: start the consumer service and enter in the browser http://localhost:8090/consumer/doRestEcho1 Address. If the access is successful, it will appear, as shown in the figure:

Section interview analysis

  • Why register the service with nacos? (to better find these services)
  • How do service providers renew their contracts with the Nacos registry in Nacos? (5 second heartbeat)
  • For the Nacos service, how does it determine the status of the service instance? (heartbeat detection package, 15,30)
  • How does the service consumer invoke the services of the service provider? (RestTemplate)

Design and implementation of service load balancing (key)

Business description

A service instance can process requests is limited. If the concurrent access of a service instance is relatively large, we will start multiple service instances and let these service instances process concurrent requests with certain policy balancing (polling, weight, random, hash, etc.). How is the service load balancing (Nacos client load balancing) applied in Nacos?

LoadBalancerClient application

The LoadBalancerClient object can obtain the service instance from nacos based on the service name, and then call the load balancing method based on the characteristic algorithm in the project. The case implementation is as follows:

Step 1: modify the ConsumerController class, inject the LoadBalancerClient object, add the doRestEcho2 method, and then access the service

  @Autowired
  private LoadBalancerClient loadBalancerClient;
  
  @Value("${spring.application.name:8090}")
  private String appName;
   
  @GetMapping("/consumer/doRestEcho02")
 public String doRestEcho02(){
     ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
     String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
     System.out.println("request url:"+url);
     return restTemplate.getForObject(url, String.class);
     }
 }

Step 2: open the Idea service startup configuration, as shown in the figure:

 

Step 3: modify the concurrent Run option (if this option is not found, we need to find the corresponding solution through the search engine based on combined query, such as searching idea allow parallel run), as shown in the figure:

Step 4: modify the configuration file port of SCA provider and start it in the mode of 80818082 port respectively.

server:
  port: 8082
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      server-addr: localhost:8848

Step 5: after successful startup, access the service list of nacos and check whether the service is successfully registered, as shown in the figure:

Step 6: start the SCA consumer project module, open the browser to access the consumer service, refresh constantly during access, and detect the changes of page data, for example:

Note: the way multiple instances provide services concurrently here is load balancing. The default implementation of load balancing here is because Nacos integrates the ribbon. The ribbon can easily access services with RestTemplate. Ribbon is one of the core components of Spring Cloud. The most important function it provides is the load balancing of the client (the client can adopt certain algorithms, such as polling access and accessing the instance information of the server). This function allows us to easily automatically convert the service-oriented REST template requests into service calls in the client load balancing mode.

@LoadBalanced 

When using RestTemplate for remote service calls, if load balancing is required, you can also use @ LoadBalanced to modify the method of building RestTemplate when building RestTemplate object. For example, build a RestTemplate object named loadBalancedRestTemplate in ConsumerApplication:

@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
    return new RestTemplate();
}

Dependency injection is performed where RestTemplate is required to implement load balancing calls For example, add the loadBalancedRestTemplate attribute in the ConsumerController class

@Autowired
private RestTemplate loadBalancedRestTemplate;

Next, in the method of the corresponding service caller, the service can be called with the help of the service name based on RestTemplate, for example:

@GetMapping("/consumer/doRestEcho3")
public String doRestEcho03(){
    String url=String.format("http://%s/provider/echo/%s","sca-provider",appName);
    //Send an http request to the service provider to obtain the response data
    return loadBalancedRestTemplate.getForObject(
            url,//The address of the service to request
            String.class);//String.class is the response result type of the request service
}

RestTemplate will be intercepted by LoadBalancerInterceptor when sending a request. It is used for load balancing of RestTemplate. Loadbalancerinceptor gives the core logic of load balancing to loadBalancer. The core code is as follows (understand):

public ClientHttpResponse intercept(final HttpRequest request, 
    final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
	final URI originalUri = request.getURI();
	String serviceName = originalUri.getHost();
	return this.loadBalancer.execute(serviceName, 
    requestFactory.createRequest(request, body, execution));
}

@The LoadBalanced annotation belongs to Spring, not the Ribbon. When Spring initializes the container, if it detects that the Bean is @ LoadBalanced annotated, Spring will set the interceptor of loadbalancerinceptor for it.

Ribbon load balancing strategy (understand)

Based on Ribbon load balancing, Netflix provides seven load balancing strategies by default. For spring cloud Alibaba solution, it also provides NacosRule strategy. The default load balancing strategy is rotation training strategy. As shown in the figure:

When the load balancing policy provided by the system cannot meet our needs, we can also define our own policy based on IRule interface

Section interview analysis

  • @What is the function of bean annotation? (it is generally used to configure the interior of a class and describe relevant methods. It is used to tell spring that the return value of this method should be managed by spring. The bean name is the method name by default. If you need to specify the name, you can @ Bean("bean name"). The most common application scenario is to integrate third-party resources - objects)
  • @What is the role of Autowired annotations? (this annotation is used to describe attributes, construction methods, set methods, etc. it is used to tell the spring framework to perform DI operations for attributes according to certain rules. By default, the corresponding object is found according to the attribute and method parameter types. If only one is found, it will be injected directly. When there are multiple types, it will also be injected according to the attribute name or method parameter name. If the names are also different, an error will be reported.)
  • How is the bottom layer responsible for balancing in Nacos implemented? (through the Ribbon implementation, some load balancing algorithms are defined in the Ribbon, and then an instance is obtained from the service instance based on these algorithms to provide services for the consumption method)
  • What is Ribbon? (the load balancing client provided by Netflix is generally applied to the service consumption method)
  • What problems can Ribbon solve? (service invocation is based on load balancing policy, and all policies will implement IRule interface)
  • What are the built-in load policies of Ribbon? (8, which can be analyzed by viewing the implementation class of IRule interface)
  • @What is the role of LoadBalanced? (describe the RestTemplate object, which is used to tell the Spring framework that when a service call is made using RestTempalte, the call process will be intercepted by an interceptor, and then start the load balancing policy inside the interceptor.)
  • Can we define our own load balancing strategy? (policy can be defined based on IRule interface or implemented with reference to NacosRule)

 

Feign based remote service invocation (key)

Background analysis

When the service consumer requests the service of the service provider based on rest, a direct way is to splice the url, splice the parameters, and then implement the service call. However, this splicing is required for each service call. The amount of code is complex and difficult to maintain. At this time, Feign was born.

What is Feign

Feign is a declarative Web service client. The bottom layer encapsulates the application of Rest technology. Feign can simplify the call and implementation of remote service provider methods by service consumers. As shown in the figure:

Feign was first maintained by Netflix. Later, Netflix no longer maintained feign. Finally, feign was maintained by some communities and renamed OpenFeign.

Feign application practice (Master)

Step 1: add project dependencies on the service consumer (the SpringCloud team has developed the starter based on OpenFeign). The code is as follows:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>


Step 2: add @ EnableFeignClients annotation on the startup class. The code is as follows:

@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {...}


Step 3: define the Http request API. Based on this API, access the remote service with OpenFeign. The code is as follows:

package com.jt.consumer.service;
@FeignClient(name="sca-provider")//SCA provider is the name of the service provider
public interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//The premise is that the remote end needs this service
    public String echoMessage(@PathVariable("string") String string);
}


Among them, the bottom layer of the interface described by @ FeignClient will create an implementation class for it.

Step 4: create feign consumercontroller and add feign access. The code is as follows:

package com.jt.consumer.controller;
@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**Service invocation based on feign mode*/
    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //Remote service invocation based on feign method (provided that the service must exist)
        return remoteProviderService.echoMessage(msg);
    }
}


Step 5: start the consumer service and access it directly through the feign client in the browser, as shown in the figure (repeatedly refresh and detect the response results):


It shows that for feign remote service invocation, the bottom layer will automatically realize load balancing based on ribbon components.

Feign configuration advanced practice

 

A service provider usually provides many resource services. The service consumer writes many service invocation interfaces based on the same service provider. At this time, if no contextId is specified, the service
The startup will fail. For example, if the following interface is added to the service consumer, the consumer will fail to start when starting, for example:

 @FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}


The startup exceptions are as follows:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.


At this time, we need to specify a contextId for the remote calling service interface as the unique ID of the remote calling service (this ID is the name of the Bean object), for example:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//SCA provider is the name of the service provider
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//The premise is that the remote end needs this service
    public String echoMessage(@PathVariable("string") String string);
}


Also, when we call a remote service, what if the called service is suddenly unavailable or the calling process times out? General service consumers will provide specific fault-tolerant schemes. For example, in Feign applications, default related processing is carried out through the implementation class of FallbackFactory interface, such as:

Step 1: define the implementation of FallbackFactory interface. The code is as follows:

package com.cy.service.factory;
/**
 * Service interruption, timeout and other problems when handling RemoteProviderService interface calls based on this object
 */
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    /**
     * This method will be executed after an exception occurs when the RemoteProviderService interface is called
     * @param throwable Used to receive exceptions
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "In service maintenance,Wait a moment and visit again";
        };
    }
}


Step 2: apply FallbackFactory object in Feign provider, for example:

@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
             fallbackFactory = ProviderFallbackFactory.class)//SCA provider is the service name in nacos
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    public String echoMsg(@PathVariable String msg);
}


Step 3: in the configuration file application Add the following configuration to YML to start the service interrupt processing mechanism when feign mode is called

feign:  
  hystrix:
    enabled: true #The default value is false


Step 4: add thread in the calling method corresponding to the service provider Sleep (5000) simulates time - consuming operations, and then starts the service for access testing

Feign call procedure analysis (understand)

Feign application process analysis (understand the underlying logic first):
1) Tell springcloud through the @ EnableFeignCleints annotation to start the Feign Starter component.
2) Feign Starter will register the global configuration during the project startup, scan the interface described by @ feign client annotation under the package, then create the interface implementation class (JDK proxy class) at the bottom of the system, build the class object, and then hand it over to spring management (register the IOC container).
3) When the feign interface is called, the underlying proxy object will create a Request object based on the Request information in the interface through the encoder, and make remote procedure calls based on this object.
4) Feign client request objects will be load balanced through the Ribbon to select a healthy Server instance.
5) Feign client will call the remote service with Request and return a response.
6) Feign client object parses the Response information and returns it to the client.

Section interview analysis

  • Why use Feign? (based on Feign, service invocation can be implemented more friendly and service consumer's invocation of service provider's methods can be simplified).
  • @What is the function of FeignClient annotation? (tell Feign Starter to create an implementation class proxy class for the interface described in this annotation when the project is started)
  • How is the underlying load balancing implemented for Feign mode calls? (Ribbon)
  • @What is the role of the EnableFeignCleints annotation? (describe configuration classes, such as startup classes)

Summary

Analysis of key and difficult points

FAQ analysis

  • What is Nacos and what features (registration, discovery and configuration of services) it provides?
  • Why did you choose Nacos? (activity, stability, performance, learning cost)
  • Nacos official website? (nacos.io)
  • Nacos source code in GitHub? (github.com/alibaba/nacos)
  • Nacos installed in windows environment? (it can be used after decompression)
  • Initial configuration of Nacos in windows? (application.properties access the data source of the database)
  • The basic process of Nacos service registration? (send web request when service starts)
  • The basic process of Nacos service consumption? (the service gets the service instance at startup and then calls the service).
  • Nacos service load balancing logic and its design and implementation? (Ribbon)
  • What is the core data of the registry? (name of the service and its corresponding network address)
  • Why does the registry use read-write locks to access core data? (bottom safety and performance)
  • How does Nacos health check? (implemented based on heartbeat packet mechanism)
  • How does Nacos ensure high availability? (retry, local cache, cluster)
  • What is the basic function of RestTemplate?
  • What is feign, what is its application, and how is the proxy object created in feign application (JDK)?
  • How is the load balancing of Feign call process implemented? (Ribbon)

Bug analysis

  • JAVA_ The definition of home environment variable is wrong, for example:

    Note: you must pay attention to Java here_ Spelling of home word, Java_ The JDK defined in home exists, and the following path cannot have a semicolon ";"

  • MySQL version is relatively low (mysql5.7 or MariaDB 10.5 or above is recommended), for example:
    When executing Nacos mysql The following error occurred while the SQL file:

  • The sql file does not exist, for example

  • SQL file application error, for example:

  • Nacos application In the properties configuration file, the configuration of connecting to the database is incorrect

  • nacos configuration file application Properties configuration error, for example:

  • The port was occupied when the service was started. For example:

  • During service registration, the service name is incorrect, the format is incorrect, the configuration file name is incorrect, or there is no configuration file, for example:

  • Disk write permission problem (when nacos service starts, logs will be written in the current disk directory), for example:

 

 

  • Service registration based on Nacos failed, for example

  • Client 500 exception, for example

  • Connection exception during service call, for example:

  • The client 404 is abnormal, for example:

  • Underlying 404 problems during service invocation, such as:

  • Service access issues, such as:

  • Dependency injection exception, for example:

  • The client request mode does not match the server, for example:

  • Version dependent problems, such as:

  • Service configuration reading problem, for example:

Classroom tips

  • Start nacos based on idea, for example:
  • Link database database based on idea, for example:
    Step 1: open the DataSource and find mysql, for example:

    Step 2: configure the connected database, for example:

Topics: Java eureka Cloud Native