本系列程式碼地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford
我們的業務叢集結構是這樣的:
- 不同 Region,使用不同的 Eureka 叢集管理,不同 Region 之間不互相訪問。
- 同一 Region 內,可能有不同的業務叢集,不同業務叢集之間也不互相訪問,共用同一套業務叢集。
- 同一業務叢集內可以隨意訪問,同時同一業務叢集會做跨可用區的容災。
- 在我們這裡的抽象中,zone 代表不同叢集,而不是實際的不同可用區。
在這裡,我們提供一個 Eureka Server 的叢集模板,供大家參考。
首先,專案依賴是:
<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: