Microservices - message bus SpringCloud Bus

Posted by hungryOrb on Sun, 28 Nov 2021 22:12:09 +0100

1. why

The server of the configuration center in the previous article can pull the real-time changed configuration from the remote warehouse, but the client cannot directly update the configuration. It needs to send a post request to the client to refresh the configuration (/ Actor / refresh). When there are few client microservices, it can accept them. Once there are hundreds of client microservices, It is impossible for the operation and maintenance engineer to send a post request to each client to manually refresh the configuration. Then, can a large-scale automatic refresh through a broadcast technology realize a notification and take effect everywhere? That is the message bus technology I want to write below

2. What is a message bus

In microservice architecture systems, lightweight message brokers are usually used to build a common message topic and connect all microservice instances in the system. Since the messages generated in this topic will be monitored and consumed by all instances, it is called message bus. Each instance on the bus can easily broadcast some messages that need to be known by other instances connected to the subject.

What is a message broker?
Message broker is an architecture mode of message verification, transmission and routing. It is mainly used to receive and distribute messages, and forward them to the correct application according to the set message processing flow. It plays the role of communication scheduling between micro services and reduces the dependence between services.

Spring Cloud Bus can be used with Spring Cloud Config to dynamically refresh the configuration.

Basic principles
ConfigClient instances listen to the same Topic in MQ (springcloudbus by default). When a service refreshes the data, it will put this information into the Topic, so that other services listening to the same Topic can be notified, and then update their own configuration.

3. What is SpringCloud Bus

Official information → SpringCloud Bus
Spring Cloud Bus is a message bus within the Spring Cloud system, which is used to connect all nodes of the distributed system. A framework dedicated to solving the problem of connecting nodes of distributed system with lightweight message system, which integrates the event processing mechanism of Java and the function of message middleware.

Spring Cloud Bus connects distributed nodes with lightweight message brokers (currently only RibbitMQ and Kafka message queues are supported). The message broker can broadcast changes to configuration files, or communication between services, or can be used for monitoring. It solves the problem of timely synchronization of microservice data changes.

4. Environmental planning

  • RabbitMQ → RabbitMQ environment configuration
  • atguigu-cloud-2020 polymerization project:
    Version: SpringBoot 2.2.2.RELEASE, Spring Cloud Hoxton.SR1
    Registration Center eureka01:7001
    Registration Center eureka02:7002
    Configuration center server cloud-config-center-3344
    Configuration center client 1 cloud-config-client-3355
    Configuration center client 2 cloud-config-client-3366

5. Best practices

5.1 RabbitMQ installation

The above gives the detailed process of installing RabbitMQ on Windows system. I won't elaborate here. I mainly talk about the process of installing RabbitMQ using docker. The following case is also RabbitMQ configuration using Linux environment
Use docker to install and run rabbmitMQ related commands

# Search rabbitMQ
docker search rabbitmq:management
# Download rabbitMQ image
docker pull rabbitmq:management
# Run rabbitMQ container
docker run --name rabbitmq -p 5671:5671 -p 5672:5672 -p 15671:15671 -p 15672:15672 -p 4369:4369 -p 25672:25672 rabbitmq:management
# View running containers
docker ps -a
# Stop rabbitMQ container
docker stop rabbitmq
# Start rabbitMq container
docker start rabbitmq
# Remove rabbitMQ container
docker rm rabbitmq
# Start docker
systemctl start docker
# Stop docker
systemctl stop docker

After rabbitMQ is started successfully, access http://192.168.65.129:15672/ View console

Enter the default user password guest/guest to enter the rabbitmq console

5.2 create parent project

Create the parent project [atguigu-cloud-2020], and use the dependency of the parent project to manage the version of spring boot, spring cloud and common components

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>atguigu-cloud-2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>cloud-eureka-server-7001</module>
        <module>cloud-eureka-server-7002</module>
        <module>cloud-config-center-3344</module>
        <module>cloud-config-client-3355</module>
        <module>cloud-config-client-3366</module>
    </modules>
    <packaging>pom</packaging>

    <!-- unified management  jar Package version -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!-- SpringCloud Official warehouse -->
    <!-- <repositories>
         <repository>
             <id>spring-snapshots</id>
             <name>Spring Snapshots</name>
             <url>https://repo.spring.io/snapshot</url>
             <snapshots>
                 <enabled>true</enabled>
             </snapshots>
         </repository>
         <repository>
             <id>spring-milestones</id>
             <name>Spring Milestones</name>
             <url>https://repo.spring.io/milestone</url>
             <snapshots>
                 <enabled>false</enabled>
             </snapshots>
         </repository>
     </repositories>-->

    <!-- After the sub module inherits, it provides the following functions: locking the version+son modlue Do not write groupId and version  -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

