1.概述
Consul 是 HashiCorp 公司推出的開源工具,用於實現分佈式系統的服務發現與配置。與其他分佈式服務註冊與發現的方案,Consul的方案更“一站式”,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value存儲、多數據中心方案,不再需要依賴其他工具(比如ZooKeeper等)。
Consul是一個工具,提供解決微服務架構中一些最常見挑戰的組件:
- 服務發現 - 自動註冊和取消註冊服務實例的網絡位置
- 運行狀況檢查 - 檢測服務實例何時啓動並運行
- 分佈式配置 - 確保所有服務實例使用相同的配置
Spring Cloud Consul 項目提供Spring Boot 集成 Consul的非常輕鬆的方法。在本文中,我們將瞭解如何配置Spring Boot應用程序來使用Consul。
2.先決條件
首先,建議您快速查看Consul及其所有功能。
在本文中,我們將使用在localhost:8500上運行的Consul代理。有關如何安裝Consul和運行代理的更多詳細信息,請參閱此鏈接。
在windows下安裝Consul,
去官網下載:https://www.consul.io/downloads.html
解壓到某個目錄下。cmd啓動:
consul agent -dev
3.引入依賴
首先,我們需要在我們的pom.xml中添加spring-cloud-starter-consul-all依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
4.服務發現
4.1 服務註冊
讓我們編寫我們的第一個Spring Boot應用程序並與正在運行的Consul代理連接:
@SpringBootApplication
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceDiscoveryApplication.class).web(true).run(args);
}
}
默認情況下,Spring Boot將嘗試連接到localhost:8500上的Consul代理。要使用其他設置,我們需要更新application.yml文件:
spring:
application:
name: myApp
cloud:
consul:
host: localhost
port: 8500
然後,我們在瀏覽器 http://localhost:8500 訪問Consul代理的站點,我們將看到我們的應用程序在Consul中正確註冊。
要想自定義顯示的標識符,我們需要使用另一個表達式更新屬性spring.cloud.discovery.instanceId:
spring:
application:
name: myApp
cloud:
consul:
discovery:
instanceId: ${spring.application.name}:${random.value}
如果我們再次運行此應用程序,我們將看到它是使用標識符“MyApp”加上隨機值註冊的。使用random.value是想在本地機器上運行應用程序的多個實例。
如果想要禁用Service Discovery,我們可以將屬性spring.cloud.consul.discovery.enabled設置爲false。
4.2 尋找服務
我們已經在Consul中註冊了我們的應用程序,但客戶如何找到服務端點呢?我們需要一個客戶端服務來從Consul中獲取運行和可用的服務。
Spring 爲此提供了DiscoveryClient API,我們可以使用@EnableDiscoveryClient註釋啓用它:
@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryClientApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(DiscoveryClientApplication.class).web(true).run(args);
}
}
然後,我們可以將DiscoveryClient bean注入到我們的controller控制器:
@RestController
public class DiscoveryClientController {
@Autowired
private DiscoveryClient discoveryClient;
public Optional<URI> serviceUrl() {
return discoveryClient.getInstances("myApp")
.stream()
.map(si -> si.getUri());
.findFirst()
}
}
最後,我們將定義我們的應用程序端點:
@GetMapping("/discoveryClient")
public String discoveryPing() throws RestClientException, ServiceUnavailableException {
URI service = serviceUrl().map(s -> s.resolve("/ping")).orElseThrow(ServiceUnavailableException::new);
return restTemplate.getForEntity(service, String.class).getBody();
}
@GetMapping("/ping")
public String ping() {
return "Client ping";
}
其中“myApp/ping”的路徑是Spring應用程序的名稱與服務端點。Consul將提供名爲“myApp”的所有可用應用程序。
5.健康檢查
Consul會定期檢查服務端點的運行狀況。
默認情況下,如果應用程序啓動,Spring會訪問運行狀況端點以返回200 OK來判斷服務是正常的。如果我們想要自定義端點,我們必須更新application.yml:
spring:
cloud:
consul:
discovery:
healthCheckPath: /my-health-check
healthCheckInterval: 20s
Consul將每20秒輪詢一次“/my-health-check”端點。
假設我們故意將自定義的運行狀態檢查服務返回FORBIDDEN狀態:
@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
String message = "Testing my healh check function";
return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}
如果我們去Consul代理網站查看,我們會看到我們的應用程序健康檢測是失敗的。要解決此問題,“/my-health-check”服務應返回HTTP 200 OK狀態代碼。
Consul代理網站截圖
健康檢測詳情
6.分佈式配置
此功能允許在所有服務之間同步配置。Consul將監視任何配置更改,然後觸發所有服務的更新。
首先,我們需要將spring-cloud-starter-consul-config依賴項添加到我們的pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
我們還需要將Consul和Spring應用程序的設置從application.yml文件移動到Spring首先加載的bootstrap.yml文件中。
然後,我們需要啓用Spring Cloud Consul Config:
spring:
application:
name: myPro
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
server:
port: 8509
Spring Cloud Consul Config將在“/config/myPro”中查找Consul中的屬性。因此,如果我們有一個名爲“my.prop”的屬性,我們需要在Consul代理站點中創建此屬性。
我們可以通過訪問“KEY/VALUE”界面來創建屬性,然後在“Create Key”表單中輸入“/config/myPro/my/prop”,填入“Hello World”作爲值。最後保存此值。
現在,讓我們看看帶有注入屬性的控制器是什麼樣的:
@RestController
public class DistributedPropertiesController {
@Value("${my.prop}")
String value;
@Autowired
private MyProperties properties;
@GetMapping("/getConfigFromValue")
public String getConfigFromValue() {
return value;
}
@GetMapping("/getConfigFromProperty")
public String getConfigFromProperty() {
return properties.getProp();
}
}
MyProperties類:
@RefreshScope
@Configuration
@ConfigurationProperties("my")
public class MyProperties {
private String prop;
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
}
如果我們運行應用程序,則通過字段值和屬性來取值都會獲得“Hello World”值。
6.1 更新配置
如何在不重新啓動Spring Boot應用程序的情況下更新配置?
我們返回Consul代理站點並使用“New Hello World”更新屬性“/config/myPro/my/prop ”,而其他不變。則字段屬性將更新爲預期的那樣:“New Hello World”。
這是因爲字段屬性是MyProperties類具有@RefreshScope註釋。使用@RefreshScope註釋註釋的所有bean 將在配置更改後刷新。
在實際應用場景中我們不應該直接在Consul中設置屬性,我們應該將它們永久存儲在某個地方。我們可以使用一個Config Server來完成此操作。
7. 結論
在本文中,我們已經瞭解瞭如何設置Spring Boot應用程序以與Consul一起使用以進行服務發現,自定義運行狀況檢查規則和共享分佈式配置。
像往常一樣,可以在GitHub上找到消息來源。