BUS components

1.

Spring Cloud Bus uses a lightweight message broker to connect the nodes of a distributed system. It can then be used to broadcast state changes (such as configuration changes) or other administrative instructions. AMQP (RabbitMQ) and Kafka Broker implementations are included in the project. Alternatively, any Spring Cloud Stream binder found on the classpath can be used as a transport.

Definition 2.

The reason why Bus is called as the message Bus in Spring Cloud is mainly used to inform all clients to refresh configuration information through broadcast when remote configuration updates are implemented in microservice system, avoiding manual service restart.

Configuring Semi-automatic Refresh

1. Set up the RabbitMQ service

  1. Download Erlang: www.erlang.org/downloads

  2. Download RabbitMQ: github.com/rabbitmq/ra…

  3. Prepare a CentOS7 vm.

  4. Set up FTP and upload the two installation packages to the VM.

  5. Install Erlang

    The RPM - the ivh Erlang 21.3.8.6-1. El7. X86_64-2. RPMCopy the code
  6. Install the RabbitMQ

    Yum install -- y the rabbitmq server - 3.7.18-1. El7. Noarch. RPMCopy the code
  7. The RabbitMQ after the installation is complete to/usr/share/doc/the RabbitMQ server – 3.7.18 / RabbitMQ. Config. The example configuration file to the/etc/RabbitMQ/directory, and named the RabbitMQ. Config.

    Cp/usr/share/doc/the rabbitmq server - 3.7.18 / rabbitmq config. The example/etc/rabbitmq/rabbitmq configCopy the code
  8. Modify rabbitmq.config

    vim /etc/rabbitmq/rabbitmq.config
    Copy the code

  9. Execute plug-in management services

    rabbitmq-plugins enable rabbitmq_management
    Copy the code
  10. Start the RabbitMQ

    # start the RabbitMQ
    systemctl start rabbitmq-server
    # to restart the RabbitMQ
    systemctl restart rabbitmq-server
    # stop the RabbitMQ
    systemctl stop rabbitmq-server
    Copy the code
  11. Check the RabbitMQ status

    systemctl status rabbitmq-server
    Copy the code
  12. Visit the RabbitMQ

    http://VM IP address :15672/Copy the code
  13. Log in to RabbitMQ using the guest account and password

Note:

  1. RabbitMQ requires the Erlang environment to operate, and RabbitMQ and Erlang versions must be strictly compatible.

  2. Network connection is required to install RabbitMQ because yum will need network connection to download other dependencies during RabbitMQ installation.

  3. If you cannot find the correct location to change rabbitmq.config, enter “:61” to go to line 61 and remove the first two %’s and the last comma.

  4. If http://VM IP address :15672/ cannot access the RabbitMQ page, enable the VM port or disable the firewall on the VM.

    Open VM ports (recommended) :

    # Open vm ports
    sudo firewall-cmd --permanent --add-port=15672/tcp
    sudo firewall-cmd --permanent --add-port=5672/tcp
    # Disable the vm port
    sudo firewall-cmd --permanent --remove-port=15672/tcp
    sudo firewall-cmd --permanent --remove-port=5672/tcp
    You need to restart the firewall after entering the open and close commands
    firewall-cmd --reload
    Copy the code

    Disable the firewall:

    systemctl disable firewalld
    systemctl stop firewalld
    Check the firewall status
    systemctl status firewalld
    Copy the code

2. Automatically refresh the configuration

In this case, automatic refreshing is implemented on the basis of manual refreshing, so the configuration of manual refreshing remains unchanged.

  1. Config Imports dependencies from the configuration center

    <dependency>
       <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    Copy the code
  2. Config Configure RabbitMQ for the configuration center

    spring:
      application:
        name: config
      cloud:
        # consul configuration
        consul:
          .
        # config configuration
        config:
          .
      # RabbitMQ configuration (new)
      rabbitmq:
        The IP address of the server where RabbitMQ resides
        host: 172.20131.194.
        Port (TCP) for rabbitMQ
        port: 5672
        Rabbitmq user name and password
        username: guest
        password: guest
    Copy the code
  3. Config client imports dependencies

    <dependency>
       <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    Copy the code
  4. Go to the remote repository to find the public configuration file corresponding to the Config client to add

     spring:
       .
       rabbitmq:
          host: 172.20131.194.
          port: 5672
          username: guest
          password: guest
    Copy the code
  5. Config Client bootstrap.yml adds the configuration

    spring:
      cloud:
        config:
          .
          Let the microservice work when there is a problem connecting the message bus to the message server
          fail-fast: true
    Copy the code
  6. Config Center enables all Web endpoints (including those for remote configuration file refresh)

    management:
      endpoints:
        web:
          exposure:
            include: "*"
    Copy the code
  7. Send a POST request to the configuration server to send a message to RabbitMQ, which tells all servers to refresh the configuration file.

    Curl -x POST http://IP address of the S2600: S2600 port/actuator/bus-refreshCopy the code

