Spring Boot uses Apache cursor to register and discover services. "Chapter 4: ZooKeeper cursor application scenario practice" and "architecture road ZooKeeper theory and practice"

 

Related historical articles (you may need to read the previous series before reading this article 👇)

The most complete Spring in China   Boot Series IV

Sharing mode: sharing girlfriend  -  Part 355

What is?   ZooKeeper  -  Part 347

ZooKeeper installation  -  Chapter 348

ZooKeeper data structure and operation   -  Part 349

watch mechanism of ZooKeeper  -  Part 350

acl permission control of ZooKeeper   -  Part 351

ZooKeeper memory data and persistence   -  Part 352

ZooKeeper cluster construction  -  Part 354

ZooKeeper   Basic use of Java client  -  Part 356

ZooKeeper client Curator  -  Part 358

Advanced use of ZooKeeper client Curator  -  Part 359

ZooKeeper client and cursor implement Watch event listening  -  Part 361

Spring Boot using cursor to operate ZooKeeper - Chapter 363

Spring Boot uses Apache cursor to realize service registration and discovery - Part 364
Spring Boot uses Apache cursor to implement distributed locks (reentrant exclusive locks) - Chapter 365

Spring Boot uses Apache cursor to implement leader election - Chapter 366

Spring Boot uses Apache cursor to implement distributed counters - 367 articles

Fundamentals of ZooKeeper Session - Chapter 369

ZooKeeper bucket splitting strategy for high performance session management - Chapter 371

ZooKeeper cluster architecture and read-write principle - Chapter 372

The election principle of ZooKeeper Leader is just the same. After reading this article, you will no longer be confused - Chapter 374

Why should Zookeeper cluster nodes be deployed in odd numbers? - Chapter 376

ZooKeeper cluster cleft brain problem - Chapter 379

Distributed consistency algorithm Paxos, ZAB protocol of ZooKeeper - Part 381

 

Earlier, we integrated cursor into the Spring Boot project. In this section, we take a look at one of the application scenarios supported by cursor: registration and discovery of services in the registry

1, Basic concepts and ideas

1.1 registry / service registration / service discovery concept

1.1.1 Registration Center

The registry can be said to be the "address book" in the micro service architecture, which records the mapping relationship between services and service addresses. In the distributed architecture, services will register here. When services need to call other services, they will find the service address here and call.

       We don't need to code the registration center here. ZooKeeper is a registration center. I store the service information in the registration center.

1.1.2 service registration

       It is to register the module information of a service (usually the ip and port of the service) to a public component (such as zookeeper / consumer).

1.1.3 service discovery

Service discovery, in short, means that consumers go to the registration center to query which services are registered, how many instances of services are there, which are healthy and which are unavailable.

1.2 Curator Service Discovery

Cursor Service Discovery is designed to solve this problem. It abstracts three interfaces: ServiceInstance, ServiceProvider and ServiceDiscovery. Through it, we can easily implement Service Discovery.

1.3 ideas

       The general idea of using cursor service discovery is:

(1) Import dependency package: cursor-x-discovery-server

(2) Use ServiceDiscovery to discover and register services.

(3) The class of service entity is ServiceInstance, and the class that constructs ServiceInstance is ServiceInstanceBuilder.

2, Cursor's service registration and service discovery practice

       No matter how much you say, it's better to operate it in practice.

2.1 environmental description

(1) The coding is based on the previous section "Spring Boot using cursor to operate ZooKeeper".

(2) ZooKeeper version: 3.6.2

(3) Cursor version: 5.1.0

(4) For ordinary java projects, the code for service discovery and registration is the same, as long as the CuratorFramework can be obtained.

2.2 adding dependencies

       In the pom.xml file, the dependency curator-x-discovery is added, and the original dependency curator recipes is added. Now the core dependency is:

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-x-discovery</artifactId>
    <version>5.1.0</version>
</dependency>

2.3 service details

       When constructing a service instance ServiceInstance, we are allowed to customize some other service information. Here we call it ServiceDetail:

package com.kfit.springbootcuratordemo.register;

/**
 * Service details
 *
 * @author The "official account SpringBoot"
 * @date 2021-03-25
 * @slogan Great road to simple enlightenment in Tiancheng
 */
public class ServiceDetail {
    //Root path of service registration
    public static final String REGISTER_ROOT_PATH = "/apps";

    private String desc;
    private int weight;

    @Override
    public String toString() {
        return "ServiceDetail{" +
                "desc='" + desc + '\'' +
                ", weight=" + weight +
                '}';
    }

    public ServiceDetail() {
    }

