服務發現和註冊
我們有了兩個服務。服務A的IP地址是192.168.0.1,埠9001,服務B的IP地址192.168.0.2,埠9002。我們的客戶端需要呼叫服務A和服務B,我們只需要在配置檔案中寫上服務A和服務B的IP地址即可。
此時,服務A的伺服器負載有點高,我們需要臨時增加服務A的例項,IP192.168.0.3,埠9001。但是我們的客戶端要怎麼才能呼叫新的例項?
常規來說,我們可以有以下幾種方法:
網路代理方式
如果是http方式通訊的服務,可以增加一個nginx做反向代理,轉發到兩個服務A的例項上。
如果是RPC服務則可以增加一個LVS或HAProxy或者ESB之類的網路代理,客戶端配置網路代理地址。
服務B我們再來一套一樣的配置,這時候又來了服務C、服務D、服務E...,好吧我們好還要再多維護同樣多的網路代理。此外,所有的服務呼叫服務呼叫都必須經過網路代理,我們還必須保證代理的高可用。最後,陷入運維災難。DNS方式
給服務A配置一個域名,然後通過配置兩個A記錄分別指向兩個服務A的例項,客戶端只要配置服務A的域名即可。
這種方式也存在問題,首先DNS沒有辦法管理埠,我們的埠還是隻能寫在每個客戶端的配置檔案中。此外DNS輪詢負載均衡能力太弱,可能會導致客戶端負載的不均衡。
現在有了服務發現和序號產生器制,我們可以更合理的解決這個問題。
服務發現和註冊,參考字面意思很容易理解,其核心部分可以理解為一個服務登錄檔。服務啟動時,將自己的資訊註冊到登錄檔中。登錄檔需要每一定時間訪問下已經註冊的服務,將沒有響應的服務從登錄檔中刪除。最終讓客戶端拿到正常執行的服務地址。
此時,我們的服務登錄檔必須具備分散式、高可用、強一致性等特點。
目前,業界開源的服務發現和註冊產品有很多,比較流行的主要有:ZooKeeper,Etcd,Consul,Eureka等。
下面介紹下今天的主角,Consul。
Consul
Consul是一個服務發現和註冊的工具,其具有分散式、高擴充套件效能特點。
Consul主要包含如下功能:
- 服務發現: 支援 http 和 dns 兩種協議的服務註冊和發現方式。
- 監控檢查: 支援多種方式的健康檢查。
- Key/Value儲存: 支援通過HTTP API實現分散式KV資料儲存。
- 多資料中心支援:支援任意數量資料中心。
上圖是官網提供的一個事例系統圖,圖中的Server是consul服務端高可用叢集,Client是consul客戶端。consul客戶端不儲存資料,客戶端將接收到的請求轉發給響應的Server端。Server之間通過區域網或廣域網通訊實現資料一致性。每個Server或Client都是一個consul agent。Consul叢集間使用了GOSSIP協議通訊和raft一致性演算法。
使用Consul也非常簡單,基本可以做到開箱即用。
下載應用後可以通過簡單的指令碼啟動服務端和客戶端:
$ consul
usage: consul [--version] [--help] <command> [<args>]
Available commands are:
agent Runs a Consul agent
configtest Validate config file
event Fire a new event
exec Executes a command on Consul nodes
force-leave Forces a member of the cluster to enter the "left" state
info Provides debugging information for operators
join Tell Consul agent to join cluster
keygen Generates a new encryption key
keyring Manages gossip layer encryption keys
kv Interact with the key-value store
leave Gracefully leaves the Consul cluster and shuts down
lock Execute a command holding a lock
maint Controls node or service maintenance mode
members Lists the members of a Consul cluster
monitor Stream logs from a Consul agent
operator Provides cluster-level tools for Consul operators
reload Triggers the agent to reload configuration files
rtt Estimates network round trip time between nodes
version Prints the Consul version
watch Watch for changes in Consul
執行consul agent
加上相關的引數,就可以啟動一個consul server 或者 client。
接著,我們可以通過http api註冊服務,向/v1/catalog/register傳送PUT動作的JSON報文:
{
"Datacenter": "dc1",
"Node": "foobar",
"Address": "192.168.10.10",
"Service": { //註冊的服務資訊
"ID": "redis1",
"Service": "redis",
"Tags": [
"primary",
"v1"
],
"Address": "127.0.0.1",
"Port": 8000
},
"Check": { //註冊健康檢查
"Node": "foobar",
"CheckID": "service:redis1",
"Name": "Redis health check",
"Notes": "Script based health check",
"Status": "passing",
"ServiceID": "redis1"
}
}
註冊後,我們可以在consul自帶的WEB UI中看到剛剛註冊的服務:
與Spring Cloud整合
如果你的服務正好使用spring boot構建,不妨試試Spring Cloud Consul。
Spring Cloud Consul通過幾個簡單的註解,就可以整合諸多consul功能,讓你更方便的治理你的服務。
@SpringBootApplication
@EnableDiscoveryClient //只要新增這個註解即可向配置號的consul註冊服務
@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 actuator來註冊監控檢查:
spring:
cloud:
consul:
discovery:
healthCheckPath: ${management.contextPath}/health
healthCheckInterval: 15s
Spring Cloud支援 Feign 或者 Spring RestTemplate 通過服務發現來呼叫服務,也可以使用org.springframework.cloud.client.discovery.DiscoveryClient:
@Autowired //注入一個DiscoveryClient
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;
}
consul除了可以用作服務治理的工具,還可以利用其KV儲存能力,實現分散式服務配置或分散式鎖等功能。各位感興趣的童鞋可以去consul官網,學習更多的內容。
最後,都看到這了,就順手點個贊吧~~~
參考資料:
https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/
https://highops.com/insights/service-discovery-6-questions-to-4-experts/
https://www.consul.io/
http://cloud.spring.io/spring-cloud-consul/