SpringCloud升級之路2020.0.x版-20. 啟動一個 Eureka Server 集群


本系列代碼地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford

image

我們的業務集群結構是這樣的:

  • 不同 Region,使用不同的 Eureka 集群管理,不同 Region 之間不互相訪問。
  • 同一 Region 內,可能有不同的業務集群,不同業務集群之間也不互相訪問,共用同一套業務集群。
  • 同一業務集群內可以隨意訪問,同時同一業務集群會做跨可用區的容災。
  • 在我們這里的抽象中,zone 代表不同集群,而不是實際的不同可用區

image

在這里,我們提供一個 Eureka Server 的集群模板,供大家參考。

image

首先,項目依賴是:

<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>

其實就是包含之前我們定義的所有同步微服務的依賴,以及 eureka-server 的相關依賴。

編寫啟動類,其實核心就是添加注解 @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);
    }
}

我們准備啟動一個兩個 Eureka Server 實例的集群,首先編寫兩個實例公共的配置,放入 application.yml

spring:
  application:
    name: eureka-server

eureka:
  server:
    #主動檢查服務實例是否失效的任務執行間隔,默認是 60s
    eviction-interval-timer-in-ms: 1000
    #這個配置在兩個地方被使用:
    #如果啟用用了自我保護,則會 renewal-threshold-update-interval-ms 指定的時間內,收到的心跳請求個數是否小於實例個數乘以這個 renewal-percent-threshold
    #定時任務檢查過期實例,每次最多過期 1 - renewal-percent-threshold 這么多比例的實例
    renewal-percent-threshold: 0.85
    #注意,最好所有的客戶端實例配置的心跳時間相關的配置,是相同的。這樣使用自我保護的特性最准確。
    #關閉自我保護
    #我們這里不使用自我保護,因為:
    #自我保護主要針對集群中網絡出現問題,導致有很多實例無法發送心跳導致很多實例狀態異常,但是實際實例還在正常工作的情況,不要讓這些實例不參與負載均衡
    #啟用自我保護的情況下,就會停止對於實例的過期
    #但是,如果出現這種情況,其實也代表很多實例無法讀取注冊中心了。
    #並且還有一種情況就是,Eureka 重啟。雖然不常見,但是對於鏡像中其他的組件更新我們還是很頻繁的
    #我傾向於從客戶端對於實例緩存機制來解決這個問題,如果返回實例列表為空,則使用上次的實例列表進行負載均衡,這樣既能解決 Eureka 重啟的情況,又能處理一些 Eureka 網絡隔離的情況
    #自我保護模式基於每分鍾需要收到 renew (實例心跳)請求個數,如果啟用了自我保護模式,只有上一分鍾接收到的 renew 個數,大於這個值,實例過期才會被注銷
    enable-self-preservation: false
    # 增量實例隊列實例過期時間,默認 3 分鍾
    retention-time-in-m-s-in-delta-queue: 180000
    # 增量實例隊列過期任務間隔,默認 30s
    delta-retention-timer-interval-in-ms: 30000
    # 響應緩存中有兩個主要元素,一個是 readOnlyCacheMap,另一個是 readWriteCacheMap
    # 是否使用 readOnlyCacheMap,默認為 true
    # 如果為是,則從 readOnlyCacheMap 讀取,否則直接讀取 readWriteCacheMap
    use-readonly-response-cahce: true
    # 初始 readWriteCacheMap 大小,默認 1000
    initial-capacity-of-response-cache: 1000
    # LoadingCache 緩存過期時間,默認 180s
    response-cache-auto-expiration-in-seconds: 9
    # 定時從 LoadingCache 同步到只讀緩存的間隔時間,默認為 30s
    response-cache-update-interval-ms: 3000
  client:
    service-url:
      # 默認eureka集群,這里必須是defaultZone,不能用-替換大寫,與其他的配置不一樣,因為實在EurekaClientConfigBean里面寫死的
      defaultZone: 'http://127.0.0.1:8211/eureka/,http://127.0.0.1:8212/eureka/'
    # 是否從 eureka 上面拉取實例, eureka server 不調用其他微服務,所以沒必要拉取
    fetch-registry: false
    # 是否將自己注冊到 eureka 上面,eureka server 不參與負載均衡,所以沒必要注冊
    register-with-eureka: false