5.3 building a registration center

Create registration centers eureka01:7001 and eureka02:7002 clusters. The specific steps are not expanded
You can view the blog → Eureka cluster construction

5.4 create configuration center server

New configuration center server [cloud config center-3344]

5.4.1 pom dependency

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

    <artifactId>cloud-config-center-3344</artifactId>

    <dependencies>
        <!--Add message bus RabbitMQ support-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <!--spring-cloud-config Server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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>

5.4.2 write configuration

Write the configuration using the application.yml or bootstrap.yml file

server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/wang-qz/springcloud-config.git
          search-paths: springcloud-config #search for directory
          default-label: master # Read branch
  rabbitmq:
    host: 192.168.65.129
    port: 5672
    username: guest
    password: guest
# eureka configuration
eureka:
  instance:
    hostname: localhost
    instance-id: cloud-config-center-3344
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://www.eureka01.com:7001/eureka,http://www.eureka02.com:7002/eureka
##rabbitmq related configuration, exposing the endpoint of bus refresh configuration
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'

5.4.3 write startup class

com.atguigu.springcloud.ConfigCenterApplication

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

/**
 * Class description: configuration center server startup class
 * @Author wang_qz
 * @Date 2021/11/21 21:49
 * @Version 1.0
 */
@SpringBootApplication
@EnableConfigServer
public class ConfigCenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigCenterApplication.class);
    }
}

5.4.4 remote warehouse configuration

You can add a remote configuration repository on GitHub or gitee. I created the remote configuration repository [springcloud config] on gitee
A remote configuration config-dev.yml is added to the repository

The configuration reading method of the remote warehouse can be viewed Official website → Spring Cloud Config

5.4.5 verify the configuration center server

Start registry microservice

After starting the configuration center server micro service, access http://localhost:3344/config-dev.yml, successfully read the configuration of the remote warehouse

5.5 create configuration center client

New configuration center clients cloud-config-client-3355 and cloud-config-client-3366 are added. The two clients are used to test the fixed-point notification later. The configurations of the two clients are basically the same

5.5.1 pom dependency

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

    <artifactId>cloud-config-client-3355</artifactId>

    <dependencies>
        <!--Add message bus RabbitMQ support-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <!--spring-cloud-config client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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>

5.5.2 write configuration

Add configuration to the application.yml or bootstrap.yml file

server:
  port: 3355
spring:
  application:
    name: config-client
  cloud:
    #Config client configuration
    config:
      uri: http://localhost:3344 # configuration center address
      label: master #Branch name
      name: config #Profile name
      profile: dev #Read suffix name
      # The above three combinations: the config-dev.yml configuration file on the master branch is read http://localhost:3344/master/config-dev.yml
  rabbitmq:
    host: 192.168.65.129
    port: 5672
    username: guest
    password: guest

#eureka configuration
eureka:
  instance:
    hostname: localhost
    instance-id: config-client-3355
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://www.eureka01.com:7001/eureka,http://www.eureka02.com:7002/eureka
# Exposure monitoring endpoint
management:
  endpoints:
    web:
      exposure:
        include: "*"

5.5.3 write startup class

com.atguigu.springcloud.ConfigClientApplication

package com.atguigu.springcloud;

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

/**
 * Class description: configuration center client startup class
 * @Author wang_qz
 * @Date 2021/11/21 22:08
 * @Version 1.0
 */
@SpringBootApplication
@EnableEurekaClient
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class);
    }
}

5.5.4 writing controller

com.atguigu.springcloud.controller.ConfigClientController

package com.atguigu.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Class description:
 * @Author wang_qz
 * @Date 2021/11/21 22:15
 * @Version 1.0
 */
@RestController
@RefreshScope
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}

5.5.5 verifying client read configuration

Start the configuration center client micro service and register with eureka

visit http://localhost:3355/configInfo And http://localhost:3366/configInfo , successfully read the configuration of the remote warehouse

So far, all environments have been prepared and the basic verification has passed. Part I Configuration center Spring Cloud Config This section describes in detail how to refresh the client configuration through post request / acuator/refresh
At the beginning of this article, we also talked about the disadvantages of refreshing the configuration by requesting the client. The following details how to refresh the client configuration by using the spring cloud bus broadcast notification

Personal blog

Welcome to personal blog: https://www.crystalblog.xyz/

Alternate address: https://wang-qz.gitee.io/crystal-blog/

Topics: Java Spring Cloud Microservices