    public ServiceDetail(String desc, int weight) {
        this.desc = desc;
        this.weight = weight;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

2.4 service registration and service discovery

       Here, service registration and service discovery are managed in one class. The specific code is as follows:

package com.kfit.springbootcuratordemo.register;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
import org.apache.curator.x.discovery.ServiceInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.net.InetAddress;
import java.util.Collection;

/**
 * TODO
 *
 * @author The "official account SpringBoot"
 * @date 2021-03-25
 * @slogan Great road to simple enlightenment in Tiancheng
 */
@Service
public class RegisterService {

    //Environmental information
    @Autowired
    private Environment environment;

    //Curator client
    @Autowired
    private CuratorFramework curatorFramework;

    /**
     * Service registration: register the currently started service information (ip+port) into zk.
     */
    public void register(){
        try {
            //address.getHostAddress(): 192.168.0.106
            InetAddress address = InetAddress.getLocalHost();
            ServiceInstance<ServiceDetail> instance = ServiceInstance.<ServiceDetail>builder()
                    .address(address.getHostAddress())//ip address: 192.168.0.106
                    .port(Integer.parseInt(environment.getProperty("local.server.port")))//port:8080
                    .name("userService") //Name of the service
                    .payload(new ServiceDetail("User services", 1))
                    .build();

            ServiceDiscovery<ServiceDetail> serviceDiscovery = ServiceDiscoveryBuilder.builder(ServiceDetail.class)
                    .client(curatorFramework)
                    //. serializer() / / serialization method
                    .basePath(ServiceDetail.REGISTER_ROOT_PATH)
                    .build();

            //Service registration
            serviceDiscovery.registerService(instance);
            serviceDiscovery.start();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * Service discovery: query services through serviceDiscovery
     */
    public void discovery(){
        try {
            ServiceDiscovery<ServiceDetail> serviceDiscovery = ServiceDiscoveryBuilder.builder(ServiceDetail.class)
                    .client(curatorFramework)
                    .basePath(ServiceDetail.REGISTER_ROOT_PATH)
                    .build();
            serviceDiscovery.start();

            //Get service by name
            Collection<ServiceInstance<ServiceDetail>> services = serviceDiscovery.queryForInstances("userService");
            for(ServiceInstance<ServiceDetail> service : services) {
                System.out.print(service.getPayload()+" -- ");
                System.out.println(service.getAddress() + ":" + service.getPort());
            }
            System.out.println();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}

2.5 start registration on zk

       After the application starts successfully, register on zk:

package com.kfit.springbootcuratordemo;

import com.kfit.springbootcuratordemo.register.RegisterService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SpringbootCuratorDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringbootCuratorDemoApplication.class, args);

        //Register the service
        RegisterService registerService = ctx.getBean(RegisterService.class);
        registerService.register();

        //Testing: Service Discovery
        while (true){
            registerService.discovery();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }



}

2.6 start up test

       First start the zk server service, and then start the spring boot application.

       Modify the property server.port=8081 of application.properties and start the application again.

       Observe the printed information of the console:

 

       The application started first can only find the service published by itself at the beginning. When another application starts, it can listen to other service information.

       At this time, let's look at the node information of zk server:

       You can see that there are two nodes under userService /. Let's look at the following data:

get /curator/apps/userService/260508a9-83c8-4d95-bdf6-8879888a6600

        The data returned is:

{"name":"userService","id":"260508a9-83c8-4d95-bdf6-8879888a6600","address":"192.168.0.106","port":8080,"sslPort":null,"payload":{"@class":"com.kfit.springbootcuratordemo.register.ServiceDetail","desc":"User services","weight":1},"registrationTimeUTC":1616657422516,"serviceType":"DYNAMIC","uriSpec":null}

       When we close an application, we can only find one service in an instant, and there are fewer nodes on the zk server.

3, Explore the service registration and service discovery of cursor

3.1 what types of nodes are used for service registration

 

       From here, the node for each service is a temporary node. What are the characteristics of the temporary node? That is, when our session is disconnected from the server, the node will be deleted.

3.2 service registration source code analysis

       We follow up the method serviceDiscovery.registerService(instance), which can be found

Org.apache.cursor.x.discovery.details.servicediscoveryimpl#internalregisterservice contains the following code:

       The code for creating the node core here is the following sentence:

client.create().creatingParentContainersIfNeeded().withMode(mode).forPath(path, bytes);

       The parent node is a container node. Do you remember the characteristics of the container node? Here, I'll help you review:

The container node is used to store child nodes. If the child node in the container node is 0, the container node will be deleted by the server in the future. The scheduled task is executed every 60 seconds by default.

       We can delete all applications to see if the parent node is automatically deleted.

       Wait 60 seconds to see if the parent node has been deleted.

       After a while, apps will be deleted, and / curator will be deleted after a while.

       withMode passes in the parameter mode. The mode is judged in the switch case. We do not specify the ServiceType. What is the default value? You can follow it and see that the default value is set in the construction method of ServiceInstance: ServiceType.DYNAMIC.

       Therefore, the node for each service is a temporary node.

4, Summary

       Finally, we summarize the content of this paper:

(1) To register and discover services using curator, you need to add a dependency curator-x-discovery. The core class is ServiceDiscovery.

(2) The created parent node is a container node, which will be deleted after 60 seconds when there are no child nodes; The node of the created service instance is a temporary node and will be deleted immediately when the session is disconnected/ Container node / temporary node

 

I am me, fireworks of different colors.
I am me, a different little apple.

Long Wukong College: Wukong College

There is Spring in the college   Boot related courses!!

SpringBoot Video: Learn Spring Boot Plus from scratch - Netease cloud class

SpringBoot communication platform: https://t.cn/R3QDhU0

Springsecurity 5.0 Video: Permission management spring security - Netease cloud class

ShardingJDBC sub database and sub table: Sharding JDBC practice - Netease cloud classroom

Distributed transaction solutions: Distributed transaction solution "handwritten code" - Netease cloud classroom

JVM memory model tuning practice: In depth understanding of JVM memory model / tuning practice - Netease cloud class

From getting started to mastering Spring: Spring zero foundation from introduction to mastery - Netease cloud classroom

Big talk design pattern love you: Talk about the design mode of loving you for 10000 years - Netease cloud classroom

 

Tags: Apache Spring Zookeeper

Posted on Mon, 13 Sep 2021 15:38:23 -0400 by rachelkoh