8. Chapter 8 of spring cloud, upgrade, service registration and discovery Eureka, Zookeeper and Consule

Chapter 7 of spring cloud, upgrade, service registration and discovery Eureka, Zookeeper and Consule

1, Basic concepts

1. Service governance

In the traditional remote RPC remote call framework, it is very complex to manage the dependency between each service and service. So we need to use service governance to manage services and services
The dependency between services can realize service invocation, load balancing, fault tolerance, etc. Realize service registration and discovery.

Eureka module is used to implement service governance

2. Service registration and discovery

Eureka adopts CS design architecture,
Eureka Server is the server of service registration function. It is the service registry. Other services in the system use Eureka's client to connect to
Eureka Server and maintain the heartbeat link. In this way, the maintenance personnel of the system can monitor whether the microservices in the system are normal through Eureka Server
Function.

In service registration and discovery, there is a registry. When the server is started, the current server information, such as the service address, will be aliased
Register to the registry. On the other hand, the service consumer obtains the actual service address in the registry in the way of the alias, and then realizes the local RPC call.

The design idea of RPC remote call framework is: Registry. Because the registry is used to manage the dependencies between each service and service.
In any RPC remote call framework, there will be a registry (for service address related information).

 

Two, Eureka

Eureka includes two components Eureka Server and Eureka Client. Eureka Server provides service registration service. Eureka Client is accessed through the registry.

<!--Eureka Server-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<!--Eureka Client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Eureka Server provides service registration service.
	After the microservice nodes are started through configuration, they will be registered in EurekaServer. In this way, the service registry in EurekaServer will store all
The information of each service node can be directly seen in the interface.

Eureka Client is accessed through the registry.
	It is a java client, which is used to simplify the interaction of Eureka server. The client also has a built-in polling round robin load
Load balancer of the algorithm. After the application is started, the heartbeat will be sent to EurekaServer (the default cycle is 30s). If EurekaServer does not receive the heartbeat of a node in multiple heartbeat cycles, EurekaServer will remove the service node from the service registry (the default is 90s).

1. Single machine Eureka service construction

1.1. Eureka construction

new maven module

moduleName   cloud-Eureka-server-7001
parentProject  cloud_2020
groupId      com.lee.springcloud
artifactId    cloud_2020
packaging     jar

POM

<?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>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-Eureka-server-7001</artifactId>

    <dependencies>
        
        <!--eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        
		<!--springboot-->
        <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>
        
        <!--General configuration-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 7001

eureka:
  instance:
    hostname: localhost 
  client:
    register-with-eureka: false #Does not register itself with the registry
    fetch-registry: false #No need to go to the registry to get other services
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka / ා stand alone points to itself

Main boot class

package com.lee.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

//This is Eureka server
@EnableEurekaServer
@SpringBootApplication
public class EurekaMain7001 {

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

Test:

http://localhost:7001/

Next, we will inject both the provider of the service and the consumer of the service into eureka

1.2. cloud-provider-payment-8001 construction

POM add

<!--Eureka client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml add

eureka:
  client:
    register-with-eureka: true #Register yourself with eureka server
    fetch-registry: true #You need to go to the registration center to get the address of other services
    service-url:
      defaultZone: http://localhost:7001/eureka point to Eureka service registry
      
#The original configuration indicates the service name when registering with Eureka server
spring:
  application:
    name: cloud-payment-service #Own service name

Add main startup class

//Indicates that it is the client of Eureka
@EnableEurekaClient

Test:

##Start eureka provider, refresh Eureka to see if it is registered
http://localhost:7001/

1.3. cloud-consumer-order-80 construction

Almost the same as cloud-provider-payment-8001

POM add

<!--Eureka client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml add

spring:
  application:
    name: cloud-consumer-order #Indicates the name of your own service when you register with Eureka server
eureka:
  client:
    register-with-eureka: true #Register yourself with eureka server
    fetch-registry: true #You need to go to the registration center to get the address of other services
    service-url:
      defaultZone: http://localhost:7001/eureka ා points to Eureka service registry

Add main startup class

//Indicates that it is the client of Eureka
@EnableEurekaClient

Test:

##Start eureka provider and consumer, refresh Eureka to see if it is registered
http://localhost:7001/

1.4. Modify the consumer access mechanism

The original method for consumer order to access provider payment is to use RestTemplate to directly access by specifying the provider's real address (Eureka is not involved in it):

private static final String PAYMENT_URL = "http://localhost:8001/";

restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);

restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class, id);

Now, we need to register consumer order with Eureka through provider payment, find the real address of provider payment in Eureka server, and then visit (Eureka participates in it):

