Spring Cloud Eureka 總結
寫在前面的話(給自己)
為了鞏固自身學習,從今天(2019.01.08),每天晚上開始總結SpringCloud的相關學習,用於自我勉勵,自我積累與人生總結。
總結2018年的我,心態較之從前浮躁,雜念多了,沒有用心,更沒能好好的反思自己;按照自己單身的情況,平時我本應該有更多的時間去學習,去提高,去真正的充實自己。
學習本身就並非易事,無論是為了生活還是理想,還是一種生活狀態,最重要的是要用心,要真正的去理解,更要沈得住氣,靜得下心。
選擇了IT這一行,應該有苦修的覺悟,任何技術只停留在簡單會用的階段(目前我深陷其中),其實是遠遠不夠的。就跟我最早學了spring-cloud-ribbon只知道一個@LoadBalanced
2019年,我希望我能戒掉周末還有時間打遊戲的生活狀態,能充實自己,克服焦慮;
2019年,我希望我能堅持,能勤奮;
2019年,我希望我能多讀書,能成長;
2019年,我希望我能坦然面對生活中的任何壓力,能有內驅動力,能找到女朋友,找到外驅動力。
希望我每次看到這段給自己的話,都不要忘了初心。
好了,閑言碎語,皆盡於此。
在微服務架構中,註冊中心是核心的基礎服務。
它主要記錄各個微服務和微服務地址的映射關系,各個微服務都將自己註冊到這個註冊中心上面,當微服務之間需要互相調用時,就可以從註冊中心上面去發現微服務和進行調用。
Spring Cloud是一個開箱即用的微服務框架,秉承了微服務的真正理念而設計。
Spring Cloud中,誰是服務的註冊中心 ? Eureka Server即服務的註冊中心,核心配置如下
註 : 本文只講Eureka,不關註Consul與Zookeeper等替代方案
1. 加入依賴,pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-server</artifactId> </dependency>
2. 程序入口類添加@EnableEurekaServer,啟用Eureka Server。例如:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* Created by EalenXie on 2018/12/28 14:13.
*/
@EnableEurekaServer
@SpringBootApplication
public class SpringCloudEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
}
}
3. 單機版Eureka Server,配置application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost # 服務註冊中心實例的主機名
lease-renewal-interval-in-seconds: 30 # 客戶端向Eureka發送心跳周期(s)
lease-expiration-duration-in-seconds: 90 # Eureka Server接收實例的最後一次發出的心跳後,刪除需要等待時間(s)
server:
enable-self-preservation: true # Eureka自我保護模式
client:
register-with-eureka: false # 是否向服務註冊中心註冊自己
fetch-registry: false # 是否檢索發現服務
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 指定服務註冊中心的位置
4. Eureka Server集群配置(HA,高可用),實際上就是將自己作為服務向其他服務註冊中心註冊自已,這樣就可以形成一組互相註冊的服務註冊中心,以實現服務清單的互相同步,達到高可用的效果。多個Eureka Server的實例互相註冊。配置application.yml
Eureka Server 實例1 配置
server:
port: 8761
eureka:
instance:
hostname: localhost # 服務註冊中心實例的主機名
server:
enable-self-preservation: true # Eureka自我保護模式
client:
register-with-eureka: true # 是否註冊到Eureka Server
fetch-registry: true # 是否檢索發現服務
service-url:
defaultZone: http://${eureka.instance.hostname}:8762/eureka/,http://${eureka.instance.hostname}:8763/eureka/
#指定多個服務註冊中心的位置,並向服務註冊中心註冊自己
Eureka Server 實例2 配置
server:
port: 8762
eureka:
instance:
hostname: localhost # 服務註冊中心實例的主機名
server:
enable-self-preservation: true # Eureka自我保護模式
client:
register-with-eureka: true # 是否註冊到Eureka Server
fetch-registry: true # 是否檢索發現服務
service-url:
defaultZone: http://${eureka.instance.hostname}:8761/eureka/,http://${eureka.instance.hostname}:8763/eureka/
#指定多個服務註冊中心的位置,並向服務註冊中心註冊自己
...
誰註冊到Eureka Server ? Eureka Client 即註冊的服務,基本配置如下
1. 加入依賴,pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. 主類上面加入@EnableDiscoveryClient ,開啟該註解使該服務能夠被註冊中心發現,例如:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Created by EalenXie on 2018/12/28 14:45.
*/
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudEurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaClientApplication.class, args);
}
}
3. 客戶端的最基本的配置,application.yml ,例如:
server:
port: 8090
spring:
application:
name: spring-cloud-eureka-client-application
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
4. 啟動Eureka Server,訪問http://localhost:8761 可以進入到Eureka Server的查看頁面 :
5. 啟動Eureka Client,即可在Eureka Server上面看到註冊上去的本服務,或者訪問: http://localhost:8761/eureka/apps
6. Eureka Client可以通過LookupService核心接口(基本實現類DiscoveryClient)從服務中心獲取服務實例的查詢方法。
package com.netflix.discovery.shared;
import java.util.List;
import com.netflix.appinfo.InstanceInfo;
public interface LookupService<T> {
Application getApplication(String appName);
Applications getApplications();
List<InstanceInfo> getInstancesById(String id);
InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}
關於Eureka和其客戶端相關說明
1. 關於Eureka Server的自我保護模式:
默認情況下,如果Eureka Server在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會註銷該實例(默認90秒)。
但是當網絡分區故障發生時,會統計心跳失敗的比例,閾值因子默認是0.85,如果閾值比最小值大則表明微服務與Eureka Server之間無法正常通信,這就可能變得非常危險了--因為微服務本身是健康的,此時本不應該註銷這個微服務。
Eureka Server通過‘自我保護模式‘來解決這個問題,當Eureka Server節點在短時間內丟失過多客戶端時(可能發生了網絡分區故障),那麽這個節點就會進入自我保護模式。
一旦進入該模式,Eureka Server就會保護服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。當網絡故障恢復後,該Eureka Server節點會自動退出自我保護模式。
自我保護模式是一種對網絡異常的安全保護措施。使用自我保護模式,而已讓Eureka集群更加的健壯、穩定。
2. 關於Eureka Server REST API 接口
POST /eureka/apps/{appId} 註冊新的實例
DELETE /eureka/apps/{appId}/{instanceId} 註銷應用實例
PUT /eureka/apps/{appId}/{instanceId} 應用實例發送心跳
GET /eureka/apps 查詢所有的實例
GET /eureka/apps/{appId} 查詢指定appId的實例
GET /eureka/apps/{appId}/{instanceId} 查詢指定appId和instanceId的實例
GET /eureka/instances/{instanceId} 查詢指定的instanceId的實例
PUT /eureka/apps/{appId}/{instanceId}/status?value=OUT_OF_SERVICE 暫停應用實例
PUT /eureka/apps/{appId}/{instanceId}/status?value=UP 恢復應用實例
PUT /eureka/apps/{appId}/{instanceId}/metadata?key=value 更新元數據信息
GET /eureka/vips/{vipAddress} 根據vip地址查詢
GET /eureka/svips/{svipAddress} 根據svip地址查詢
3. Eureka的核心類
InstanceInfo : 註冊的服務實例,裏面包含服務實例的各項屬性
LeaseInfo : Eureka用這個類來標識應用實例的租約信息
ServiceInstance : 發現的實例信息的抽象接口,約定了服務發現的實例應用有哪些通用信息
InstanceStatus : 用於標識服務實例的狀態,是一個枚舉類,主要有狀態UP,DOWN,STARTING,OUT_OF_SERVICE,UNKNOWN
EurekaServerConfigBean : Eureka Server的核心配置類,裏面包含了Eureka Server的各項核心屬性信息
4. Eureka的核心動作,核心接口為LeaseManager,基本實現類為InstanceRegistry
package com.netflix.eureka.lease;
import com.netflix.eureka.registry.AbstractInstanceRegistry;
public interface LeaseManager<T> {
void register(T r, int leaseDuration, boolean isReplication);
boolean cancel(String appName, String id, boolean isReplication);
boolean renew(String appName, String id, boolean isReplication);
void evict();
}
服務註冊(register) : 其他客戶端將自己註冊到Eureka上面
服務下線(cancel) : Eureka 刪除服務信息
服務租約(renew) : 客戶端定時向Eureka發送心跳證明自己存活,Eureka接收到心跳為其維持租約
服務剔除(evict) : Eureka Server的方法,剔除心跳檢測過期的服務實例
5. Eureka的核心動作監聽,個人示例代碼如下 :
package name.ealen.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean;
import org.springframework.cloud.netflix.eureka.server.event.*;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* Created by EalenXie on 2018/9/20 14:46.
* EurekaServerEventListener 監聽Eureka的事件行為
* 註 : EurekaInstanceRegisteredEvent,EurekaInstanceCanceledEvent,EurekaInstanceRenewedEvent
*/
@Component
public class EurekaServerEventListener {
private static final Logger log = LoggerFactory.getLogger(EurekaServerEventListener.class);
/**
* Eureka Server 註冊事件
*/
@EventListener
public void eurekaRegister(EurekaRegistryAvailableEvent event) {
//write your logic..........
log.info("Eureka Server Register at timestamp : {}", event.getTimestamp());
}
/**
* Eureka Server 啟動事件
*/
@EventListener
public void serverStart(EurekaServerStartedEvent event) {
//write your logic..........
Object source = event.getSource();
if (source instanceof EurekaServerConfigBean) {
EurekaServerConfigBean eureka = (EurekaServerConfigBean) source;
log.info("Eureka ServerConfigBean : {}",eureka);
}
}
/**
* 服務註冊事件
*/
@EventListener(condition = "#event.replication==false")
public void instanceRegister(EurekaInstanceRegisteredEvent event) {
//write your logic..........
log.info("Register InstanceInfo : {}",event.getInstanceInfo());
}
/**
* 服務下線事件
*/
@EventListener(condition = "#event.replication==false")
public void instanceCancel(EurekaInstanceCanceledEvent event) {
//write your logic..........
log.info("instanceCancel serviceId : {}",event.getServerId());
}
/**
* 服務續約事件
*/
@EventListener(condition = "#event.replication==false")
public void instanceRenewed(EurekaInstanceRenewedEvent event) {
//write your logic..........
}
}
Eureka會為每個核心動作發布一個相關的事件,我們可以通過監聽這些事件來做一些針對性的自定義處理邏輯。
Eureka Server自身註冊事件 : EurekaRegistryAvailableEvent
Eureka Server自身啟動事件 : EurekaServerStartedEvent
服務註冊事件(register) : EurekaInstanceRegisteredEvent
服務下線事件(cancel) : EurekaInstanceCanceledEvent
服務租約事件(renew,續約,發送心跳) : EurekaInstanceRenewedEvent
6. Eureka的健康檢查
Spring Boot Actuator 提供了/health 端點
只需要啟用Eureka的健康檢查,就可以將端點中的健康狀態傳遞到Eureka Server
eureka.client.healthcheck.enable: true
註意 : 這個只能在application.yml中配置,如果在bootstrap.yml中配置,可能會導致一些不良後果。
這一點官方有明確說明 : https://cloud.spring.io/spring-cloud-static/Edgware.SR5/single/spring-cloud.html#_eureka_s_health_checks
Eureka Server和Client 參數調優與說明
以下所有參數,均為Eureka的默認值,可按需調整。
Client端參數說明(篇幅問題,部分) :
eureka.client.register-with-eureka: true 是否註冊自己到Eureka Server上面
eureka.client.fetch-registry: true 是否從Eureka Server上面拉取服務信息
eureka.client.enable: true 是否啟用Eureka客戶端,不啟用則不註冊到Eureka Server
eureka.client.healthcheck.enable: true 是否啟用Eureka健康檢查
eureka.client.availability-zones: new HashMap<>() 告訴client有哪些可用的region和zone
eureka.client.filter-only-up-instances: true 是否過濾出InstanceStatus為UP的實例
eureka.client.region: us-east-1 指定該應用實例所在的region,AWS datacenters適用
eureka.client.prefer-same-zone-eureka: true 是否優先使用與該應用相同Zone的Eureka Server
eureka.client.cache-refresh-executor-thread-pool-size: 2 緩存刷新線程池CacheRefreshThread的初始化線程數
eureka.client.registry-fetch-interval-seconds: 30 Eureka client拉取服務註冊信息間隔時間(s)
eureka.client.instance-info-replication-interval-seconds: 30 復制實例變化信息到Eureka服務器所需要的時間間隔(s)
eureka.client.eureka-service-url-poll-interval-seconds: 300 輪詢Eureka服務端地址更改的間隔時間(s)
eureka.client.eureka-server-read-timeout-seconds: 8 讀取Eureka Server信息的超時時間(s)
eureka.client.eureka-server-connect-timeout-seconds: 5 連接Eureka Server的超時時間(s)
eureka.client.eureka-server-total-connections: 200 從Eureka客戶端到所有Eureka服務端的連接總數
eureka.client.eureka-server-total-connections-per-host: 50 從Eureka客戶端到每個Eureka服務端主機的連接總數
eureka.client.eureka-connection-idle-timeout-seconds: 30 Eureka服務端連接的空閑關閉時間(s)
eureka.instance.metadata-map: new HashMap<>() 指定應用實例的元數據信息
eureka.instance.prefer-ip-address: false 是否優先使用ip地址來替代hostname作為實例hostname字段值
eureka.instance.lease-expiration-duration-in-seconds: 90 Eureka clent最後一次心跳後,Eureka Server剔除需要等待時間(s)
eureka.instance.lease-renewal-interval-in-seconds: 30 客戶端向Eureka Server發送心跳周期(s)
Server端參數說明(篇幅問題,部分) :
eureka.server.enable-self-preservation: true Eureka Server是否開啟自我保護模式
eureka.server.renewal-percent-threshold: 0.85 指定每分鐘需要收到的續約次數的闕值,如果閾值比最小值大,則自我保護模式開啟
eureka.server.eviction-interval-timer-in-ms: 60*1000 指定EvictionTask定時任務的調度頻率,用於剔除過期的實例
eureka.server.wait-time-in-ms-when-sync-empty: 1000*60*5 在Eureka服務器獲取不到集群裏對等服務器上的實例時,需要等待的時間
誰有權使用和操作Eureka Server? 如何保證它的安全性? HTTP Basic認證
1.Eureka Server只需要結合spring-boot-security,就可以為Eureka Server開啟用戶認證的能力。加入pom.xml依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.修改application.yml的配置:
security:
basic:
enabled: true # 開啟基於HTTP Basic的認證
user:
name: ealenxie # 登陸賬號名
password: zaxscdvfrewq # 登陸密碼
server:
port: 8761
eureka:
instance:
hostname: localhost # 服務註冊中心實例的主機名
client:
register-with-eureka: false # 是否向服務註冊中心註冊自己
fetch-registry: false # 是否檢索發現服務
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 指定服務註冊中心的位置
3. 另外,由於spring-boot-starter-security默認開啟csrf校驗,對於Client端這類非界面應用來說並不合適,可以配置將其disable掉。
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class EurekaServerSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable();
}
}
4. 由於Eureka Server開啟了HTTP Basic認證, Eureka Client 也要配置相應的賬號信息才能註冊到Eureka Server上面,需要修改Eureka Client的 application.yml
security:
basic:
enabled: true # 開啟基於HTTP Basic的認證
user:
name: ealenxie # 登陸賬號名
password: zaxscdvfrewq # 登陸密碼
server:
port: 8090
spring:
application:
name: spring-cloud-eureka-client-application
eureka:
client:
service-url:
defaultZone: http://${security.user}:${security.password}@localhost:8761/eureka/ #包含賬號信息的Eureka Server地址
5. 其實對於上面開啟HTTP Basic認證來說,從安全角度考慮,如果暴露在公網很容易被抓包然後破解,所以建議啟用https,用安全證書與密鑰的形式來保證安全。
其實現方式可以參考博客(篇幅原因) : https://www.v2ex.com/t/516287
或者參考《重新定義Spring Cloud實戰》一書 , 61頁章節,啟用https。
Eureka Admin 開源的微服務管控平臺
因為在Spring Cloud的技術棧中,Eureka Server是微服務架構中非常重要的基礎組件。
所以Spring Cloud中國社區為Eureka 註冊中心開源了一個節點監控,服務動態啟停的管控平臺 : Eureka Admin
Eureka Admin可以對註冊的服務實例進行上線,下線,停止等操作,自己就不必再調用Eureka Server的REST API了,很方便。感興趣的道友可以嘗試使用。
基本效果 :
Eureka Admin的github地址 : https://github.com/SpringCloud/eureka-admin
Eureka 也可以跟Spring Boot Admin相結合
1. 只需要搭建一個Spring Boot Admin,然後將其作為Eureka Client註冊到Eureka Server上面,就可以實現完美的整合。Spring Boot Admin簡單搭建流程如下,pom.xml需要加入下面依賴 :
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 在管理界面中與 JMX-beans 進行交互所需要被依賴的 JAR -->
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 主類上面添加@EnableAdminServer,啟用 Spring Boot Admin,和將其註冊到Eureka上面。
package name.ealen;
import de.codecentric.boot.admin.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Created by EalenXie on 2018/11/6 9:23.
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableAdminServer
public class SpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminApplication.class,args);
}
}
3. 簡單配置application.yml,指定Eureka Server,關閉掉安全端口暴露限制。
server:
port: 8889
spring:
application:
name: spring-cloud-boot-admin
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
management:
security:
enabled: false
4. 啟動Eureka Sever應用,和Spring Boot Admin應用,然後訪問localhost:8889,即可以看到Admin的界面。
點開 Details按鈕,可以看到Admin裏面的各種詳細配置信息,內存信息,接口調用次數,甚至是線程數量,都可以一目了然,十分方便。
寫在最後的話
本文參考內容 :
大量參考了《重新定義Spring Cloud實戰》一書的內容 , 個人十分推崇。
參考了周立老師的《Spring Cloud與Docker》一書。
參考了翟永超大神的《Spring Cloud 微服務實戰》一書。
聲明 :
本文是總結根據自身從各路大神所學習到的內容與理解。
個人才疏學淺,如博文有不當之處,望各路大神見諒和幫忙指正。
原創不易,十分感謝各位提出意見和支持。
Spring Cloud Eureka 總結