Spring Cloud Netflix Eureka介紹
1.概述
在本教程中,我們將通過“ Spring Cloud Netflix Eureka
”介紹client-side service
發現。
Client-side service discovery
使服務無需硬編碼主機名和端口即可相互查找和通信。這種體系結構中唯一的“固定點”由service registry
組成,每個服務都必須向該service registry
進行註冊。
缺點是所有客戶端都必須實現某種邏輯才能與此固定點進行交互。假設在實際請求之前進行了額外的網絡往返。
使用Netflix Eureka,每個客戶端可以同時充當服務器,以將其狀態復製到連接的對等方。換句話說,客戶端檢索service registry
的所有已連接對等方的列表,並通過負載平衡算法向所有其他服務發出所有其他請求。
要獲知客戶端的存在,他們必須向註冊表發送心跳信號。
為了實現本文的目標,我們將實現三個microservices
:
-
service registry
(**Eureka Server**
), - 在註冊表(
**Eureka Client**
)上註冊的REST
服務和 - 一個Web應用程序,它將
REST
服務用作支持註冊表的客戶端(Spring Cloud Netflix **Feign Client**
)。
2. Eureka服務器
實施Eureka Server
進行服務註冊非常簡單:
- 將
[spring-cloud-starter-netflix-eureka-server](https://search.maven.org/search?q=spring-cloud-starter-netflix-eureka-server)
到依賴項 - 通過使用
@EnableEurekaServer
註釋在@SpringBootApplication
啟用Eureka服務器 - 配置一些屬性
但是,我們將逐步進行。
首先,我們將創建一個新的Maven項目並將依賴項放入其中。您必須注意,我們正在將[spring-cloud-starter-parent](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-parent%22)
導入到本教程中描述的所有項目中:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
注意:我們可以在Spring的Projects文檔中查看最新的Spring Cloud版本。
接下來,我們將創建主應用程序類:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
最後,我們以YAML
格式配置屬性;因此application.yml
將是我們的配置文件:
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
在這裡,我們正在配置一個應用程序端口– Eureka
服務器的默認端口是8761
。我們告訴內置的Eureka Client
不要向“自己”註冊,因為我們的應用程序應充當服務器。
現在,將瀏覽器指向http:// localhost:8761,以查看Eureka
儀表板,稍後我們將在其中檢查註冊的實例。
目前,我們看到諸如狀態和健康指標之類的基本指標。
3. Eureka客戶端
為了使@SpringBootApplication
能夠發現,我們必須在classpath.
包含一些Spring Discovery Client
(例如spring-cloud-starter-netflix-eureka-client
) classpath.
然後,我們需要使用@EnableDiscoveryClient
或@EnableEurekaClient –
註釋@Configuration
@EnableEurekaClient –
注意,如果我們對類路徑具有spring-cloud-starter-netflix-eureka-client
依賴性,則此註釋是可選的。
後者告訴Spring Boot
明確使用Spring Netflix Eureka進行服務發現。為了使我們的客戶端應用程序具有一些示例壽命,我們還將在pom.xml
包含spring-boot-starter-web
包,並實現REST
控制器。
但是首先,我們將添加依賴項。同樣,我們可以將其留給spring-cloud-starter-parent
依賴項來為我們找出工件版本:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在這裡,我們將實現主要的應用程序類:
@SpringBootApplication
@RestController
public class EurekaClientApplication implements GreetingController {
@Autowired
@Lazy
private EurekaClient eurekaClient;
@Value("${spring.application.name}")
private String appName;
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
@Override
public String greeting() {
return String.format(
"Hello from '%s'!", eurekaClient.getApplication(appName).getName());
}
}
和GreetingController
接口:
public interface GreetingController {
@RequestMapping("/greeting")
String greeting();
}
在這裡,除了接口以外,我們還可以在EurekaClientApplication
類內部簡單地聲明映射。如果我們要在服務器和客戶端之間共享該接口,則該接口可能很有用。
接下來,我們必須使用配置Spring
應用程序名稱來設置application.yml
,以在註冊的應用程序列表中唯一標識我們的客戶端。
我們可以讓Spring Boot
為我們選擇一個隨機端口,因為稍後我們將使用其名稱訪問此服務。
最後,我們必須告訴客戶它必須在哪裡找到註冊表:
spring:
application:
name: spring-cloud-eureka-client
server:
port: 0
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
instance:
preferIpAddress: true
當我們決定以這種方式設置Eureka Client時,我們牢記這種服務以後應該可以輕鬆擴展。
現在,我們將運行客戶端,並將瀏覽器再次指向http://localhost:8761
,以在Eureka儀表板上查看其註冊狀態。通過使用儀表板,我們可以進行進一步的配置,例如將註冊客戶端的主頁與儀表板鏈接以進行管理。但是,配置選項不在本文討論範圍之內。
4. Feign Client
為了使用三個相關的微服務完成我們的項目,我們現在將使用Spring Netflix Feign Client
實現一個使用REST
Web應用程序。
將Feign
視為使用接口與端點進行通信的可發現發現的Spring
RestTemplate
。該接口將在運行時自動實現,並且使用service-names
代替service-urls
。
如果沒有Feign
我們將不得不將EurekaClient
一個實例自動EurekaClient
到我們的控制器中,使用該實例我們可以收到一個以service-name
為對象的服務信息作為Application
對象。
我們將使用此Application
獲取此服務的所有實例的列表,選擇一個合適的InstanceInfo
,然後使用此InstanceInfo
獲取主機名和端口。這樣,我們可以對任何http client
發出標準請求。
例如:
@Autowired
private EurekaClient eurekaClient;
public void doRequest() {
Application application =
eurekaClient.getApplication("spring-cloud-eureka-client");
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
// ...
}
還可以使用RestTemplate
按名稱訪問Eureka
客戶端服務,但是本主題不屬於本文範圍。
要設置Feign Client
項目,我們將在其pom.xml
添加以下四個依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Feign Client
位於[spring-cloud-starter-feign](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-feign%22)
軟件包中。要啟用它,我們必須使用@EnableFeignClients
註釋@Configuration
。要使用它,我們只需使用@FeignClient(“service-name”)
註釋一個接口並將其自動連接到控制器中即可。
創建此類Feign
Clients
一個好方法是使用@RequestMapping
註釋方法創建接口,並將其放入單獨的模塊中。這樣,它們可以在服務器和客戶端之間共享。在服務器端,可以將它們實現為@Controller
,而在客戶端,可以將其擴展和註釋為@FeignClient
。
此外, spring-cloud-starter-eureka package
需要包含在項目中,並通過使用@EnableEurekaClient
註釋主應用程序類來@EnableEurekaClient
。
spring-boot-starter-web
和spring-boot-starter-thymeleaf
依賴關係用於呈現視圖,其中包含從REST
服務中獲取的數據。
這將是我們的Feign Client
界面:
@FeignClient("spring-cloud-eureka-client")
public interface GreetingClient {
@RequestMapping("/greeting")
String greeting();
}
在這裡,我們將實現同時充當控制器的主要應用程序類:
@SpringBootApplication
@EnableFeignClients
@Controller
public class FeignClientApplication {
@Autowired
private GreetingClient greetingClient;
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
@RequestMapping("/get-greeting")
public String greeting(Model model) {
model.addAttribute("greeting", greetingClient.greeting());
return "greeting-view";
}
}
這將是我們視圖的HTML模板:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting Page</title>
</head>
<body>
<h2 th:text="${greeting}"/>
</body>
</html>
至少application.yml
配置文件與上一步中的幾乎相同:
spring:
application:
name: spring-cloud-eureka-feign-client
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
現在我們可以構建並運行此服務。最後,我們將瀏覽器指向http://localhost:8080/get-greeting
,它應顯示如下內容:
Hello from SPRING-CLOUD-EUREKA-CLIENT!
5.'TransportException TransportException:
無法在任何已知服務器上執行請求'
在運行Eureka服務器時,我們經常遇到以下異常:
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
基本上,這是由於application.properties
或application.yml
的錯誤配置導致的。 Eureka
為客戶端提供了兩個可配置的屬性。
-
registerWithEureka:
如果我們將此屬性設置為true
則在服務器啟動時,內置客戶端將嘗試向Eureka服務器註冊自身。 -
fetchRegistry:
如果我們將此屬性配置為true,則內置客戶端將嘗試獲取Eureka
註冊表。
現在,當我們啟動Eureka服務器時,我們不想註冊內置客戶端來使用server對其進行配置。
如果在啟動服務器時將上述屬性標記為true
(或默認情況下未將其配置為true
),則內置客戶端會嘗試向Eureka
服務器註冊自身,並嘗試獲取尚不可用的註冊表。結果,我們得到TransportException
。
因此,我們永遠不要在Eureka
服務器應用程序中將這些屬性配置為true
。下面給出了應放在application.yml
中的正確設置:
eureka:
client:
registerWithEureka: false
fetchRegistry: false
六,結論
如我們所見,我們現在能夠使用Spring Netflix Eureka Server
實施服務註冊表並向其中註冊一些Eureka Clients
。
由於第3步中的Eureka Client
監聽隨機選擇的端口,因此如果沒有註冊表中的信息,它就不會知道其位置。使用Feign Client
和我們的註冊表,即使位置發生更改,我們也可以定位和使用REST
服務。
最後,我們對在微服務架構中使用服務發現有了一個全面了解。
像往常一樣,您會[on GitHub ,](https://github.com/eugenp/tutorials/tree/master/spring-cloud/spring-cloud-eureka)
找到源代碼[on GitHub ,](https://github.com/eugenp/tutorials/tree/master/spring-cloud/spring-cloud-eureka)
該源代碼還包括一組與Docker
相關的文件,可與docker-compose
一起使用來從我們的項目中創建容器。