Now modify the controller of consumer order as follows:

package com.lee.springcloud.controller;

import com.lee.springcloud.entities.CommonResult;
import com.lee.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@RequestMapping("/consumer")
public class OrderController {

    //This is the real path of provider-payment-8001
    //private static final String PAYMENT_URL = "http://localhost:8001/";

    //This is the "service name" registered by provider-payment-8001 in Eureka Server
    private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;

    @PostMapping("/payment/create")
    public CommonResult<Payment> create(@RequestBody Payment payment) {
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class, id);
    }



}

Modify the configuration class as follows:

package com.lee.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * Configuration class
 */
@Configuration
public class ApplicationContextConfig {


    //With this annotation, RestTemplate has client load balancing capability
    //This annotation must be added, otherwise java.net.unknownhostexception: closed-payment-service
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

Test:

##Start Eureka provider consumer

http://localhost/consumer/payment/get/2

Result:

<CommonResult>
    <code>200</code>
    <message>Data query succeeded :Payment(id=2, serial=002)</message>
    <data/>
</CommonResult>

2. Eureka cluster construction

In order to prevent the single node failure of Eureka service and realize high availability, we need to build Eureka cluster.

2.1,cloud-Eureka-server-7002

Refer to cloud-Eureka-server-7001 to create cloud-Eureka-server-7002

host file modification

#Path C:\Windows\System32\drivers\etc\hosts

127.0.0.1  eureka7001.com
127.0.0.1  eureka7002.com

application.yml file modification

##cloud-Eureka-server-7001 is configured as follows:
server:
  port: 7001

spring:
  application:
    name: cloud-eureka-server #eureka server instance name
eureka:
  instance:
    hostname: eureka7001.com   #In fact, it's still localhost
  client:
    register-with-eureka: false #Does not register itself with the registry
    fetch-registry: false #Don't go to the registration center to get the address of other services
    service-url:
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka / ා stand alone points to itself
      defaultZone: http://eureka7002.com:7002/eureka? Cluster points to another Eureka Server service address
      
      
      
      
##cloud-Eureka-server-7002 is configured as follows:
server:
  port: 7002

spring:
  application:
    name: cloud-eureka-server #eureka server instance name
eureka:
  instance:
    hostname: eureka7002.com #In fact, it's still localhost
  client:
    register-with-eureka: false #Does not register itself with the registry
    fetch-registry: false #Don't go to the registration center to get the address of other services
    service-url:
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka / ා single machine points to itself
      defaultZone: http://eureka7001.com:7001/eureka? Cluster points to another Eureka Server service address


Test:

Visit: http://localhost:7001 / and http://localhost:7002/

Result:

Page appears separately
DS Replicas
	eureka7002.com
and
DS Replicas
	eureka7001.com

2.2. Modify cloud-provider-payment-8001 cluster

Modify application.yml as follows:

eureka:
  client:
    register-with-eureka: true #Register yourself with eureka server
    fetch-registry: true #You need to go to the registration center to get the address of other services
    service-url:
      #defaultZone: http://localhost:7001/eureka ා stand alone point to Eureka service registry
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002:7002.com/eureka ා cluster execution Eureka service registry

2.3. Modify cluster in cloud consumer order-80

Modify application.yml as follows:

Ditto

eureka:
  client:
    register-with-eureka: true #Register yourself with eureka server
    fetch-registry: true #You need to go to the registration center to get the address of other services
    service-url:
      #defaultZone: http://localhost:7001/eureka ා stand alone point to Eureka service registry
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002:7002.com/eureka ා cluster points to Eureka service registry

2.4. Create cloud-provider-payment-8002

Refer to cloud-provider-payment-8001 to create cloud-provider-payment-8002

In order to distinguish between 8001 and 8002, their controller s are modified as follows

@Slf4j
@RequestMapping("/payment")
@RestController
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    //To distinguish which 8001 and 8002 provider s are called
    @Value("${server.port}")
    private String serverPort;


    @PostMapping("/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        log.info("Insert data's ID:\t" + payment.getId());
        log.info("Insert results:" + result);
        if (result > 0) {
            return new CommonResult(200, "Insert data successful serverPort:"+serverPort +result);
        } else {
            return new CommonResult(444, "Insert data failed serverPort"+serverPort, null);
        }
    }

    @GetMapping("/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        log.info("***Query results O(∩_∩)O Ha-ha~: " + payment);
        if (payment != null) {
            return new CommonResult(200, "Data query succeeded serverPort:"+serverPort + payment);
        } else {
            return new CommonResult(444, "No corresponding record serverPort"+serverPort, null);
        }
    }
}

Test:

