談到SpringCloud最新接觸到的可能就是那五大"神獸",之前最先接觸分布式開發是通過dubbo的RPC遠程過程調用,而dubbo給我得感覺就是:雖然所有的主機物理上分布了,但是對於用戶而言就仿佛是一個整體。而對我們的java開發人員而言,分布式開發的意義又是什么呢?也就是說哪里需要去使用分布式開發呢,其實在任何一個項目里面(MVC設計模式),業務操作是最為核心的部分,而所有項目之中你的業務操作是否完成直接決定了你的項目本身是否健壯。之前太年輕...一直感覺業務對一個追求技術培養得學者來說意義不大,大不了是一套CRUD,后來才發現這種想法就像是一頭還不知道自己獵物在哪里的獅子一樣,還不清楚自己獵物得特性,就急着想去吃它身上的肉,但是什么事都沒有絕對,如果真的是業務堆積,一堆技術含量很低的業務代碼CRUD的堆積就另當別論了...
回到"五大神獸":
- 服務發現——Netflix Eureka
- 客服端負載均衡——Netflix Ribbon(Feign)
- 斷路器——Netflix Hystrix
- 服務網關——Netflix Zuul
- 分布式配置——Spring Cloud Config
下面我們逐個研究一下SpingCloud分布式這五個重點:
Eureka:
一個RESTful風格的服務,用來定位運行在業務流程管理開發平台(AWS Enterprise BPM Platform)層的中間層服務。
1.Eureka服務器用作服務的注冊中心。(對比dubbo的注冊中心:zk redis等);
2.Eureka客戶端其實就是一個java客戶端,負責與服務器的交互,用作輪詢負責均衡,故障切換支持等。
Netflix在其生產環境中使用的是另外的客戶端,它提供基於流量、資源利用率以及出錯狀態的加權負載均衡。
依賴:
<!--eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
注解:
- @EnableEurekaServer:這個注解需要在springboot工程的啟動application類上加,表示啟動一個服務注冊中心;
- @EnableEurekaClient:表明自己是一個eurekaclient;
配置:
- 注冊中心服務器:
server:
port: 8761
# 默認情況下erureka server也是一個eureka client ,必須要指定一個 server。eureka server的配置文件appication.yml 通過eureka.client.registerWithEureka:false和fetchRegistry:false來表明自己是一個eureka server.
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 客戶端服務器:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8762
spring:
application:
name: service-hi
Ribbon:
主要提供客戶側的軟件負載均衡算法。
Ribbon客戶端組件提供一系列完善的配置選項,比如連接超時、重試、重試算法等。 Ribbon是一個負載均衡客戶端,可以很好的控制http和tcp的一些行為。Feign默認集成了Ribbon。
Ribbon內置可插拔、可定制的負載均衡組件。
一些常用的負載均衡策略:
1. 簡單輪詢負載均衡
2. 加權響應時間負載均衡
3. 區域感知輪詢負載均衡
4. 隨機負載均衡
Ribbon中還包括一下功能:
1. 易於與服務發現組件(比如Netflix的Eureka)集成
2. 使用Archaius完成運行時配置
3. 使用JMX暴露運維指標,使用Servo發布
4. 多種可插拔的序列化選擇
5. 異步和批處理操作(即將推出)
6. 自動SLA框架(即將推出)
7. 系統管理/指標控制台(即將推出)
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
注解:
- @EnableDiscoveryClient:向服務中心注冊;
- @LoadBalanced:結合入職restRemplate的@Bean一起使用,開始負載均衡功能;
配置:
application.yml:
#指定服務的注冊中心地址為http://localhost:8761/eureka/
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#程序端口為8764
server:
port: 8764
#程序名稱為 service-ribbon
spring:
application:
name: service-ribbon
Feign:
Feign是一個聲明式的偽Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只需要創建一個接口並注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的編碼器和解碼器。Feign默認集成了Ribbon,並和Eureka結合,默認實現了負載均衡的效果。
簡而言之:
Feign 采用的是基於接口的注解
Feign 整合了ribbon
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
注解:
- @EnableFeignClients:開啟Feign功能;
- @FeignClient:在feign接口上加入此注解,通過@FeignClient("服務名"),來指定調用哪個服務。(類似controller的@RequestMapping(value = "訪問路徑"))
配置:
application.yml
#服務注冊地址為http://localhost:8761/eureka/
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#端口號為8765
server:
port: 8765
#指定程序名為service-feign
spring:
application:
name: service-feign
Hystrix:
Netflix開源了Hystrix組件,實現了斷路器模式,SpringCloud對這一組件進行了整合。較底層的服務如果出現故障,會導致連鎖故障。當對特定的服務的調用的不可用達到一個閥值(Hystric 是5秒20次)斷路器將會被打開。斷路打開后,可用避免連鎖故障,fallback方法可以直接返回一個固定值。
斷路器的特點:
1.斷路器可以防止一個應用程序多次試圖執行一個操作,即很可能失敗,允許它繼續而不等待故障恢復或者浪費 CPU 周期,而它確定該故障是持久的.
2.斷路器模式也使應用程序能夠檢測故障是否已經解決。如果問題似乎已經得到糾正,應用程序可以嘗試調用操作。
3.斷路器增加了穩定性和靈活性,以一個系統,提供穩定性,而系統從故障中恢復,並盡量減少此故障的對性能的影響。它可以幫助快速地拒絕對一個操作,即很可能失敗,而不是等待操作超時(或者不返回)的請求,以保持系統的響應時間。如果斷路器提高每次改變狀態的時間的事件,該信息可以被用來監測由斷路器保護系統的部件的健康狀況,或以提醒管理員當斷路器跳閘,以在打開狀態。
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
注解:
- @EnableHystrix:開啟Hystrix;
- @HystrixCommand:在Service層的方法上加入,對方法創建熔斷器的功能,並指定了fallbackMethod熔斷方法,書寫對應名稱的方法;
PS:Feign中的斷路器:
Feign是自帶斷路器的,在D版本的SpringCloud中,它沒有默認打開。需要在配置文件中配置打開它,在配置文件加入配置:feign.hystrix.enabled=true
注解:
- @FeignClient:在FeignClient的接口的注解中加上fallback屬性指定類,此類實現FeignClient的接口,並注入到IOC容器中(@Component),實現熔斷方法即可。
Hystrix Dashboard (斷路器:Hystrix 儀表盤):
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
注解:
- @EnableHystrixDashboard:配置到主程序啟動類中,開啟hystrixDashboard;
Zuul:
在微服務架構中,需要幾個基礎的服務治理組件,包括服務注冊與發現、服務消費、負載均衡、斷路器、智能路由、配置管理等,由這幾個基礎組件相互協作,共同組建了一個簡單的微服務系統。在SpringCloud微服務系統中,一種常見的負載均衡方式是:客戶端的請求首先經過負載均衡(zuul、Ngnix),再到達服務網關(zuul集群),然后再到具體的服。,服務統一注冊到高可用的服務注冊中心集群,服務的所有的配置文件由配置服務管理,配置服務的配置文件放在git倉庫,方便開發人員隨時改配置。類似nginx,反向代理的功能,不過netflix自己增加了一些配合其他組件的特性。Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,比如/api/user轉發到到user服務,/api/shop轉發到到shop服務。zuul默認和Ribbon結合實現了負載均衡的功能。
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
注解:
- @EnableZuulProxy:一般應用在入口applicaton類加上注解@EnableZuulProxy,開啟zuul的功能;
配置:
#指定服務注冊中心的地址為http://localhost:8761/eureka/
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#服務的端口為8769
server:
port: 8769
#服務名為service-zuul
spring:
application:
name: service-zuul
#以/api-a/ 開頭的請求都轉發給service-ribbon服務
#以/api-b/ 開頭的請求都轉發給service-feign服務
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-ribbon
api-b:
path: /api-b/**
serviceId: service-feign
zuul的服務過濾:zuul不僅只是路由,並且還能過濾,做一些安全驗證。(實現:繼承ZuulFilter)
filterType:返回一個字符串代表過濾器的類型,
在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
pre:路由之前
routing:路由之時
post: 路由之后
error:發送錯誤調用
filterOrder:過濾的順序
shouldFilter:這里可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
run:過濾器的具體邏輯。可用很復雜,包括查sql,nosql去判斷該請求到底有沒有權限訪問。
SpringCloudConfig:
1.SpringCloudConfig就是我們通常意義上說的分布式配置中心,將應用原本放在本地文件的配置抽取出來放在中心服務器上,從而能夠提供更好的管理,發布能力。
2.SpringCloudConfig分為服務端和客戶端,服務端負責將git(或者svn)上存儲的配置文件發布成REST接口,客戶端可以從服務端RESTjie接口獲取配置。但客戶端並不能主動感知配置文件的變化,從而主動去獲取新的配置,它需要每個客戶端通過POST方法觸發各自的/refresh請求,SpringCloudBus就通過一個輕量級消息代理連接分布式系統節點。
3.可以用於廣播狀態更改,(如配置更改)或者管理指令。
4.SpringCloudBus提供了通過POST方法訪問的endpoint/bus/refresh,這個接口通常由git的鈎子功能調用,用以通知各個SpringCloudConfig的客戶端去服務端更新配置。
依賴:
<!-- 服務端開始 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 服務端結束 -->
<!-- 客戶端開始 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 客戶端結束 -->
注解:
- @EnableConfigServer:應用在程序的入口Application類上,表示開啟配置服務器的功能;
配置:
服務端:application.properties
spring.application.name=config-server
server.port=8888
#配置git倉庫地址
spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/
#配置倉庫路徑
spring.cloud.config.server.git.searchPaths=respo
#配置倉庫的分支
spring.cloud.config.label=master
#訪問git倉庫的用戶名(如果Git倉庫為公開倉庫,可以不填寫用戶名和密碼)
spring.cloud.config.server.git.username=your username
#訪問git倉庫的用戶密碼
spring.cloud.config.server.git.password=your password
客戶端:bootstrap.properties
spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:8888/
server.port=8881
-
spring.cloud.config.label 指明遠程倉庫的分支
-
spring.cloud.config.profile
- dev開發環境配置文件
- test測試環境
- pro正式環境
-
spring.cloud.config.uri= http://localhost:8888/指明配置服務中心的網址。
http請求地址和資源文件映射如下: · /{application}/{profile}[/{label}] · /{application}-{profile}.yml · /{label}/{application}-{profile}.yml · /{application}-{profile}.properties · /{label}/{application}-{profile}.properties
PS:高可用配置中心:當服務實例很多時,都從配置中心讀取文件,這時可以考慮將配置中心做成一個微服務,將其集群化,從而達到高可用;
依賴:
<!-- 服務注冊中心依賴開始 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 服務注冊中心依賴結束 -->
<!-- 配置服務端依賴開始 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 配置服務端依賴結束 -->
配置:
注冊中心:application.yml
#服務端口為8889
server:
port: 8889
# 作為服務注冊中心的基本配置
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
服務端:bootstrap.properties
spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
#spring.cloud.config.uri= http://localhost:8888/
#加上服務注冊地址為http://localhost:8889/eureka/
eureka.client.serviceUrl.defaultZone=http://localhost:8889/eureka/
#是從配置中心讀取文件
spring.cloud.config.discovery.enabled=true
#配置中心的servieId,即服務名
spring.cloud.config.discovery.serviceId=config-server
server.port=8881
暫時先記錄這些;感謝網絡上大神方志鵬的帖子:
https://gitee.com/liudongyang/SpringCloudLearning