Note:

  1. The RabbitMQ Web port is 15672 and the TCP port is 5672.
  2. You can create your own users on the RabbitMQ Web. This article uses its own guest account.

3. Specify semi-automatic refresh of configurations

It is used by default

Curl -x POST http://IP address of the S2600: S2600 port/actuator/bus-refreshCopy the code

This mode of configuration refresh is broadcast. The configuration center will tell RabbitMQ to broadcast the refresh to all configuration files in the remote repository. However, sometimes we only change the configuration of one service, and the notification of other services is unnecessary, so we need to specify the service for notification.

  • Specify all nodes in a service cluster to automatically refresh configuration files

    Curl -x POST http:// service center IP: port service center/physical/bus - refresh/service nameCopy the code
  • Specify a node in a service cluster to refresh the configuration file automatically

    Curl -x POST http://IP address of the bSACTUATOR: bSACTUATOR port/ BSACTUATOR /bus-refresh/ BSACTUATOR port: bSACTUATOR port: bSACTUATOR portCopy the code

Configuring Automatic Refresh

In a semi-automatic refresh, we still need to manually send a POST request to the configuration center to notify RabbitMQ of the changes after modifying the configuration file in the remote repository. After the Github Webhock function is used to realize automatic configuration refresh, the configuration file will be automatically refreshed to the corresponding service after modification, without us to manually send a request.

Webhock works like a listener. Github automatically sends a POST request to the configuration center when we modify and submit a configuration file.

1. Configuration webhock

  1. Access remote warehouse

  2. Add webhock

  3. Fill in the Webhock configuration

2. NATAPP penetrates the Intranet

Because a registered user in NATAPP can have two tunnels of different protocols for free, this paper uses NATAPP to achieve Intranet penetration.

  1. Log in to NATAPP website, register, log in.

  2. Buy free tunnels

  3. Get authtoken

  4. Downloading a Client

  5. Open CMD in the directory of the NATAPP execution file.

  6. Start NATAPP, enter natapp-AuthToken = 56f71DB69ea4be2a in CMD

  7. Obtain the public IP address after Intranet penetration

  8. Fill in the payload URL required in the Webhock configuration with the public IP address

  9. Create the Config package in the Config configuration center.

  10. Create a Filter to Filter out other unwanted information in the Webhock POST request

    import org.springframework.stereotype.Component;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    
    @Component
    public class UrlFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}@Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest)request;
            HttpServletResponse httpServletResponse = (HttpServletResponse)response;
     
            String url = new String(httpServletRequest.getRequestURI());
     
            // Only filters /actuator/bus-refresh requests
            if(! url.endsWith("/bus-refresh")) {
                chain.doFilter(request, response);
                return;
            }
     
            // Get the original body
            String body = readAsChars(httpServletRequest);
     
            System.out.println("original body: "+ body);
     
            // Wrap the original request with HttpServletRequest to modify the body content of the POST request
            CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
     
            chain.doFilter(requestWrapper, response);
        }
     
        @Override
        public void destroy(a) {}private class CustometRequestWrapper extends HttpServletRequestWrapper {
            public CustometRequestWrapper(HttpServletRequest request) {
                super(request);
            }
     
            @Override
            public ServletInputStream getInputStream(a) throws IOException {
                byte[] bytes = new byte[0];
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
     
                return new ServletInputStream() {
                    @Override
                    public boolean isFinished(a) {
                        return byteArrayInputStream.read() == -1 ? true:false;
                    }
     
                    @Override
                    public boolean isReady(a) {
                        return false;
                    }
     
                    @Override
                    public void setReadListener(ReadListener readListener) {}@Override
                    public int read(a) throws IOException {
                        returnbyteArrayInputStream.read(); }}; }}public static String readAsChars(HttpServletRequest request) {
     
            BufferedReader br = null;
            StringBuilder sb = new StringBuilder("");
            try {
                br = request.getReader();
                String str;
                while((str = br.readLine()) ! =null) {
                    sb.append(str);
                }
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null! = br) {try {
                        br.close();
                    } catch(IOException e) { e.printStackTrace(); }}}returnsb.toString(); }}Copy the code

Note:

  1. Configure the payload URL in the Webhock to be a public IP address. Otherwise, deploy the configuration center to the cloud server, or perform Intranet penetration.

  2. If a Filter is not created, Github will report a 400 error when sending a Post request to the configuration center. This is because Spring Boot can’t deserialize properly, so we need to write a filter that returns the Body as empty.