##Launch eureka7001 eureka7002 provider8001 provider8002 consumer respectively to access as follows:

http://localhost:7001/
http://localhost:7002/
http://localhost/consumer/payment/get/2

Result:

Explain:
When visiting http://localhost/consumer/payment/get/2, polling calls the controller s of 8001 and 8002
From the print information, you can see:
{"code":200,"message": "query data successfully serverPort:8002 Payment(id=2, serial=002)","data":null}
{"code":200,"message": "query data successfully serverPort:8001 Payment(id=2, serial=002)","data":null}

3. Consummation of actor microservice information

POM

<!--This configuration has been added-->
<!--springboot-->
<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>

Application.yml NEW

eureka:
	instance:
		instance-id: cloud-provider-payment-8001
		prefer-ip-address: true #Show service IP address or not
		
#Other services are similar

4. Eureka service discovery

eureka service discovery is a service that exposes the service name, address, port, etc. registered in eureka

Take cloud-provider-payment-8001 as an example:

Add a DiscoveryController class

package com.lee.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
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;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/eureka")
public class DiscoveryController {

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/discovery")
    public Object discovery(){
        List<String> services = discoveryClient.getServices();
        for(String s: services){
            log.info("==================================");
            log.info("----->service :"+s);
            List<ServiceInstance> instances = discoveryClient.getInstances(s);
            for (ServiceInstance si : instances){
                log.info("   ---->"+si.getServiceId()+"  "+si.getInstanceId()+"  "+si.getHost()+"  "+si.getPort()+"  "+si.getUri());
            }
            log.info("==================================");
        }
        return this.discoveryClient;
    }
}

Start class add annotation

package com.lee.springcloud;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

//Service discovery
@EnableDiscoveryClient
//Indicates that it is the client of Eureka
@EnableEurekaClient
@SpringBootApplication
@MapperScan("com.lee.springcloud.dao")
public class PaymentMain8001 {

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

Test:

http://localhost:8001/eureka/discovery

Result:

Browser print:
{"services":["cloud-consumer-order","cloud-payment-service"],"order":0}


console printing:
: ==================================
: ----->service :cloud-consumer-order
:    ---->CLOUD-CONSUMER-ORDER  cloud-consumer-order-80  192.168.0.117  80  http://192.168.0.117:80
: ==================================
: ==================================
: ----->service :cloud-payment-service
:    ---->CLOUD-PAYMENT-SERVICE  cloud-provider-payment-service-8002  192.168.0.117  8002  http://192.168.0.117:8002
:    ---->CLOUD-PAYMENT-SERVICE  cloud-provider-payment-service-8001  192.168.0.117  8001  http://192.168.0.117:8001
: ==================================

5. Eureka self protection

5.1 overview:

The protection mode is mainly used for the protection of a group of Eureka clients and Eureka servers with network partition.

   Once in protected mode: eureka server will try to protect the information in its service registry, and no longer delete the data in the service registry, that is
No microservices will be unregistered.
	
	In other words, when a microservice is unavailable at a certain time, the eureka server will not clean up immediately, but will still save the service information.

	AP: A high availability P partition fault tolerance in CAP principle

1. Why does eureka self-protection mechanism come into being?
	In order to prevent the normal operation of the eureka client, but it is not connected to the eureka server network, the eureka server will immediately
Elimination of eureka client service.

2. What's the self-protection model?
	By default, if the eureka server does not receive the heartbeat (60s) of a microservice instance within a certain period of time, the eureka server will
Unregister the instance.
	However, when the network partition fails (delay, jam, congestion), the micro service and eureka server cannot communicate normally, and the above behaviors may become very dangerous. -----Because the microservice itself is very healthy, this service should not be unregistered at this time.
	eureka solves this problem through "self-protection mode": when eureka server loses too many clients in a short time (network partition failure may occur
Then the eureka server node will enter the self-protection mode.

	It is better to keep the wrong service registration information than to blindly log off any possible healthy service instance. Using self-protection mode to make eureka cluster more robust
And stability.

5.2 relevant configuration

###################Eureka Server#############################
#true by default, enabling eureka self-protection mechanism
eureka.server.enable-self-preservation=true
# Interval time between scan failure services (in milliseconds, the default is 60 * 1000), i.e. 60 seconds
eureka.server.eviction-interval-timer-in-ms=5000
#Set the default waiting time of eureka server synchronization failure 5 points
#During this time, it does not provide service registration information to clients
eureka.server.wait-time-in-ms-when-sync-empty=5
#Set the number of retries for eureka server synchronization failure to 5 by default
eureka.server.number-of-replication-retries=5
#Self protection coefficient (default 0.85)
eureka.server.renewal-percent-threshold=0.49

##################Eureka client###############################
#Time interval between sending heartbeat from Eureka client to server, in seconds (default is 30 seconds)
eureka.instance.lease-renewal-interval-in-seconds=30
#The maximum waiting time of Eureka server after receiving the last heartbeat, in seconds (the default is 90 seconds), timeout rejection service
eureka.instance.lease-expiration-duration-in-seconds=90

3, Zookeeper

Zookeeper is a distributed coordination tool, which can replace Eureka to realize the function of registry.

Because some companies are changing their projects from dubbo to spring cloud, zookeeper has also become a registry choice.

Only the stand-alone configuration of zookeeper is mentioned here.

1. Zookeeper simple installation

##download
1>,wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.9/zookeeper-3.4.14.tar.gz

##decompression
2>,tar -zxvf zookeeper-3.4.9.tar.gz

##rename
3>,mv zookeeper-3.4.9 zookeeper

##move
4>,mv zookeeper /opt/

5>,Modify profile

cd /opt/zookeeper/conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/opt/zookeeper/data/data
# the port at which the clients will connect
clientPort=2181
dataLogDir=/opt/zookeeper/data/log
server.1=localhost:2888:3888

6>,start-up
./zkServer.sh start

7,Close
./zkServer.sh stop

8,Other
//For example, the firewall configuration of 2181 aliesc will not be explained in detail

2. Create cloud-provider-payment-8004

new maven module

moduleName   cloud-provider-payment-8004
parentProject  cloud_2020
groupId      com.lee.springcloud
artifactId    cloud_2020
packaging     jar

The POM file of the parent project will have multiple labels after creation

Incorrect POM presentation

<?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>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <artifactId>cloud-provider-payment-8004</artifactId>

    <dependencies>

        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>


        <!--SpringBoot integration Zookeeper The client is actually here zk Will produce jar Package conflict-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>

        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

application.yml

server:
  port: 8004

spring:
  application:
    name: cloud-provider-payment # Service alias - name of registering zookeeper to the registry
  cloud:
    zookeeper:
      connect-string: zk Server IP:2181

Main boot class

package com.lee.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * This annotation is used to register services when using consumer or zookeeper as the registry
 * It can also be used for external service exposure service discovery
 */
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentZkMain8004 {

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

Controller

package com.lee.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
 * There are no more ways to write service s like cloud-provider-payment-8001 and 8002
 * Write a controller method directly
 */
@Slf4j
@RestController
public class PaymentController {

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

    @RequestMapping(value = "payment/zk")
    public String paymentZk() {
        log.info("SpringCloud with zookeeper:----->"+serverPort);
        return "SpringCloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
    }

}

test

Start ZK
Start cloud-provider-payment-8004

Report jar package conflict

Solution: modify POM

<!--SpringBoot integration Zookeeper Client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <exclusions>
        <!--Exclude the self-contained zookeeper3.5.3-->
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!--Add to zookeeper 3.4.9 Version, same zk Server version consistent-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.9</version>
    <type>pom</type>
</dependency>

Result:

{
  "name": "cloud-provider-payment",
  "id": "64c897d0-85ef-42ab-854d-424adae6ebc9",
  "address": "DESKTOP-3H86HI9",
  "port": 8004,
  "sslPort": null,
  "payload": {
    "@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
    "id": "application-1",
    "name": "cloud-provider-payment",
    "metadata": {}
  },
  "registrationTimeUTC": 1585305270235,
  "serviceType": "DYNAMIC",
  "uriSpec": {
    "parts": [
      {
        "value": "scheme",
        "variable": true
      },
      {
        "value": "://",
        "variable": false
      },
      {
        "value": "address",
        "variable": true
      },
      {
        "value": ":",
        "variable": false
      },
      {
        "value": "port",
        "variable": true
      }
    ]
  }
}

3. Create cloud-consumer-order-81

new maven module

moduleName   cloud-consumer-order-81
parentProject  cloud_2020
groupId      com.lee.springcloud
artifactId    cloud_2020
packaging     jar

The POM file of the parent project will have multiple labels after creation

POM

<?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>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order-81</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--SpringBoot integration Zookeeper Client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <!--Exclude the self-contained zookeeper3.5.3-->
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--Add to zookeeper3.4.9 Edition-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 81
spring:
  application:
    # Server Alias
    name: cloud-consumer-order
  cloud:
    zookeeper:
      # Register to zookeeper address
      connect-string: zk The server IP:2181

Main boot class

package com.lee.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * This annotation is used to register services when using consumer or zookeeper as the registry
 * It can also be used for external service exposure service discovery
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerZkMain81 {

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

config

package com.lee.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

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

}

controller

package com.lee.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Slf4j
@RestController
public class OrderController {

    public static final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/zk")
    public String paymentInfo() {
        return restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
    }


}

test

start-up zk,cloud-provider-payment-8004,cloud-consumer-order-81
//Browse:
http://localhost:81/consumer/payment/zk
//Result:
SpringCloud with zookeeper:8004 05acbb42-6e89-4803-bc99-6f8117bc1ecc

Knowledge points:

The nodes registered by each microservice in zookeeper are: temporary nodes.

Four, Consul

1. Overview of Consul

Consumer is an open source distributed service discovery and configuration management system.
Consumer provides services governance, configuration center, control bus and other functions in the micro service system. Each of these functions can be used separately or together to build a comprehensive service network.

Official website: https://www.consul.io/intro/index.html

Download address: https://www.consul.io/downloads.html

How to use with springcloud: https://www.springcloud.cc/spring-cloud-consul.html

2. Install and run consumer

Because Nacos of spring cloud Alibaba is used as the registration center in the mainstream of China, the windows version is simply used here.

After downloading, there is only one consumer.exe

Execute consumer agent - Dev to run in developer mode.

Visit http://localhost:8500

3. Create cloud-provider-payment-8006

new maven module

moduleName   cloud-provider-payment-8006
parentProject  cloud_2020
groupId      com.lee.springcloud
artifactId    cloud_2020
packaging     jar

The POM file of the parent project will have multiple labels after creation

POM

<?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>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment-8006</artifactId>

    <dependencies>
        <!--SpringCloud consul-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        
        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 8006
spring:
  application:
    name: cloud-provider-payment
  cloud:
    consul:
      host: 127.0.0.1 # Address of consumer Registration Center
      port: 8500
      discovery:
        hostname: 127.0.0.1
        service-name: ${spring.application.name}

Main boot class

package com.lee.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * This annotation is used to register services when using consumer or zookeeper as the registry
 * It can also be used for external service exposure service discovery
 */
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentConsulMain8006 {

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

Controller

package com.lee.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
 * There are no more ways to write service s like cloud-provider-payment-8001 and 8002
 * Write a controller method directly
 */
@RestController
public class PaymentController {

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

    @RequestMapping(value = "payment/consul")
    public String paymentZk() {
        return "SpringCloud with consul:" + serverPort + "\t" + UUID.randomUUID().toString();
    }

}

Test:

Start consumer: 

Visit: http://localhost:8500 / to view the node status

4. Create cloud-consumer-order-82

new maven module

moduleName   cloud-consumer-order-82
parentProject  cloud_2020
groupId      com.lee.springcloud
artifactId    cloud_2020
packaging     jar

The POM file of the parent project will have multiple labels after creation

POM

<?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>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order-82</artifactId>

    <dependencies>
        <!--SpringCloud consul-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        
        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Monitor-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--Thermal deployment-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Application.yml

server:
  port: 82
spring:
  application:
    name: cloud-consumer-order
  cloud:
    consul:
      host: 127.0.0.1 # Address of consumer Registration Center
      port: 8500
      discovery:
        hostname: 127.0.0.1
        service-name: ${spring.application.name}

Main boot class

package com.lee.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * This annotation is used to register services when using consumer or zookeeper as the registry
 * It can also be used for external service exposure service discovery
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerConsulMain82 {

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

config

package com.lee.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

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

}

Controller

package com.lee.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Slf4j
@RestController
public class OrderController {

    public static final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/consul")
    public String paymentInfo() {
        return restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
    }


}

Test:

Start consumer, cloud provider-payment-8006, cloud consumer-order-82 

Visit: http: / / localhost: 82 / consumer / payment / consumer

5, Comparison of three registration centers

1. Review CAP principles first

CAP principle, also known as CAP theorem, refers to that in a distributed system, Consistency, Availability and Partition tolerance cannot be obtained simultaneously. The essence of CAP principle is either AP, CP or AC, but there is no CAP.

C Consistency Uniformity
A Availability Usability
P Partition tolerance Partition tolerance

2. Differences among the three

Component name language CAP Spring cloud integration
Eureka Java AP Integrated
Zookeeper Java CP Integrated
Consul Go CP Integrated

AP is: if the two servers do not complete data synchronization, they can still provide external services.

CP is: if the two servers do not complete data synchronization, they will not provide external services until the data synchronization is completed.

 

===============================================================

As part of the service registry, spring cloud Alibaba Nacos will write in a later article

Tags: Programming Spring Zookeeper Maven Apache

Posted on Fri, 27 Mar 2020 07:01:01 -0700 by threaders