第一篇:SpringCloud 構建微服務系統之服務註冊和發現(consul)
今天我們要學習的是consul在soringcloud中的使用。首先學習consul之前,我們應該看看consul的官網,對它有一個初步的認識。
1. consul 官網 (https://www.consul.io)
2. consul 簡介
consul是google開源的一個使用go語言開發的服務發現、配置管理中心服務。內建了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value儲存、多資料中心方案,不再需要依賴其他工具(比如ZooKeeper等)。服務部署簡單,只有一個可執行的二進位制的包。每個節點都需要執行agent,他有兩種執行模式server和client。每個資料中心官方建議需要3或5個server節點以保證資料安全,同時保證server-leader的選舉能夠正確的進行。
3.consul基本概念
- client
CLIENT表示consul的client模式,就是客戶端模式。是consul節點的一種模式,這種模式下,所有註冊到當前節點的服務會被轉發到SERVER,本身是不持久化這些資訊。
- server
SERVER表示consul的server模式,表明這個consul是個server,這種模式下,功能和CLIENT都一樣,唯一不同的是,它會把所有的資訊持久化的本地,這樣遇到故障,資訊是可以被保留的。
- server-leader
中間那個SERVER下面有LEADER的字眼,表明這個SERVER是它們的老大,它和其它SERVER不一樣的一點是,它需要負責同步註冊的資訊給其它的SERVER,同時也要負責各個節點的健康監測。
- raft
server節點之間的資料一致性保證,一致性協議使用的是raft,而zookeeper用的paxos,etcd採用的也是taft。
- 服務發現協議
consul採用http和dns協議,etcd只支援http
- 服務註冊
consul支援兩種方式實現服務註冊,一種是通過consul的服務註冊http API,由服務自己呼叫API實現註冊,另一種方式是通過json個是的配置檔案實現註冊,將需要註冊的服務以json格式的配置檔案給出。consul官方建議使用第二種方式。
- 服務發現
consul支援兩種方式實現服務發現,一種是通過http API來查詢有哪些服務,另外一種是通過consul agent 自帶的DNS(8600埠),域名是以NAME.service.consul的形式給出,NAME即在定義的服務配置檔案中,服務的名稱。DNS方式可以通過check的方式檢查服務。
- 服務間的通訊協議
Consul使用gossip協議管理成員關係、廣播訊息到整個叢集,他有兩個gossip pool(LAN pool和WAN pool),LAN pool是同一個資料中心內部通訊的,WAN pool是多個數據中心通訊的,LAN pool有多個,WAN pool只有一個。
4.consul架構圖
5.Consul常用命令
5.1 agent 執行一個consul agent
consul agent -dev
5.2 join 將agent加入到consul叢集
consul join IP
5.3 members 列出consul cluster的members
consul members
5.4 leave 將節點移除所在叢集
consul leave
6.consul安裝和啟動
點選“download”下載:使用命令啟動
consul agent -dev
啟動成功之後在地址:http://localhost:8500
7.consul服務的發現與註冊
7.1 註冊服務
使用HTTP API 註冊個服務,使用[介面API](https://www.consul.io/api/agent/service.html API)呼叫
呼叫 http://localhost:8500/v1/agent/service/register PUT 註冊一個服務。request body:
{
"ID": "userServiceId", //服務id
"Name": "userService", //服務名
"Tags": [ //服務的tag,自定義,可以根據這個tag來區分同一個服務名的服務
"primary",
"v1"
],
"Address": "127.0.0.1",//服務註冊到consul的IP,服務發現,發現的就是這個IP
"Port": 9000, //服務註冊consul的PORT,發現的就是這個PORT
"EnableTagOverride": false,
"Check": { //健康檢查部分
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com", //指定健康檢查的URL,呼叫後只要返回20X,consul都認為是健康的
"Interval": "10s" //健康檢查間隔時間,每隔10s,呼叫一次上面的URL
}
}
使用curl呼叫
curl http://127.0.0.1:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
"ID": "userServiceId",
"Name": "userService",
"Tags": [
"primary",
"v1"
],
"Address": "127.0.0.1",
"Port": 8000,
"EnableTagOverride": false,
"Check": {
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com",
"Interval": "10s"
}
}'
結果
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 288 0 0 100 288 0 18000 --:--:-- --:--:-- --:--:-- 18000HTTP/1.1 200 OK
Vary: Accept-Encoding
Date: Wed, 26 Dec 2018 05:11:32 GMT
Content-Length: 0
7.2 發現個服務
剛剛註冊了名為userService的服務,我們現在發現(查詢)下這個服務
curl http://127.0.0.1:8500/v1/catalog/service/userService
返回的響應:
curl http://127.0.0.1:8500/v1/catalog/service/userService
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 891 100 891 0 0 28741 0 --:--:-- --:--:-- --:--:-- 28741[
{
"ID": "9b831a00-ae68-d575-5e51-df193897b834",
"Node": "vip-PC",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"NodeMeta": {
"consul-network-segment": ""
},
"ServiceKind": "",
"ServiceID": "userServiceId",
"ServiceName": "userService",
"ServiceTags": [
"primary",
"v1"
],
"ServiceAddress": "127.0.0.1",
"ServiceWeights": {
"Passing": 1,
"Warning": 1
},
"ServiceMeta": {},
"ServicePort": 8000,
"ServiceEnableTagOverride": false,
"ServiceProxyDestination": "",
"ServiceProxy": {},
"ServiceConnect": {},
"CreateIndex": 88,
"ModifyIndex": 88
}
]
基本的服務發現和註冊我們已經弄清楚了。接下來我來看看Spring Cloud 整合consul的使用。
8. consul服務提供者
8.1建立一個專案:spring-cloud-consul-provider
引入依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lidong</groupId>
<artifactId>spring-cloud-consul-producer</artifactId>
<version>1.0.0</version>
<name>spring-cloud-consul-producer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
對配置檔案做一個簡單的介紹,我們使用的是最新版的springboot2.1.1,springcloud.Greenwich.RC2版本。
其中:
spring-boot-starter-actuator 健康檢查依賴於此包。
spring-cloud-starter-consul-discovery Spring Cloud consul的服務發現支援。
8.2 提供者新增配置(application.yml)
server:
port: 9001 #提供者的埠
spring:
application:
name: spring-cloud-consul-producer
cloud:
consul:
host: localhost
port: 8500
discovery:
tags: dev
serviceName: spring-cloud-consul-producer # 註冊到consul的服務名稱
healthCheckPath: /actuator/health
healthCheckInterval: 15s
healthCheckUrl: http://127.0.0.1:9001/actuator/health
register: true
prefer-ip-address: false
consul的地址和埠號預設是127.0.0.1:8500,如果沒有配置hosts,預設的地址localhost,consul服務會佔用8500埠
server.port :9001 服務的提供者的埠
spring.application.name 是指註冊到 consul的服務名稱,後期客戶端會根據這個名稱來進行服務呼叫。
spring.application.cloud.discovery.discovery.host: localhost
spring.application.cloud.discovery.discovery. port:8500
8.3 修改啟動類
新增 @EnableDiscoveryClient 註解,開啟服務發現支援。
package com.lidong.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* 開啟服務發現
*/
@EnableDiscoveryClient
@SpringBootApplication
public class SpringCloudLidongProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudLidongProviderApplication.class, args);
}
}
8.4新建服務
新建 ConsulProducerController,提供 sayHello 介面, 返回一個hello—>字串。
package com.lidong.provider.service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 建立服務
*/
@RestController
public class ConsulProducerController {
@Value("${server.port}")
private Integer port;
/**
* 服務介面
* @param name
* @return
*/
@RequestMapping("/hello")
public String sayHello(@RequestParam("name")String name) {
return "hello ---> "+name+" port -->"+port;
}
}
啟動專案:
2018-12-26 13:21:42.984 INFO 20248 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9001 (http) with context path ''
2018-12-26 13:21:42.994 INFO 20248 --- [ main] o.s.c.c.s.ConsulServiceRegistry : Registering service with consul: NewService{id='spring-cloud-consul-producer-9001', name='spring-cloud-consul-producer', tags=[dev, secure=false], address='vip-PC', meta=null, port=9001, enableTagOverride=null, check=Check{script='null', interval='15s', ttl='null', http='http://127.0.0.1:9001/actuator/health', method='null', header={}, tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null'}, checks=null}
2018-12-26 13:21:43.008 INFO 20248 --- [ main] l.p.SpringCloudLidongProviderApplication : Started SpringCloudLidongProviderApplication in 4.09 seconds (JVM running for 4.755)
服務提供者釋出成功。
這時候,我們在控制檯會發現服務列表中有一個名字為spring-cloud-consul-producer的服務
點選詳情會發現服務的詳細資訊
9. Consul服務消費者
9.1建立一個專案:spring-cloud-consul-consumer
引入依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lidong</groupId>
<artifactId>spring-cloud-consul-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-consul-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
9.2 消費者新增配置(application.yml)
server:
port: 9002 #服務消費者的埠
spring:
application:
name: spring-cloud-consul-consumer
cloud:
consul:
host: localhost
port: 8500
discovery:
tags: dev
register: false #設定不需要註冊到 consul 中
healthCheckPath: /actuator/health
healthCheckInterval: 15s
healthCheckUrl: http://127.0.0.1:9002/actuator/health
consul的地址和埠號預設是 127.0.0.1:8500,如果沒有配置hosts,預設的地址localhost,consul服務會佔用8500介面
server.port :9006 服務的消費者的埠
spring.application.cloud.consul.discovery.register: false
9.3配置啟動類
package com.lidong.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudConsulConsumerApplication {
@Autowired
private RestTemplateBuilder builder;
@LoadBalanced
@Bean// 新增負載均衡支援,很簡單,只需要在RestTemplate上新增@LoadBalanced註解,那麼RestTemplate即具有負載均衡的功能,如果不加@LoadBalanced註解的話,會報java.net.UnknownHostException:springboot-h2異常,此時無法通過註冊到Eureka Server上的服務名來呼叫服務,因為RestTemplate是無法從服務名對映到ip:port的,對映的功能是由LoadBalancerClient來實現的。
public RestTemplate restTemplate() {
return builder.build();
}
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsulConsumerApplication.class, args);
}
}
9.4建立消費服務
package com.lidong.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 建立服務的消費者
*/
@RestController
public class ConsumerController {
private static final String SERVICE_NAME = "spring-cloud-consul-producer";
@Autowired
private DiscoveryClient discoveryClient;
/**
* 獲取所有服務
*/
@RequestMapping("/services")
public Object services() {
return discoveryClient.getInstances(SERVICE_NAME);
}
/**
* 消費服務
*/
@RequestMapping("/callSayHello")
public String services(@RequestParam("name") String name) {
ServiceInstance serviceInstance = (ServiceInstance) discoveryClient.getInstances(SERVICE_NAME);
String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class);
System.out.println(callServiceResult);
return callServiceResult;
}
}
http://localhost:9002/services
獲取服務列表的結果
[{"instanceId":"spring-cloud-consul-producer-9001","serviceId":"spring-cloud-consul-producer","host":"vip-PC","port":9001,"secure":false,"metadata":{"dev":"dev","secure":"false"},"uri":"http://vip-PC:9001","scheme":null}]
測試請求的url
http://localhost:9002/callSayHello?name=9002
消費的結果
hello ---> 9002 port -->9001
原始碼地址
https://download.csdn.net/download/u010046908/10877868