Spring Cloud學習---服務註冊與發現(Eureka)
本博目錄:
一、 服務註冊與發現簡介
如何使用Spring Cloud搭建服務註冊與發現模組。
這裡我們會用到Spring Cloud Netflix,該專案是Spring Cloud的子專案之一,Eureka是Spring Cloud Netflix的一個子模組,也是核心模組之一。用於雲端服務發現,一個基於REST的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。通過一些簡單的註解,開發者就可以快速的在應用中使用Eureka。
Eureka 原理,如圖所示:
由圖可知,Eureka包括兩個元件:Eureka Server 和Eureka Client
Eureka Server:提供服務發現的能力,客戶端微服務啟動時,會向Eureka Server註冊自己的資訊,EurekaServer 會儲存這些資訊。
Eureka Client:是一個Java客戶端,和Eureka Server 進行互動。
注:微服務啟動後,會週期性(30秒)向Eureka Server 傳送心跳以續約自己的“租期”,如果Eureka Server在一定時間之內沒有接收到某個服務的心跳,EurekaServer會登出該例項(90秒之內),綜上,Eureka通過心跳檢測。客戶端快取等機制,提高了系統的靈活性、可伸縮性。
二、編寫 Eureka Server (服務註冊中心)
建立一個基礎的Spring Boot工程,並在pom.xml中引入需要的依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
通過@EnableEurekaServer註解啟動一個服務註冊中心,在Spring Boot應用啟動類中新增這個註解就能開啟此功能,如下:
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerDemoApplication.class, args);
}
}
在預設設定下,該服務註冊中心也會將自己作為客戶端來嘗試註冊它自己,所以我們需要禁用它的客戶端註冊行為,只需要在application.properties中增加如下配置:
server.port=8671
## 是否將自己註冊到Eureka Server 預設為true
eureka.client.register-with-eureka=false
## 是否從Eureka Server 獲取註冊資訊,預設為true
eureka.client.fetch-registry=false
## 與Eureka server 互動的地址,查詢服務和註冊服務都需要這個地址,多個地址使用“,”分割
eureka.client.service-url.defaultZone=http://localhost:8671/eureka/
三、 Eureka Client (服務提供者)
首先,建立一個基本的Spring Boot應用,在pom.xml中,加入如下配置:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在主類中通過加上@EnableDiscoveryClient註解,該註解能啟用Eureka中的DiscoveryClient實現,才能實現Controller中對服務資訊的輸出。
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientDemoApplication.class, args);
}
}
application.properties專案配置:
##指定註冊到Eureka Server上的應用名稱
spring.application.name=compute-service
server.port=8672
eureka.client.serviceUrl.defaultZone=http://localhost:8671/eureka/
四、 為Eureka提供使用者認證
在之前的例子中,Eureka Server 是允許匿名登入的。新增spring-boot-starter-security的依賴,使得Eureka Server需要登入才能訪問
在pom檔案中新增如下配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
配置檔案中新增:
//開啟基於HTTP basic的認證
security.basic.enabled=true
//登入賬號和密碼
security.user.name=chaole
security.user.password=chao1111
啟動eureka Server ,如圖輸入賬號和密碼即可登入
五、 Eureka自我保護模式
預設情況下,如果Eureka Server在一定時間內沒有接收到某個微服務例項的心跳,Eureka Server將會登出該例項(預設90秒)。但是當網路分割槽故障發生時,微服務與Eureka Server之間無法正常通訊,這就可能變得非常危險了—-因為微服務本身是健康的,此時本不應該登出這個微服務。
Eureka Server通過“自我保護模式”來解決這個問題—-當Eureka Server節點在短時間內丟失過多客戶端時(可能發生了網路分割槽故障),那麼這個節點就會進入自我保護模式。一旦進入該模式,Eureka Server就會保護服務登錄檔中的資訊,不再刪除服務登錄檔中的資料(也就是不會登出任何微服務)。當網路故障恢復後,該Eureka Server節點會自動退出自我保護模式。
自我保護模式是一種對網路異常的安全保護措施。使用自我保護模式,而已讓Eureka叢集更加的健壯、穩定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation=false來禁用自我保護模式
—- — —— —— —- —– —–可參考《Spring cloud 與 docker 微服務架構實戰》
六、 帶你出坑
在編寫Eureka Server 時,出現了以下錯誤
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.swc.EurekaServerDemoApplication]; nested exception is java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.cloud.netflix.eureka.server.EurekaServerConfiguration
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:616) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:299) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:198) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:270) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:93) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
at com.swc.EurekaServerDemoApplication.main(EurekaServerDemoApplication.java:12) [classes/:na]
Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.cloud.netflix.eureka.server.EurekaServerConfiguration
at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:163) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.retrieveBeanMethodMetadata(ConfigurationClassParser.java:380) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:314) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:606) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
... 17 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/context/embedded/FilterRegistrationBean
at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_131]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_131]
at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_131]
at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:152) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]
... 21 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.embedded.FilterRegistrationBean
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_131]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_131]
... 25 common frames omitted
最終才發現,是在pom檔案中,spring cloud 的版本有誤,我引入的版本是
這個版本對應的spring boot 版本 是 1.3.5.RELEASE 但我的spring boot 版本是1.5.7.RELEASE,最後修改springcloud版本到 Camden.SR6 即可。