07 application of service registry Nacos

Posted by karan23424 on Mon, 10 Jan 2022 17:51:29 +0100

1. Introduction to Nacos registry

1.1 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).
The commonly used registration centers on the market are zookeeper (Yahoo, APACHE), Eureka (Netfix), Nacos (Alibaba) and consult (Google). Next, we choose Nacos for learning. Nacos 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.

1.2 overview of Nacos

Nacos (dynamic naming and configuration service) is a platform applied to service registration, discovery and configuration management. It hatched with Alibaba and grew up in the Hongfeng postgraduate entrance examination of the double 11 in the past decade, precipitating the 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

2. Build Nacos service

2.1 download and installation

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:

Step 3: unzip Nacos (do not unzip it to the Chinese directory), and its directory structure is as follows:

2.2 initialization configuration

Step 1: find conf / Nacos mysql The sql script in the sql file, and then log in to MySQL. Based on the description in the script file, create a database (name nacos_config, encoding utf8mb4) and execute the script file. After the script is executed successfully, some tables will be created, as shown in the figure.

Note: when executing this file, the version of mysql must be greater than 5.7 (preferably 10.5.11 for MariaDB), otherwise the following errors will occur.

Step 2: open conf / application Properties and configure the database to connect to based on the current environment. (if there is #, remove it)

### 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
db.password.0=root

2.3 service startup and access

Step 1: start the Nacos service.
Windows startup command (standalone stands for stand-alone mode, non cluster mode):

startup.cmd -m standalone

explain:
1) When executing the command, either configure the environment variable or directly execute it through the cmd command window in the nacos/bin directory.
2) Java needs to be configured in the local environment variable when nacos starts_ Home (the installation directory of the corresponding jdk).
Step 2: access the Nacos service.
Open the browser and enter http://localhost:8848/nacos Address, the following login page appears:

The default account number is nacos, and the default password is nacos.

3. Getting started with service registration and invocation

3.1 business description

Create two project modules: service provider and service consumer. Both of them should be registered in NacosServer (this is essentially a web service, and the default port is 8848). Then the service provider can provide remote calling services for service consumers (for example, payment service is the service provider, and order service is the service consumer), as shown in the figure.

3.2 create Maven parent project

Step 1: create maven module project 05 JT SCA Nacos, which is the parent project of our subsequent project modules. The role of this project is to manage the common dependencies required in the sub modules.
Step 2: import the required core dependencies. The contents of the pom 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>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.cy</groupId>
    <artifactId>06-jt-sca-nacos</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>sca-providers</module>
        <module>sca-consumers</module>
    </modules>

    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8
        </project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8
        </project.reporting.outputEncoding>

        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
        <spring.cloud.alibaba-version>
            2.2.5.RELEASE
        </spring.cloud.alibaba-version>
    </properties>
    <!--Dependency management-->
    <dependencyManagement>
        <dependencies>
            <dependency>
            <!--spring cloud Dependency, this dependency requires springboot The dependency is defined in spring cloud Microservice specification-->
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <!--import Indicates that the subprojects under this project can directly reference the version in this dependency-->
                 <scope>import</scope>
                 <!--When scope by import The type here must be pom type-->
                <type>pom</type>
            </dependency>
            <!--spring cloud alibaba Dependency, which is based on spring cloud´╝îIn the current dependency, the microservice based specification is implemented in detail-->
            <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>
</project>

For the version, please refer to the following website (it involves a compatibility problem, and its version cannot be specified arbitrarily).

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

Finally, after the parent project resource initialization is completed, delete the src directory because the parent project is only responsible for dependency management.

3.3 service provider creation and registration

Step 1: create a service provider to inherit the parent project, and its module name is SCA providers.

Step 2: add project dependencies.

    <dependencies>
        <!--Web service-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Registration and discovery of services()-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

Step 3: create and modify the configuration file application YML to realize service registration.

server:
  port: 8081
spring:
  application:
    name: sca-providers
  cloud:
    nacos:
      server-addr: localhost:8848