server:
  undertow:
    # 以下的配置會影響buffer,這些buffer會用於服務器連接的IO操作
    # 如果每次需要 ByteBuffer 的時候都去申請,對於堆內存的 ByteBuffer 需要走 JVM 內存分配流程(TLAB -> 堆),對於直接內存則需要走系統調用,這樣效率是很低下的。
    # 所以,一般都會引入內存池。在這里就是 `BufferPool`。
    # 目前,UnderTow 中只有一種 `DefaultByteBufferPool`,其他的實現目前沒有用。
    # 這個 DefaultByteBufferPool 相對於 netty 的 ByteBufArena 來說,非常簡單,類似於 JVM TLAB 的機制
    # 對於 bufferSize,最好和你系統的 TCP Socket Buffer 配置一樣
    # `/proc/sys/net/ipv4/tcp_rmem` (對於讀取)
    # `/proc/sys/net/ipv4/tcp_wmem` (對於寫入)
    # 在內存大於 128 MB 時,bufferSize 為 16 KB 減去 20 字節,這 20 字節用於協議頭
    buffer-size: 16364
    # 是否分配的直接內存(NIO直接分配的堆外內存),這里開啟,所以java啟動參數需要配置下直接內存大小,減少不必要的GC
    # 在內存大於 128 MB 時,默認就是使用直接內存的
    directBuffers: true
    threads:
      # 設置IO線程數, 它主要執行非阻塞的任務,它們會負責多個連接, 默認設置每個CPU核心一個讀線程和一個寫線程
      io: 4
      # 阻塞任務線程池, 當執行類似servlet請求阻塞IO操作, undertow會從這個線程池中取得線程
      # 它的值設置取決於系統線程執行任務的阻塞系數,默認值是IO線程數*8
      worker: 128
    # http post body 大小,默認為 -1B ,即不限制
    max-http-post-size: -1B
    # 是否在啟動時創建 filter,默認為 true,不用修改
    eager-filter-init: true
    # 限制路徑參數數量,默認為 1000
    max-parameters: 1000
    # 限制 http header 數量,默認為 200
    max-headers: 200
    # 限制 http header 中 cookies 的鍵值對數量,默認為 200
    max-cookies: 200
    # 是否允許 / 與 %2F 轉義。/ 是 URL 保留字,除非你的應用明確需要,否則不要開啟這個轉義,默認為 false
    allow-encoded-slash: false
    # 是否允許 URL 解碼,默認為 true,除了 %2F 其他的都會處理
    decode-url: true
    # url 字符編碼集,默認是 utf-8
    url-charset: utf-8
    # 響應的 http header 是否會加上 'Connection: keep-alive',默認為 true
    always-set-keep-alive: true
    # 請求超時,默認是不超時,我們的微服務因為可能有長時間的定時任務,所以不做服務端超時,都用客戶端超時,所以我們保持這個默認配置
    no-request-timeout: -1
    # 是否在跳轉的時候保持 path,默認是關閉的,一般不用配置
    preserve-path-on-forward: false
    options:
      # spring boot 沒有抽象的 xnio 相關配置在這里配置,對應 org.xnio.Options 類
      socket:
        SSL_ENABLED: false
      # spring boot 沒有抽象的 undertow 相關配置在這里配置,對應 io.undertow.UndertowOptions 類
      server:
        ALLOW_UNKNOWN_PROTOCOLS: false
    # access log相關配置
    accesslog:
      # 存放目錄,默認為 logs
      dir: ./logs/${server.port}
      # 是否開啟
      enabled: true
      # 格式,各種占位符后面會詳細說明
      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"
                }'
      # 文件前綴,默認為 access_log
      prefix: access.
      # 文件后綴,默認為 log
      suffix: log
      # 是否另起日志文件寫 access log,默認為 true
      # 目前只能按照日期進行 rotate,一天一個日志文件
      rotate: true

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

除了同步微服務 undertow 的配置以及 actuator 的配置,Eureka 配置中,由於 Eureka Server 感知其他實例,僅僅通過 eureka.client.service-url 這個配置讀取,所以不需要 eureka server 注冊到 eureka server 或者讀取 eureka server 上面的實例,因此這里我們配置不注冊也不讀取。然后,我們這里按照之前分析的,關閉了自我保護,開啟了定時過期任務,並且將相關的定時任務時間間隔都調低了不少,因為我們的集群不是萬個實例級別的,而是一千左右,所以可以調高這些任務頻率。

之后,我們編寫兩個實例特定 profile 的配置,其實就是提供服務的端口不一樣,即:

application-eureka1.yml

server:
  port: 8211

application-eureka2.yml

server:
  port: 8212

之后,我們通過 IDEA 的環境變量配置,第一個 Eureka Server 的環境變量指定 spring.profiles.active=eureka1,第二個 Eureka Server 的環境變量指定 spring.profiles.active=eureka2,分別啟動。即可成為一個 Eureka 集群。大家可以嘗試往其中一個實例注冊一個服務實例,看另一個實例上是否被同步了這個服務實例。

我們這一節給大家提供一個配置模板,啟動一個 Eureka Server 集群。下一節,我們將開始分析並使用我們項目中的負載均衡器 Spring Cloud Loadbalancer

微信搜索“我的編程喵”關注公眾號,每日一刷,輕松提升技術,斬獲各種offer


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM