Spring cloud upgrade 2020.0 Version x - 20 Start an Eureka Server cluster

Posted by TheFreak on Sun, 02 Jan 2022 18:39:49 +0100

Code address of this series: https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford

Our business cluster structure is as follows:

  • Different regions use different Eureka cluster management, and different regions do not access each other.
  • In the same Region, there may be different business clusters. Different business clusters do not access each other and share the same set of business clusters.
  • The same business cluster can be accessed at will. At the same time, the same business cluster will do disaster recovery across availability zones.
  • In our abstraction here, zones represent different clusters rather than actual different zones.

Here, we provide a cluster template of Eureka Server for your reference.

First, project dependencies are:

<dependencies>
    <dependency>
        <groupId>com.github.hashjang</groupId>
        <artifactId>spring-cloud-iiford-spring-cloud-webmvc</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

In fact, it includes all the dependencies of synchronous microservices defined before and the related dependencies of Eureka server.

The core of writing startup classes is to add the annotation @ EnableEurekaServer

package com.github.hashjang.spring.cloud.iiford.eureka.server;

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

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

We are going to start a cluster of two Eureka Server instances. First, write the common configuration of the two instances and put them into the application yml:

spring:
  application:
    name: eureka-server

eureka:
  server:
    #The task execution interval to actively check whether the service instance is invalid. The default is 60s
    eviction-interval-timer-in-ms: 1000
    #This configuration is used in two places:
    #If self-protection is enabled, whether the number of heartbeat requests received within the time specified by renewal threshold update interval MS is less than the number of instances multiplied by this renewal percent threshold will be
    #Scheduled tasks check expired instances, which can expire at most 1 - renewal percent threshold at a time
    renewal-percent-threshold: 0.85
    #Note that it is best to configure the heartbeat time related configuration for all client instances to be the same. This is the most accurate way to use self-protection features.
    #Turn off self-protection
    #We do not use self-protection here because:
    #Self protection is mainly aimed at the network problems in the cluster, resulting in many instances unable to send heartbeat and many instances in abnormal state, but the actual instances are still working normally. Do not let these instances not participate in load balancing
    #When self-protection is enabled, the expiration of instances will be stopped
    #However, if this happens, it also means that many instances cannot read the registry.
    #And another case is that Eureka restarts. Although it is not common, we update other components in the image very frequently
    #I prefer to use the instance caching mechanism from the client to solve this problem. If the returned instance list is empty, use the last instance list for load balancing. This can not only solve Eureka restart, but also deal with some Eureka network isolation
    #The self-protection mode is based on the number of renews (instance heartbeat) requests that need to be received per minute. If the self-protection mode is enabled, only the number of renews received in the last minute is greater than this value, and the instance will be logged off when it expires
    enable-self-preservation: false
    # Incremental instance queue instance expiration time, 3 minutes by default
    retention-time-in-m-s-in-delta-queue: 180000
    # Incremental instance queue expiration task interval, default 30s
    delta-retention-timer-interval-in-ms: 30000
    # There are two main elements in the response cache: readOnlyCacheMap and readWriteCacheMap
    # Whether to use readonlycahemap. The default value is true
    # If yes, read from readOnlyCacheMap; otherwise, read readWriteCacheMap directly
    use-readonly-response-cahce: true
    # The initial readWriteCacheMap size is 1000 by default
    initial-capacity-of-response-cache: 1000
    # LoadingCache cache expiration time, 180s by default
    response-cache-auto-expiration-in-seconds: 9
    # The interval between scheduled synchronization from LoadingCache to read-only cache. The default is 30s
    response-cache-update-interval-ms: 3000
  client:
    service-url:
      # The default eureka cluster must be defaultZone here, and cannot replace uppercase with - which is different from other configurations, because it is written dead in eureka clientconfigbean
      defaultZone: 'http://127.0.0.1:8211/eureka/,http://127.0.0.1:8212/eureka/'
    # Whether to pull instances from eureka. eureka server does not call other microservices, so it is not necessary to pull instances
    fetch-registry: false
    # Whether to register yourself with eureka. eureka server does not participate in load balancing, so it is not necessary to register
    register-with-eureka: false

server:
  undertow:
    # The following configurations will affect buffer s, which will be used for IO operations of server connections
    # If you apply for ByteBuffer every time you need it, you need to go through the JVM memory allocation process (TLAB - > heap) for heap memory and system call for direct memory, which is very inefficient.
    # Therefore, memory pools are generally introduced. Here is' BufferPool '.
    # At present, there is only one 'DefaultByteBufferPool' in UnderTow, and other implementations are useless at present.
    # The DefaultByteBufferPool is very simple compared to the ByteBufArena of netty, similar to the mechanism of JVM TLAB
    # For bufferSize, it is better to configure it the same as the TCP Socket Buffer configuration of your system
    # `/proc/sys/net/ipv4/tcp_rmem ` (for read)
    # `/proc/sys/net/ipv4/tcp_wmem ` (for write)
    # When the memory is greater than 128 MB, the bufferSize is 16 KB minus 20 bytes, which are used for the protocol header
    buffer-size: 16364
    # Whether to allocate the direct memory (the off heap memory directly allocated by NIO) is enabled here, so the java startup parameter needs to configure the direct memory size to reduce unnecessary GC
    # When the memory is greater than 128 MB, direct memory is used by default
    directBuffers: true
    threads:
      # Set the number of IO threads, which mainly perform non blocking tasks. They are responsible for multiple connections. By default, one read thread and one write thread are set for each CPU core
      io: 4
      # Block the task thread pool. When performing IO blocking operations similar to servlet requests, underow will get threads from this thread pool
      # Its value setting depends on the blocking coefficient of system threads executing tasks. The default value is IO threads * 8
      worker: 128
    # The size of http post body is - 1B by default, which is unlimited
    max-http-post-size: -1B
    # Whether to create a filter at startup. The default value is true without modification
    eager-filter-init: true
    # Limit the number of path parameters. The default value is 1000
    max-parameters: 1000
    # Limit the number of HTTP headers. The default is 200
    max-headers: 200
    # Limit the number of key value pairs of cookies in http header. The default value is 200
    max-cookies: 200
    # Allow / escape with% 2F/ It is a URL reserved word. Do not enable this escape unless your application explicitly needs it. The default is false
    allow-encoded-slash: false
    # Whether to allow URL decoding. The default value is true. All but% 2F will be processed
    decode-url: true
    # url character encoding set. The default is utf-8
    url-charset: utf-8
    # Whether the http header of the response will add 'connection: keep alive', which is true by default
    always-set-keep-alive: true
    # The request timeout is no timeout by default. Because our microservices may have long-term scheduled tasks, we do not do server timeout, but use client timeout, so we maintain this default configuration
    no-request-timeout: -1
    # Whether to keep path during jump. It is closed by default. Generally, it is not configured
    preserve-path-on-forward: false
    options:
      # spring boot has no abstract xnio related configuration, which is configured here, corresponding to org xnio. Options class
      socket:
        SSL_ENABLED: false
      # spring boot has no abstract undertow related configuration, which is configured here, corresponding to io undertow. Undertowoptions class
      server:
        ALLOW_UNKNOWN_PROTOCOLS: false
    # access log related configuration
    accesslog:
      # Storage directory, logs by default
      dir: ./logs/${server.port}
      # Open
      enabled: true
      # Format, various placeholders will be described in detail later
      pattern: '{
                  "transportProtocol":"%{TRANSPORT_PROTOCOL}",
                  "scheme":"%{SCHEME}",
                  "protocol":"%{PROTOCOL}",
                  "method":"%{METHOD}",
                  "reqHeaderUserAgent":"%{i,User-Agent}",
                  "reqHeaderUserId":"%{i,uid}",
                  "traceId":"%{i,X-B3-TraceId}",
                  "spanId":"%{i,X-B3-SpanId}",
                  "queryString": "%q",
                  "uri": "%U",
                  "thread": "%I",
                  "hostPort": "%{HOST_AND_PORT}",
                  "localIp": "%A",
                  "localPort": "%p",
                  "localServerName": "%v",
                  "remoteIp": "%a",
                  "bytesSent": "%b",
                  "time":"%{time,yyyy-MM-dd HH:mm:ss.S}",
                  "status":"%s",
                  "reason":"%{RESPONSE_REASON_PHRASE}",
                  "timeUsed":"%Dms"
                }'
      # File prefix. The default is access_log
      prefix: access.
      # The file suffix is log by default
      suffix: log
      # Whether to write access log from another log file. The default value is true
      # Currently, you can only rotate by date, one log file a day
      rotate: true

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    jmx:
      exposure:
        exclude: '*'
    web:
      exposure:
        include: '*'

In addition to synchronizing the configuration of the microservice undertow and the configuration of the actor, in the Eureka configuration, because Eureka server senses other instances, it only uses Eureka client. The service URL configuration is read, so there is no need to register the Eureka server with the Eureka server or read the instances on the Eureka server. Therefore, we do not register or read the configuration here. Then, according to the previous analysis, we turn off self-protection, turn on scheduled overdue tasks, and reduce the time interval of related scheduled tasks. Because our cluster is not at the level of 10000 instances, but about 1000, we can increase the frequency of these tasks.

After that, we write the configuration of two instance specific profile s. In fact, the ports providing services are different, that is:

application-eureka1.yml

server:
  port: 8211

application-eureka2.yml

server:
  port: 8212

After that, we configure the environment variable of IDEA, and the environment variable of the first Eureka Server specifies spring profiles. Active = eureka1, the environment variable of the second Eureka Server specifies spring profiles. Active = eureka2, start respectively. You can become an Eureka cluster. You can try to register a service instance with one instance to see whether the service instance is synchronized on the other instance.

In this section, we provide you with a configuration template to start an Eureka Server cluster. In the next section, we will start analyzing and using the load balancer Spring Cloud Loadbalancer in our project