Step 4: create the startup class and define the control layer objects and methods to process the request.

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

    @Value("${server.port}")
    private String server;

    @RestController
    public class ProviderController {
        @GetMapping(value = "/provider/echo/{msg}")
        public String doEcho(@PathVariable String msg) throws IllegalAccessException {
            //Use the following statement to default the exceptions in the service invocation process
            if(msg==null||msg.length()<3){
                throw new IllegalAccessException("Illegal parameter");
            }
            return server+"say:Hello Nacos Discovery " + msg;
        }
    }
}

Step 5: start the startup class, refresh the nacos service, and check whether the service is registered successfully.

Step 6: open the browser and enter http://localhost:8081/provider/echo/msg , access.

3.4 discovery and invocation of service consumers

Step 1: create a service consumer to inherit the parent project, and the module name is SCA consumers.
Step 2: add project dependencies.

<dependencies>
        <!--Web service-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.2.RELEASE</version>
        </dependency>
        <!--Registration and discovery of services()-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <!--add to OpenFeign Dependency, based on which remote service calls are made-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

Step 3: modify the configuration file application yml.

server:
  port: 8091
spring:
  application:
    name: sca-consumer
  cloud:
    nacos:
      disconvery:
        server-addr: localhost:8848  #Where to check the service

feign: #Enable the exception handling mechanism during feign service invocation
  hystrix:
    enabled: true #The default value is false

Step 4: create a startup class and realize service consumption.

@SpringBootApplication
@EnableFeignClients //Start feign mode service call
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

    @Value("${server.port}")
    private String server;

    //Build a remote procedure call object and access the remote object based on this object

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

    //Building load balanced remote procedure call objects
    @Bean
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate(){
        return new RestTemplate();
    }

    @RestController
    public class ConsumerController{

        @Autowired
        private RestTemplate restTemplate;

        /**
         Load balancing client object:
         Based on this object, you can get a service instance from the registry
         */
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        /**
         * RestTemplate object with load balancing applied
         */
        @Autowired
        private RestTemplate loadBalancedRestTemplate;

        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho1(){
            /**
             * explain:
               Remote service invocation is based on RestTemplate, but it does not have load balancing feature. This method does not need nacos,
               Service calls are made directly through fixed ip and ports, which is not suitable for multi service instance calls.
             */

            String url ="http://localhost:8081/provider/echo/" +server;
            //Remote call
            return restTemplate.getForObject(url, String.class);//String.class is the data type of the call service response
        }

        @GetMapping("/consumer/doRestEcho2")
        public String doRestEcho2(){
            /**
             * explain:
               The remote service call is based on RestTemplate, but before the call, the service name is searched from the nacos center based on the loadBalancedClient object
               There may be multiple service instances. At this time, the service instance will be selected locally according to a certain algorithm, and then the service will be called.
             */

            //Find a service instance based on the service name (the name in the service table in nacos)
            ServiceInstance choose = loadBalancerClient.choose("sca-providers");
            String ip = choose.getHost();//Get ip address
            int port = choose.getPort();//Get port number
            //Build url for remote call
            /*Method 1:
            String url = "http://"+ip+":"+port+"provider/echo/"+server;*/
            //Method 2:
            String url = String.format("http://%s:%s/provider/echo/%s", ip,port,server);
            //Remote call RPC
            return restTemplate.getForObject(url, String.class);
        }

        @GetMapping("/consumer/doRestEcho3")
        public String doRestEcho3(){
            /**
             * explain:
               The RestTemplate based on the load balancing feature performs remote service calls. The functions are the same as mode 2, but the code is simplified.
              In terms of efficiency, it will be slightly inferior to mode 2, because the bottom layer will intercept the request, and then obtain it based on loadBalancedClient
              Service instance.
             */

            String url = String.format("http://%s/provider/echo/%s", "sca-provider",server);
            return loadBalancedRestTemplate.getForObject(url , String.class);
        }

    }
}

Step 5: start the consumer service and enter in the browser: http://localhost:8091/consumer/doRestEcho1 , access. If the access is successful, the effect is as shown in the figure.

3.5 summary interview analysis

  • Why register the service with nacos? (to better find these services)
  • In Nacos, how does a service provider renew its contract with the Nacos registry? (5 second heartbeat)
  • For the Nacos service, how does it determine the status of the service instance? (heartbeat detection package, 15,30)
  • How to find the service startup registration configuration class when starting a service? (NacosNamingService)
  • How does the service consumer invoke the services of the service provider? (RestTemplate)

