1.Eureka
源碼:https://github.com/zhongyushi-git/cloud-eureka-demo.git。
說明:本文是創建maven父子模塊,然后把子模塊轉為SpringBoot項目進行開發的,也可以直接單獨創建SpringBoot項目開發,大同小異。
1.1定義
官網:https://github.com/Netflix/eureka/wiki。目前2.0版本已經停止維護,只能使用1.0版本。
它是一個基於REST的服務,用於定位服務,以實現雲端中間層發現和故障轉移。簡單來說就是服務注冊與發現,只要使用服務的標識就可以訪問到服務。
它采用cs架構,Eureka Server作為服務注冊的服務器,是注冊中心;
Eureka Client是客戶端,需要注冊的服務使用客戶端連接到服務器並維持心跳,可以通過服務器來監測各個微服務是否正常運行。
1.2原理圖
服務提供者把服務注冊到Eureka,而服務消費者也把服務注冊到Eureka。服務消費者想要調用服務提供者,就通過服務名去Eureka注冊中心查詢,服務提供者即可提供服務。
1.3基礎環境搭建
1)創建一個maven工程名為cloud-eureka-demo,作為父工程,刪除src目錄
2)在pom中導入依賴,對SpringBoot和SpringCloud版本進行鎖定
<properties> <spring.boot.version>2.2.2.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR1</spring.cloud.version> </properties> <!-- 依賴管理,父工程鎖定版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <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>
1.4搭建Eureka的服務注冊中心
所謂服務中心,也就是Eureka Server。服務中心需要在啟動類上添加注解@EnableEurekaServer表示這是一個Eureka的服務中心
1)創建maven的工程名為eureka-demo-server7001,作為子工程,下同。在pom中導入依賴
<dependencies> <!--eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</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-actuator</artifactId> </dependency> </dependencies>
2)創建包com.zys.cloud,在包下新建啟動類EurekaMain7001
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } }
3)在資源目錄下創建配置文件application.yml
server: port: 7001 eureka: instance: #eureka服務端的實例名稱 hostname: localhost client: #false表示不向注冊中心注冊自己 register-with-eureka: false #false表示自己端就是注冊中心,我的職責就是維護服務實例,並不需要去檢索服務 fetch-registry: false service-url: #設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4)運行測試
啟動主啟動類,在瀏覽器輸入http://127.0.0.1:7001測試server是否搭建成功,看到下圖說明已搭建成功。
1.5創建服務提供者
1)創建maven的工程名為eureka-demo-provider,在pom中導入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
引入的actuator作用是健康檢查,故每個項目都導入了此坐標。
2)新建啟動類ProviderMain8001
package com.zys; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
3)創建TestController類
package com.zys.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服務提供者,端口:" + port; } }
4)在資源目錄下創建配置文件application.yml
server: port: 8001
1.6將服務提供者注冊到Eureka
1)在eureka-demo-provider的pom中添加eureka客戶端的依賴
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)在eureka-demo-provider的yml文件中添加eureka客戶端的配置
spring:
application:
name: cloud-eureka-demo-provider
#把客戶端注冊到服務列表中
eureka:
client:
#表示是否將自己注冊進EurekaServer默認為true
register-with-eureka: true
#是否從EurekaServer抓取已有的注冊信息,默認為true。單節點無所謂,集群必須設置為true才能配合ribbon使用負載均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#設置入駐的服務的名稱,是唯一的,最好和應用名稱一致
instance-id: cloud-eureka-demo-provider
#訪問路徑顯示ip
prefer-ip-address: true
需要注意的是,必須要設置應用名稱,否則在eureka中會顯示UNKNOW。
3)在eureka-demo-provider的啟動類上添加eureka客戶端的注解@EnableEurekaClient
@SpringBootApplication @EnableEurekaClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
4)運行測試
先運行eureka服務,再運行服務提供者,在瀏覽器輸入http://127.0.0.1:7001,看到有一個服務,說明注冊成功。
1.7Eureka自我保護機制
在剛剛啟動的時候,並沒有出現下面紅色的部分,但是過一會再次刷新,就會出現下面的紅色文字。也就是說是eureka的自我保護機制發揮的作用。簡單來說,就是某一時刻,某個服務不使用了,但eureka並不會立即清除掉,而是依舊保持此微服務的信息。當它收到的心跳數重新恢復到閾值以上時該服務節點會自動退出保護模式,是一種應對網絡異常的安全保護措施。
有時候就想某個服務不用了或者死掉了,就直接清理,如何操作呢?也是可以配置的。
在動服務注冊中心7001的yml設置server.enable-self-preservation為false,配置如下
eureka:
#關閉自我保護 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000
在eureka-demo-provider的yml設置連接的時間
eureka: instance: #eureka服務端在接受到最后一次心跳后等待的時間,默認90s,超時剔除服務 lease-expiration-duration-in-seconds: 2 #eureka客戶端向服務端發送心跳的時間,默認30s lease-renewal-interval-in-seconds: 1
然后啟動服務注冊中心7001和服務提供者eureka-demo-provider,刷新eureka頁面,出現下圖說明關閉成功:
悄悄的關閉服務提供者eureka-demo-provider,刷新頁面,發現8001的服務不在了。
1.8Eureka集群搭建
如果eureka服務注冊中心只有一台,當服務器宕機時,就不能正常提供服務了,因此集群也是很重要的。這里就由三個服務器組成一個集群。
1)新建maven工程eureka-demo-server7002和eureka-demo-server7003。后面就簡稱7002和7003
2)分別把eureka-demo-server7001的pom依賴復制到7002和7003中
3)參照7001創建7002和7003的啟動類
4)修改域名映射文件C:\Windows\System32\drivers\etc\hosts, 在最后添加
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.com
5)修改配置文件yml,將eureka單機版服務改為集群服務
7001的yml
server: port: 7001 eureka: #關閉自我保護 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服務端的實例名稱 #單機版 # hostname: localhost #集群 hostname: eureka7001.com client: #false表示不向注冊中心注冊自己 register-with-eureka: false #false表示自己端就是注冊中心,我的職責就是維護服務實例,並不需要去檢索服務 fetch-registry: false service-url: #設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 #單機版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
7002的yml
server: port: 7002 eureka: #關閉自我保護 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服務端的實例名稱 #單機版 # hostname: localhost #集群 hostname: eureka7002.com client: #false表示不向注冊中心注冊自己 register-with-eureka: false #false表示自己端就是注冊中心,我的職責就是維護服務實例,並不需要去檢索服務 fetch-registry: false service-url: #設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 #單機版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7003.com:7003/eureka/
7003的yml
server: port: 7003 eureka: #關閉自我保護 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服務端的實例名稱 #單機版 # hostname: localhost #集群 hostname: eureka7003.com client: #false表示不向注冊中心注冊自己 register-with-eureka: false #false表示自己端就是注冊中心,我的職責就是維護服務實例,並不需要去檢索服務 fetch-registry: false service-url: #設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 #單機版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
6)修改eureka-demo-provider的yml,服務url設置為集群
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
7)啟動測試
依次啟動7001、7002、7003、服務提供者eureka-demo-provider,然后在瀏覽器分別訪問eureka7001.com:7001,eureka7002.com:7002,eureka7003.com:7003。會發現他們都和另外兩個服務器連接着。如訪問7003的:
1.9Eureka服務發現Discovery
它的功能就是獲取注冊進eureka中的微服務的信息。
1)修改eureka-demo-provider模塊的controller,在里面添加獲取服務信息的方法
@Autowired private DiscoveryClient discoveryClient; @GetMapping("/discovery") public Object discovery() { //獲取注冊的服務列表信息 List<String> services = discoveryClient.getServices(); //根據服務名稱獲取實例列表信息 String serviceId = "CLOUD-EUREKA-DEMO-PROVIDER"; List<ServiceInstance> instances = discoveryClient.getInstances(serviceId); Map<String, Object> map = new HashMap<>(); map.put("服務列表", services); map.put("實例列表", instances); return map; }
2)在啟動類上添加注解@EnableDiscoveryClient
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
3)啟動測試
先啟動eureka集群,然后啟動8001,在瀏覽器輸入即可看到服務的相關信息,包括服務列表,實例列表,主機ip等。
2.Zookeeper
zookeeper也可以做注冊中心。這里默認已經在linux上安裝好了Zookeeper服務並允許外部訪問。
源代碼:https://github.com/zhongyushi-git/cloud-zookeeper-demo.git
2.1項目搭建
1)創建一個maven工程名為cloud-zookeeper-demo,作為父工程,刪除src目錄
2)在pom中導入依賴,對SpringBoot和SpringCloud版本進行鎖定
<dependencies> <!--eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</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-actuator</artifactId> </dependency> </dependencies>
2.2服務提供者注冊
1)創建子模塊cloud-zk-provider,導入依賴
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency <!--springboot整合zookeeper客戶端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <!--先排除自帶的zookeeper3.5.3--> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <!--添加zookeeper3.4.14版本--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2)配置application.yml
server: port: 8001 spring: application: name: cloud-provider #配置zookeeper cloud: zookeeper: connect-string: 192.168.0.22:2181
3)創建controller
package com.zys.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服務提供者,端口:" + port; } }
4)創建啟動類並添加注解@EnableDiscoveryClient
package com.zys; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
@EnableDiscoveryClient用於Zookeeper作為注冊中心時注冊服務
5)啟動測試
啟動服務后,在瀏覽器輸入http://127.0.0.1:8001/user/get/1,數據可以正常訪問。打開連接linux的軟件,啟動Zookeeper客戶端。
查看注冊的服務
ls /
查看注冊的具體服務
ls /services ls /services/cloud-provider
獲取服務的具體信息
ls /services/cloud-provider/d619cc0e-d460-454a-8238-5ac87c0dd3f8
需要注意的是cloud-provider是注冊的時候的服務名稱,后面的字符串是生成的服務的id。這個服務節點是臨時節點。至此服務提供者已注冊到Zookeeper中。
3.Consul
源碼:https://github.com/zhongyushi-git/cloud-consul-demo.git
3.1定義
是一套開源的分布式服務發現和配置管理系統,提供了服務治理、配置中心、控制總線等功能。它擁有一個web的可視化界面。
3.2下載與安裝
1)下載網址:https://www.consul.io/downloads.html 下載對應的版本即可
2)解壓,在當前目錄打開cmd,輸入命令來以開發者模式啟動
consul agent -dev
3)在瀏覽器輸入localhost:8500看到consul控制界面,說明安裝成功。
3.3基本環境搭建
1)創建一個maven工程名為cloud-consul-demo,作為父工程,刪除src目錄
2)在pom中導入依賴,對SpringBoot和SpringCloud版本進行鎖定
<properties> <spring.boot.version>2.2.2.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR1</spring.cloud.version> </properties> <!-- 依賴管理,父工程鎖定版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <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>
3.4服務提供者注冊
1)新建maven的子工程cloud-consul-provider8001,導入依賴
<dependencies> <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-actuator</artifactId> </dependency> </dependencies>
2)配置application.yml
server: port: 8001 spring: application: name: cloud-consul-provider cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}
3)創建啟動類並加@EnableDiscoveryClient注解
package com.zxh.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ConsulProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ConsulProviderMain8001.class,args); } }
4)創建controller接口
package com.zxh.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服務提供者,端口:" + port; } }
5)啟動測試
先啟動consul服務,然后啟動8001,在瀏覽器輸入http://localhost:8500/可以看到提供者服務注冊進來了。
3.5CAP定理
在一個分布式系統中,一致性、可用性、分區容錯這三個特性,不可能同時滿足,而是必須有所舍棄,只能同時滿足其中的兩個。表示含義如下:
簡寫 | 全稱 | 說明 |
C | Consistency | 一致性。各節點的數據在同一時刻保持一致 |
A | Availability | 可用性。每次向未崩潰的節點發送請求,總能保證收到響應數據(允許不是最新數據) |
P | Partition tolerance | 分區容錯性。容許節點間傳遞消息出現延遲或丟失,而不影響系統繼續運行 |
3.6Eureka、Zookeeper與Consul的異同
組件名 | 所用語言 | CAP | 對外暴露接口 |
Eureka | java | AP | HTTP |
Zookeeper | java | CP | 客戶端 |
Consul | go | CP | HTTP/DNS |