【系統架構理論】一篇文章精通:Spring Cloud Netflix Eureka

是官方文檔的總結html

http://spring.io/projects/spring-cloud-netflix#overviewjava

講解基於2.0.2版本官方文檔git

https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.0.2.RELEASE/single/spring-cloud-netflix.htmlgithub

Netflix提供瞭如下功能:web

  • 服務發現:能夠註冊Eureka實例,客戶端可使用Spring的beans來發現這些實例
  • 服務發現:能夠經過聲明式Java配置來建立一個嵌入式Eureka服務器
  • 斷路器:能夠經過簡單的註解修飾方法來建立一個斷路器客戶端
  • 斷路器:使用聲明式Java配置能夠嵌入一個Hystrix儀表盤
  • 客戶端負載均衡器:Ribbon
  • 外部配置:從Spring環境到Archaius的橋樑(容許使用SpringBoot約定對Netflix組件進行本地配置)
  • 路由器和過濾器:Zuul過濾器的自動從新配置,和用於反向建立代理的配置方法的簡單約定。

 

1、服務發現:Eureka客戶端spring

服務發現是基於微服務的體系結構的核心原則之一。嘗試手工配置每一個客戶端或某種形式的約定可能很困難,並且很脆弱。Eureka是Netflix服務發現服務器和客戶端。能夠將服務器配置和部署爲高度可用,每一個服務器都將註冊服務的狀態複製給其餘服務器。apache

1.一、包含依賴後端

group ID:org.springframework.cloud緩存

artifact ID:spring-cloud-starter-netflix-eureka-client安全

具體版本能夠查看http://spring.io/projects/spring-cloud,查看對應Spring Cloud版本匹配的Eureka客戶端版本

1.二、註冊到Eureka中

當客戶端向Eureka註冊時,它會提供關於本身的元數據,例如主機、端口、健康指示符URL、主頁和其餘詳細信息。Eureka從屬於服務的每一個實例接收心跳消息。若是心跳在可配置的時間表上失敗,則一般從註冊表中刪除該實例。

@SpringBootApplication
@RestController
public class Application {
    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }
    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }
}

 

使用Spring Boot應用,只要classpath中包含了spring-cloud-starter-netflix-eureka-client,應用就會自動註冊到Eureka服務器

要求經過配置來指向Eureka服務器

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

 

defaultZone:當客戶端沒有明確指向一個Eureka服務器時,會採用這個默認URL。

默認應用程序名稱(即服務ID)、虛擬主機和非安全端口(從環境獲取)分別爲${Spring.application.name}、${Spring.application.name}和${server.port}。

當classpath中包含了spring-cloud-starter-netflix-eureka-client時,使這個應用既是一個Eureka實例(把本身註冊到Eureka服務器中),也是一個Eureka客戶端(他能夠查詢Eureka服務器定位其它服務)。

實例行爲能夠經過eureka.instance.*的屬性來配置,也能夠經過設置spring.application.name(做爲Eureka服務的ID或VIP)並做爲實例行爲的默認值。

更多配置屬性的信息,查看這2個Bean:EurekaInstanceConfigBean、EurekaClientConfigBean

https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java

https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java

禁止使用Eureka客戶端,能夠設置eureka.client.enabled爲false

1.三、經過Eureka服務器的驗證

在eureka.client.serviceUrl.defaultZone的路徑中嵌入一個憑證(http://user:password@localhost:8761/eureka),會自動爲你提供一個HTTP basic認證。

若是須要更加複雜的需求,能夠建立一個DiscoveryClientOptionalArgs的Bean,併爲他注入一個ClientFilter實例,用於客戶端請求服務器時使用。

因爲Eureka中的限制,不可能支持每一個服務器的basic認證憑據,所以只使用了找到的第一組。

1.四、狀態頁面和健康指標

默認路徑是Spring Boot中Actuator下的/info和/health地址,

若是你使用非默認上下文路徑或非默認servlet路徑,則須要修改他們。

eureka:
  instance:
    statusPageUrlPath: ${server.servletPath}/info
    healthCheckUrlPath: ${server.servletPath}/health

 

在Dalston版本中,還要求在更改管理上下文路徑時設置狀態和健康檢查URL。從Edgware開始,這一要求就被刪除了。

1.五、註冊一個安全的應用

若是應用須要經過HTTPS傳輸,能夠設置2個屬性

eureka.instance.[nonSecurePortEnabled]=[false]

eureka.instance.[securePortEnabled]=[true]

設置了以後,Eureka客戶端會返回https的地址。Eureka的實例信息也會有一個安全的健康檢查URL

因爲Eureka的設計,status頁、home頁並不會由於這個設置變成安全連接,須要手動更改。

eureka:
  instance:
    statusPageUrl: https://${eureka.hostname}/info
    healthCheckUrl: https://${eureka.hostname}/health
    homePageUrl: https://${eureka.hostname}/

 ${eureka.hostname}是一個本地佔位符,最新版本的Eureka才支持;也可使用Spring佔位符${eureka.instance.hostName}

If your application runs behind a proxy, and the SSL termination is in the proxy (for example, if you run in Cloud Foundry or other platforms as a service), then you need to ensure that the proxy 「forwarded」 headers are intercepted and handled by the application. If the Tomcat container embedded in a Spring Boot application has explicit configuration for the 'X-Forwarded-\*` headers, this happens automatically. The links rendered by your app to itself being wrong (the wrong host, port, or protocol) is a sign that you got this configuration wrong.

 

1.六、Eureka健康檢查

默認狀況下,Eureka使用心跳機制決定一個客戶端是否在線。

除非特殊設置,Eureka客戶端不會經過Actuator來傳遞應用的健康信息。

能夠開啓Eureka健康檢查,

。。待補充

 

1.七、Eureka實例和客戶端的元數據

使用eureka.instance.metadataMap能夠添加元數據,這些元數據能夠在遠程客戶端中獲取。

通常元數據不會改變客戶端的行爲,除了那些客戶端能識別到這些元數據的含義,有些元數據Spring Cloud已經在使用。

這個是用於部署在雲平臺,而後能夠獲取平臺的一些數據?

 

1.八、使用Eureka客戶端

Eureka客戶端,能夠經過Eureka服務器來發現其餘服務的實例。

可使用com.netflix.discovery.EurekaClient

@Autowired
private EurekaClient discoveryClient;

public String serviceUrl() {
    InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false);
    return instance.getHomePageUrl();
}

 

Do not use the EurekaClient in a @PostConstruct method or in a @Scheduledmethod (or anywhere where the ApplicationContext might not be started yet). It is initialized in a SmartLifecycle (with phase=0), so the earliest you can rely on it being available is in another SmartLifecycle with a higher phase.

1.8.一、禁用Jersey

默認狀況下Eureka客戶端使用Jersey進行HTTP通訊。

能夠經過排除依賴禁用他,而後Spring Cloud會經過Spring RestTemplate來進行HTTP通訊。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-apache-client4</artifactId>
        </exclusion>
    </exclusions>
</dependency>

 

1.九、本地Netflix Eureka客戶端的替代方案

通常不會使用上面的EurekaClient來獲取真正的物理地址。

Spring Cloud提供了一個Feign和Spring RestTemplate,能夠經過Eureka服務的識別碼(如服務ID或VIP)來訪問服務,而不是經過物理地址。

若是要用一個固定服務器物理地址列表來配置Ribbon,能夠經過設置<client>.ribbon.listOfServers,使用一個逗號分隔的物理地址(或hostnames),<client>是客戶端的ID

也可使用org.springframework.cloud.client.discovery.DiscoveryClient,包含針對服務發現客戶端(不只是Netflix)的一些API

@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri();
    }
    return null;
}

 

1.十、爲何註冊一個服務這麼慢?

Being an instance also involves a periodic heartbeat to the registry (through the client’s serviceUrl) with a default duration of 30 seconds. A service is not available for discovery by clients until the instance, the server, and the client all have the same metadata in their local cache (so it could take 3 heartbeats). You can change the period by setting eureka.instance.leaseRenewalIntervalInSeconds. Setting it to a value of less than 30 speeds up the process of getting clients connected to other services. In production, it is probably better to stick with the default, because of internal computations in the server that make assumptions about the lease renewal period.

做爲一個實例,還涉及到註冊表的週期性心跳(經過客戶端的serviceUrl),默認持續時間爲30秒。直到實例、服務器和客戶端在其本地緩存中都有相同的元數據(所以可能須要3次心跳),客戶端才能發現服務。能夠經過設置eureka.instance.leaseRenewalIntervalInSeconds.更改期間將其設置爲小於30的值能夠加快將客戶端鏈接到其餘服務的過程。在生產中,可能最好仍是堅持默認的作法,由於服務器中的內部計算會對租約續訂期作出假設。

 

1.十一、分區

若是你的Eureka客戶端分開了幾個區域,而且但願調用服務時,先在相同區域調用服務,而後才調用其它區域的服務。

這就須要進行正確的配置。

首先,要吧Eureka服務器部署到每個區域,而且他們之間是對等服務器

而後,你須要告訴Eureka服務器,你的服務是在哪個區域,能夠經過修改metadataMap屬性來實現

//Service 1 in Zone 1
eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true
//Service 1 in Zone 2
eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true

 

2、Eureka服務器

2.一、如何包含Eureka服務器

group ID:org.springframework.cloud

artifact ID:spring-cloud-starter-netflix-eureka-server

具體版本能夠查看http://spring.io/projects/spring-cloud,查看對應Spring Cloud版本匹配的Eureka客戶端版本

2.二、運行一個Eureka服務器

@SpringBootApplication
@EnableEurekaServer
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

 

服務器有一個首頁和一些HTTP API端點在/eureka/*下

有幾個Eureka的討論網站?

https://github.com/cfregly/fluxcapacitor/wiki/NetflixOSS-FAQ#eureka-service-discovery-load-balancer

https://groups.google.com/forum/?fromgroups#!topic/eureka_netflix/g3p2r7gHnN0

Due to Gradle’s dependency resolution rules and the lack of a parent bom feature, depending on spring-cloud-starter-netflix-eureka-server can cause failures on application startup. To remedy this issue, add the Spring Boot Gradle plugin and import the Spring cloud starter parent bom as follows:

build.gradle. 

buildscript {
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
  }
}

apply plugin: "spring-boot" dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}" } }

 

2.三、高可用,分區與區域(High Availability, Zones and Regions)

Eureka沒有後端存儲,可是服務實例必須保持發送心跳消息來保持他們的註冊是最新的(在內存中實現)。

客戶端也有一個對Eureka註冊服務的內存緩存,這使得不用每一次調用服務,都去查找一次註冊的服務。

默認狀況下,每一個Eureka服務器也是Eureka客戶端,須要(至少一個)服務URL來定位對等服務器。若是你不提供,服務也能運行,只是在日誌中會增長大量沒法向服務器註冊的信息。

 

2.四、單例模式

經過2個緩存(服務器、客戶端)以及心跳機制,使得只要提供一些監控或者運行時彈性(如Cloud Foundry)保持一個Eureka服務器持續運行,他就有很強的抗錯誤彈性。

在單例模式下,你能夠考慮關閉掉客戶端行爲,就不會一直嘗試註冊到不存在的服務器路徑失敗

關閉掉客戶端

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

 

注意defaultZone指向本地Eureka實例

 

2.五、同伴意識

Eureka能夠經過運行多個實例,並互相註冊,來實現更高可用高彈性。

實際上,這是一個默認行爲,只須要指定一個可用的serviceUrl給同伴便可。

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1/eureka/

在前面的示例中,咱們有一個YAML文件,經過在不一樣的Spring profiles中運行該文件,能夠在兩個主機(peer 1和peer 2)上運行相同的服務器。您可使用此配置來經過操做/etc/host來解析主機名來測試單個主機上的對等感知(在生產中這樣作沒有多大價值)。實際上,若是在知道本身主機名的機器上運行(默認狀況下,使用java.net.InetAddress查找),則不須要eureka.instance.hostname。

你能夠添加多個同伴到一個系統中,只要他們互相經過至少一個鏈接而相連,他們之間的註冊實例就會互相同步。若是這些同伴是物理隔離的,那麼這個系統就有能力抵抗腦裂(split-brain)失敗。

eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2

---
spring:
  profiles: peer3
eureka:
  instance:
    hostname: peer3

 

2.六、何時使用IP地址

在某些狀況下,Eureka最好是公佈服務的IP地址,而不是主機名。

設置eureka.instance.preferIpAddress爲true,程序註冊到Eureka中的時候,會使用IP地址二不是hostname

若是主機名不能由Java肯定,則將IP地址發送給Eureka。唯一明確設置主機名的方法是設置eureka.instance.hostname屬性。能夠經過使用環境變量(例如eureka.instance.hostname=${host_name})在運行時設置主機名。

2.七、保護Eureka服務器

您只需經過spring-boot-starter-security將Spring Security添加到服務器的類路徑中,就能夠保護您的Eureka服務器。默認狀況下,當Spring Security在類路徑上時,它將要求在嚮應用程序的每一個請求中發送一個有效的CSRF令牌。Eureka客戶端一般不會擁有有效的跨站點請求僞造(CSRF)令牌,您須要對/eureka/*端點禁用此要求。例如:

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}
相關文章
相關標籤/搜索