4. Design and implementation of service load balancing

4.1 introduction cases

The requests that a service instance can handle are limited. If the concurrent access of a service instance is relatively large, we will start multiple service instances and let these service instances use certain strategies to balance (polling, weight, random, hash, etc.) to process concurrent requests. Next, we will learn the application of load balancing in Nacos service (Nacos client load balancing).

4.2 realization process

Step 1: modify the ConsumerController class, inject the LoadBalancerClient object, add the dorestloadbalancerclientrecho method, and then access it.

         /**
         Load balancing client object:
         Based on this object, you can get a service instance from the registry
          */
        @Autowired
        private LoadBalancerClient loadBalancerClient;

		@GetMapping("/consumer/doRestEcho2")
        public String doRestEcho2(){
            /**
             * explain:
               The remote service call is based on RestTemplate, but before the call, the service name is searched from the nacos center based on the loadBalancedClient object
               There may be multiple service instances. At this time, the service instance will be selected locally according to a certain algorithm, and then the service will be called.
             */

            //Find a service instance based on the service name (the name in the service table in nacos)
            ServiceInstance choose = loadBalancerClient.choose("sca-providers");
            String ip = choose.getHost();//Get ip address
            int port = choose.getPort();//Get port number
            //Build url for remote call
            /*Method 1:
            String url = "http://"+ip+":"+port+"provider/echo/"+server;*/
            //Method 2:
            String url = String.format("http://%s:%s/provider/echo/%s", ip,port,server);
            //Remote call RPC
            return restTemplate.getForObject(url, String.class);
        }

Step 2: open the IDEA service startup configuration.

Step 3: modify the concurrent Run option: check Allow parallel run.

Step 4: modify the configuration file port of SCA provider and start it in the port mode of 80818082 respectively.
Step 5: after successful startup, access the service list of nacos to check whether the service is registered successfully.
Step 6: start the SCA consumer project module, open the browser, and enter the following URL for repeated service access.

http://localhost:8091/consumer/doRestEcho2

Then you will find that both services of SCA providers can handle SCA consumers' requests.

4.3 analysis

Here, multiple instances provide services concurrently by load balancing. In addition, load balancing is implemented by the default Nacos integrated 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 use certain algorithms, such as polling to access the instance information of the server). This function allows us to easily automatically convert the request of the service-oriented REST module into the service call of the client load balancing mode.

4.4 @LoadBalanced

When using RestTemplate for remote service calls, if load balancing is required, you can use @ LoadBalanced to modify the method of building RestTemplate when building RestTemplate objects, for example:

 //Building load balanced remote procedure call objects
    @Bean
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate(){
        return new RestTemplate();
    }

Dependency injection is performed where the RestTemplate is required to implement load balancing calls.

        /**
         * RestTemplate object with load balancing applied
         */
        @Autowired
        private RestTemplate loadBalancedRestTemplate;

Next, you can call the method at the corresponding service consumer and call the service with the service name based on RestTemplate.

 @GetMapping("/consumer/doRestEcho3")
        public String doRestEcho3(){
            /**
             * explain:
               The RestTemplate based on the load balancing feature performs remote service calls. The functions are the same as mode 2, but the code is simplified.
              In terms of efficiency, it will be slightly inferior to mode 2, because the bottom layer will intercept the request, and then obtain it based on loadBalancedClient
              Service instance.
             */

            String url = String.format("http://%s/provider/echo/%s", "sca-provider",server);
            return loadBalancedRestTemplate.getForObject(url , String.class);
        }

RestTemplate will be intercepted by loadbalancerinceptor when sending a request. Its function is to balance the load of RestTemplate. Loadbalancerinceptor gives the core logic of load balancing to loadBalancer.
@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.

4.5 Ribbon load balancing strategy

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.

4.6 summary 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 a name, you can @ Bean("bean name"), and 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 objects are found according to attribute and method parameter types. If only one is found, it will be injected directly. When there are multiple types, it will also inject values according to attribute names or method parameter names. 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)