1. 程式人生 > >Spring Cloud Eureka 總結

Spring Cloud Eureka 總結

admins dap jar throw cati 註解 自己的 pack add

寫在前面的話(給自己)

為了鞏固自身學習,從今天(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 總結