新聞中心
Spring Cloud簡(jiǎn)介
Spring Cloud是基于Spring Boot的一整套實(shí)現(xiàn)微服務(wù)的框架。他提供了微服務(wù)開發(fā)所需的配置管理、服務(wù)發(fā)現(xiàn)、斷路器、智能路由、微代理、控制總線、全局鎖、決策競(jìng)選、分布式會(huì)話和集群狀態(tài)管理等組件。最重要的是,跟spring boot框架一起使用的話,會(huì)讓你開發(fā)微服務(wù)架構(gòu)的云服務(wù)非常好的方便。

成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供沂南網(wǎng)站建設(shè)、沂南做網(wǎng)站、沂南網(wǎng)站設(shè)計(jì)、沂南網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、沂南企業(yè)網(wǎng)站模板建站服務(wù),十載沂南做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
Spring Cloud包含了非常多的子框架,其中,Spring Cloud Netflix是其中一套框架,由Netflix開發(fā)后來又并入Spring Cloud大家庭,它主要提供的模塊包括:服務(wù)發(fā)現(xiàn)、斷路器和監(jiān)控、智能路由、客戶端負(fù)載均衡等。
Spring Cloud Netflix項(xiàng)目的時(shí)間還不長(zhǎng),并入Spring Cloud大家族還是2年前,所以相關(guān)的使用文檔還比較少,除了官方文檔,國(guó)內(nèi)也有一個(gè)中文社區(qū)。但是,如果是剛開始接觸這個(gè),想使用它搭建一套微服務(wù)的應(yīng)用架構(gòu),總是會(huì)有不知如何下手的感覺。所以,這篇文章就是從整體上來看看這個(gè)框架的各個(gè)組件、用處是什么、如何相互作用。最后再結(jié)合實(shí)際的經(jīng)驗(yàn),介紹一下可能會(huì)出現(xiàn)的問題,以及針對(duì)一些問題,采用什么樣的解決方案。
微服務(wù)架構(gòu)
首先,我們來看看一般的微服務(wù)架構(gòu)需要的功能或使用場(chǎng)景:
- 我們把整個(gè)系統(tǒng)根據(jù)業(yè)務(wù)拆分成幾個(gè)子系統(tǒng)。
- 每個(gè)子系統(tǒng)可以部署多個(gè)應(yīng)用,多個(gè)應(yīng)用之間使用負(fù)載均衡。
- 需要一個(gè)服務(wù)注冊(cè)中心,所有的服務(wù)都在注冊(cè)中心注冊(cè),負(fù)載均衡也是通過在注冊(cè)中心注冊(cè)的服務(wù)來使用一定策略來實(shí)現(xiàn)。
- 所有的客戶端都通過同一個(gè)網(wǎng)關(guān)地址訪問后臺(tái)的服務(wù),通過路由配置,網(wǎng)關(guān)來判斷一個(gè)URL請(qǐng)求由哪個(gè)服務(wù)處理。請(qǐng)求轉(zhuǎn)發(fā)到服務(wù)上的時(shí)候也使用負(fù)載均衡。
- 服務(wù)之間有時(shí)候也需要相互訪問。例如有一個(gè)用戶模塊,其他服務(wù)在處理一些業(yè)務(wù)的時(shí)候,要獲取用戶服務(wù)的用戶數(shù)據(jù)。
- 需要一個(gè)斷路器,及時(shí)處理服務(wù)調(diào)用時(shí)的超時(shí)和錯(cuò)誤,防止由于其中一個(gè)服務(wù)的問題而導(dǎo)致整體系統(tǒng)的癱瘓。
- 還需要一個(gè)監(jiān)控功能,監(jiān)控每個(gè)服務(wù)調(diào)用花費(fèi)的時(shí)間等。
Spring Cloud Netflix組件以及部署
Spring Cloud Netflix框架剛好就滿足了上面所有的需求,而且最重要的是,使用起來非常的簡(jiǎn)單。Spring Cloud Netflix包含的組件及其主要功能大致如下:
- Eureka,服務(wù)注冊(cè)和發(fā)現(xiàn),它提供了一個(gè)服務(wù)注冊(cè)中心、服務(wù)發(fā)現(xiàn)的客戶端,還有一個(gè)方便的查看所有注冊(cè)的服務(wù)的界面。 所有的服務(wù)使用Eureka的服務(wù)發(fā)現(xiàn)客戶端來將自己注冊(cè)到Eureka的服務(wù)器上。
- Zuul,網(wǎng)關(guān),所有的客戶端請(qǐng)求通過這個(gè)網(wǎng)關(guān)訪問后臺(tái)的服務(wù)。他可以使用一定的路由配置來判斷某一個(gè)URL由哪個(gè)服務(wù)來處理。并從Eureka獲取注冊(cè)的服務(wù)來轉(zhuǎn)發(fā)請(qǐng)求。
- Ribbon,即負(fù)載均衡,Zuul網(wǎng)關(guān)將一個(gè)請(qǐng)求發(fā)送給某一個(gè)服務(wù)的應(yīng)用的時(shí)候,如果一個(gè)服務(wù)啟動(dòng)了多個(gè)實(shí)例,就會(huì)通過Ribbon來通過一定的負(fù)載均衡策略來發(fā)送給某一個(gè)服務(wù)實(shí)例。
- Feign,服務(wù)客戶端,服務(wù)之間如果需要相互訪問,可以使用RestTemplate,也可以使用Feign客戶端訪問。它默認(rèn)會(huì)使用Ribbon來實(shí)現(xiàn)負(fù)載均衡。
- Hystrix,監(jiān)控和斷路器。我們只需要在服務(wù)接口上添加Hystrix標(biāo)簽,就可以實(shí)現(xiàn)對(duì)這個(gè)接口的監(jiān)控和斷路器功能。
- Hystrix Dashboard,監(jiān)控面板,他提供了一個(gè)界面,可以監(jiān)控各個(gè)服務(wù)上的服務(wù)調(diào)用所消耗的時(shí)間等。
- Turbine,監(jiān)控聚合,使用Hystrix監(jiān)控,我們需要打開每一個(gè)服務(wù)實(shí)例的監(jiān)控信息來查看。而Turbine可以幫助我們把所有的服務(wù)實(shí)例的監(jiān)控信息聚合到一個(gè)地方統(tǒng)一查看。這樣就不需要挨個(gè)打開一個(gè)個(gè)的頁面一個(gè)個(gè)查看。
下面就是使用上述的子框架實(shí)現(xiàn)的為服務(wù)架構(gòu)的組架構(gòu)圖:
在上圖中,有幾個(gè)需要說明的地方:
- Zuul網(wǎng)關(guān)也在注冊(cè)中心注冊(cè),把它也當(dāng)成一個(gè)服務(wù)來統(tǒng)一查看。 負(fù)載均衡不是一個(gè)獨(dú)立的組件,它運(yùn)行在網(wǎng)關(guān)、服務(wù)調(diào)用等地方,每當(dāng)需要訪問一個(gè)服務(wù)的時(shí)候,就會(huì)通過Ribbon來獲得一個(gè)該服務(wù)的實(shí)例去掉用。Ribbon從Eureka注冊(cè)中心獲得服務(wù)和實(shí)例的列表,而不是發(fā)送每個(gè)請(qǐng)求的時(shí)候從注冊(cè)中心獲得。
- 我們可以使用RestTemplate來進(jìn)行服務(wù)間調(diào)用,也可以配置FeignClient來使用,不管什么方式,只要使用服務(wù)注冊(cè),就會(huì)默認(rèn)使用Ribbon負(fù)載均衡。(RestTemplate需要添加@LoadBalanced)
- 每個(gè)服務(wù)都可以開啟監(jiān)控功能,開啟監(jiān)控的服務(wù)會(huì)提供一個(gè)servlet接口/hystrix.stream,如果你需要監(jiān)控這個(gè)服務(wù)的某一個(gè)方法的運(yùn)行統(tǒng)計(jì),就在這個(gè)方法上加一個(gè)@HystrixCommand的標(biāo)簽。
- 查看監(jiān)控信息,就是在Hystrix Dashboard上輸入這個(gè)服務(wù)的監(jiān)控url: http://serviceIp:port/hystrix.stream,就可以用圖表的方式查看運(yùn)行監(jiān)控信息。
- 如果要把所有的服務(wù)的監(jiān)控信息聚合在一起統(tǒng)一查看,就需要使用Turbine來聚合所需要的服務(wù)的監(jiān)控信息。
我們也可以從上圖中看出該架構(gòu)的部署方式:
- 獨(dú)立部署一個(gè)網(wǎng)關(guān)應(yīng)用
- 服務(wù)注冊(cè)中心和監(jiān)控可以配置在一個(gè)應(yīng)用里,也可以是2個(gè)應(yīng)用。
- 服務(wù)注冊(cè)中心也可以部署多個(gè),通過區(qū)域zone來區(qū)分,來實(shí)現(xiàn)高可用。
- 每個(gè)服務(wù),根據(jù)負(fù)載和高可用的需要,部署一個(gè)或多個(gè)實(shí)例。
Spring Cloud Netflix組件開發(fā)
上面說到,開發(fā)基于Spring Cloud Netflix的微服務(wù)非常簡(jiǎn)單,一般我們是和Spring Boot一起使用,如果你想在自己原先的Java Web應(yīng)用中使用也可以通過添加相關(guān)配置來實(shí)踐。
有關(guān)開發(fā)的詳細(xì)內(nèi)容,可以參考Spring Cloud中文社區(qū)的這個(gè)系列文章,里面詳細(xì)介紹了每一種組件的開發(fā)。這里,就只是來看一下服務(wù)注冊(cè)中和監(jiān)控模塊的開發(fā),還有服務(wù)調(diào)用的開發(fā),其他的可以直接參考上面的系列文章。
注冊(cè)和監(jiān)控中心的開發(fā)
這個(gè)非常簡(jiǎn)單,就下面一個(gè)類:
// 省略import
@SpringBootApplication
@EnableEurekaServer
@EnableHystrixDashboard
public class ApplicationRegistry {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}這里使用Spring Boot標(biāo)簽的@SpringBootApplication說明當(dāng)前的應(yīng)用是一個(gè)Spring Boot應(yīng)用。這樣我就可以直接用main函數(shù)在IDE里面啟動(dòng)這個(gè)應(yīng)用,也可以打包后用命令行啟動(dòng)。當(dāng)然也可以把打包的war包用Tomcat之類的服務(wù)器啟動(dòng)。
使用標(biāo)簽@EnableEurekaServer,就能在啟動(dòng)過程中啟動(dòng)Eureka服務(wù)注冊(cè)中心的組件。它會(huì)監(jiān)聽一個(gè)端口,默認(rèn)是8761,來接收服務(wù)注冊(cè)。并提供一個(gè)Web頁面,打開以后,可以看到注冊(cè)的服務(wù)。
添加@EnableHystrixDashboard就會(huì)提供一個(gè)監(jiān)控的頁面,我們可以在上面輸入要監(jiān)控的服務(wù)的地址,就可以查看啟用了Hystrix監(jiān)控的接口的調(diào)用情況。
當(dāng)然,為了使用上面的組件,我們需要在Maven的POM文件里添加相應(yīng)的依賴,比如使用spring-boot-starter-parent,依賴spring-cloud-starter-eureka-server和spring-cloud-starter-hystrix-dashboard等。
服務(wù)間調(diào)用
在網(wǎng)上的各種文檔中,對(duì)服務(wù)間調(diào)用,都沒有說明的很清楚,所以這里特別說明一下這個(gè)如何開發(fā)。
有兩種方式可以進(jìn)行服務(wù)調(diào)用,RestTemplate和FeignClient。不管是什么方式,他都是通過REST接口調(diào)用服務(wù)的http接口,參數(shù)和結(jié)果默認(rèn)都是通過Jackson序列化和反序列化。因?yàn)镾pring MVC的RestController定義的接口,返回的數(shù)據(jù)都是通過Jackson序列化成JSON數(shù)據(jù)。
RestTemplate
使用這種方式,只需要定義一個(gè)RestTemplate的Bean,設(shè)置成LoadBalanced即可:
@Configuration
public class SomeCloudConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}這樣我們就可以在需要用的地方注入這個(gè)bean使用:
public class SomeServiceClass {
@Autowired
private RestTemplate restTemplate;
public String getUserById(Long userId) {
UserDTO results = restTemplate.getForObject("http://users/getUserDetail/" + userId, UserDTO.class);
return results;
}
}其中,users是服務(wù)ID,Ribbon會(huì)從服務(wù)實(shí)例列表獲得這個(gè)服務(wù)的一個(gè)實(shí)例,發(fā)送請(qǐng)求,并獲得結(jié)果。對(duì)象UserDTO需要序列號(hào),它的反序列號(hào)會(huì)自動(dòng)完成。
FeignClient
除了上面的方式,我們還可以用FeignClient。還是直接看代碼:
@FeignClient(value = "users", path = "/users")
public interface UserCompositeService {
@RequestMapping(value = "/getUserDetail/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
UserDTO getUserById(@PathVariable Long id);
}我們只需要使用@FeignClient定義一個(gè)接口,Spring Cloud Feign會(huì)幫我們生成一個(gè)它的實(shí)現(xiàn),從相應(yīng)的users服務(wù)獲取數(shù)據(jù)。
其中,@FeignClient(value = "users", path = "/users/getUserDetail")里面的value是服務(wù)ID,path是這一組接口的path前綴。
在下面的方法定義里,就好像設(shè)置Spring MVC的接口一樣,對(duì)于這個(gè)方法,它對(duì)應(yīng)的URL是/users/getUserDetail/{id}。
然后,在使用它的時(shí)候,就像注入一個(gè)一般的服務(wù)一樣注入后使用即可:
public class SomeOtherServiceClass {
@Autowired
private UserCompositeService userService;
public void doSomething() {
// .....
UserDTO results = userService.getUserById(userId);
// other operation...
}
}
遇到的問題
由于Spring Cloud說明文檔較少,微服務(wù)的架構(gòu)相對(duì)來說也比較復(fù)雜,在開發(fā)的時(shí)候,難免會(huì)遇到很多問題,有一些是如何更好地使用這套框架去搭建架構(gòu),也有一些問題是如何配置。這里就一些我在搭建微服務(wù)架構(gòu)的時(shí)候遇到的問題提供一些方法。
請(qǐng)求超時(shí)問題
Zuul網(wǎng)關(guān)默認(rèn)的超時(shí)時(shí)間非常短,這是為了保證調(diào)用服務(wù)的時(shí)候能夠很快的響應(yīng)。但是,我們會(huì)有一些業(yè)務(wù)方法運(yùn)行的時(shí)間比較長(zhǎng),特別是在測(cè)試服務(wù)器。這時(shí)候,就需要調(diào)整超時(shí)時(shí)間。這個(gè)超時(shí)有幾個(gè)地方:
- 負(fù)載均衡Ribbon,負(fù)載均衡有一個(gè)超時(shí)的設(shè)置,包括鏈接時(shí)間和讀取時(shí)間
- Hystrix斷路器也有一個(gè)超時(shí)設(shè)置,它需要在適當(dāng)?shù)臅r(shí)候返回,而不是一直等在一個(gè)請(qǐng)求上。
對(duì)應(yīng)的配置如下:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 30000 ribbon: ReadTimeout: 30000 ConnectTimeout: 15000
服務(wù)ID的問題
服務(wù)的ID,也就是服務(wù)名,可以通過在application.yml或者Bootstrap.yml里面設(shè)置:
spring:
application:
name: users
管理路徑的問題
Spring Boot的應(yīng)用默認(rèn)都是開放一些管理的接口,如/info、/health和metrics監(jiān)控的接口/metrics等。如果你使用默認(rèn)的路徑,使用Hystrix監(jiān)控、服務(wù)注冊(cè)中心的監(jiān)聽服務(wù)狀態(tài)都不會(huì)有問題,但是,如果你想使用別的路徑,例如/management/info、/management/health,那就牽扯到很多地方,而且,每個(gè)版本可能會(huì)或多或少的有一些問題,導(dǎo)致你遇到的問題還會(huì)不一樣。我遇到過的問題有:
注冊(cè)成功卻找不到服務(wù)
首先,注冊(cè)可以成功,在Eureka服務(wù)器頁面上也可以看到各個(gè)服務(wù)。但是,當(dāng)你通過網(wǎng)關(guān)調(diào)用的時(shí)候,卻總是提示服務(wù)找不到。這時(shí)候可能就需要在每個(gè)服務(wù)的application.yml里面進(jìn)行如下配置:
eureka:
instance:
nonSecurePort: ${server.port}
appname: ${spring.application.name}
statusPageUrlPath: ${management.context-path}/info
healthCheckUrlPath: ${management.context-path}/health簡(jiǎn)單來說,這就是告訴在注冊(cè)的時(shí)候,同時(shí)告訴Eureka服務(wù)器,服務(wù)的端口是什么,用來監(jiān)聽狀態(tài)的路徑是什么。這是因?yàn)槲覀兪褂昧瞬煌墓芾斫涌诼窂?,而Eureka服務(wù)器沒有使用相應(yīng)的路徑。
如果一切正常,你在Eureka服務(wù)器上點(diǎn)擊一個(gè)注冊(cè)的服務(wù),應(yīng)該能打開一個(gè)info頁面。他可能是空白的,但是,至少Eureka服務(wù)器能通過這個(gè)知道服務(wù)的運(yùn)行正常。
這個(gè)問題也不是在所有的版本都存在,只是在某一些Spring Cloud的版本存在。
設(shè)置了管理路徑的Hystrix監(jiān)控
剛才說了Hystrix監(jiān)控的路徑是http://serviceIp:port/hystrix.stream,如果你設(shè)置了管理接口的路徑,那么這個(gè)監(jiān)控路徑也會(huì)變成:
http://serviceIp:port/${management.context-path}/hystrix.stream如果這時(shí)候,你再想使用Turbine聚合,Turbine就會(huì)找不到了,因?yàn)樗J(rèn)使用Eureka服務(wù)器上的服務(wù)器地址和端口,在后面添加/hystrix.stream。這時(shí)候,你就需要設(shè)置Turbine:
turbine:
aggregator:
clusterConfig: USER
appConfig: USER
instanceUrlSuffix:
USER: /user/hystrix.stream管理路徑的安全性
對(duì)于微服務(wù)部署的幾臺(tái)機(jī)器,可以通過開通防火墻來控制誰可以訪問管理接口,但是,即使是這樣,為了安全性等,我一般還是會(huì)把管理端接口也用Spring Security來保護(hù)。這樣一來,監(jiān)控接口就沒法直接訪問了。
服務(wù)間調(diào)用的權(quán)限驗(yàn)證
一般我們的API接口都需要某種授權(quán)才能訪問,登陸成功以后,然后通過token或者cookie等方式才能調(diào)用接口。
使用Spring Cloud Netfix框架的話,登錄的時(shí)候,把登錄請(qǐng)求轉(zhuǎn)發(fā)到相應(yīng)的用戶服務(wù)上,登陸成功后,會(huì)設(shè)置cookie或header token等。然后客戶端接下來的請(qǐng)求就會(huì)帶著這些驗(yàn)證信息,從Zuul網(wǎng)關(guān)傳到相應(yīng)的服務(wù)上進(jìn)行驗(yàn)證。
Zuul網(wǎng)關(guān)在把請(qǐng)求轉(zhuǎn)發(fā)到后臺(tái)的服務(wù)的時(shí)候,會(huì)默認(rèn)把一些header傳到服務(wù)端,如:Cookie、Set-Cookie、Authorization。這樣,客戶端請(qǐng)求的相關(guān)headers就可以傳遞到服務(wù)端,服務(wù)端設(shè)置的cookie也可以傳到客戶端。
但是,如果你想禁止某些header透?jìng)鞯椒?wù)端,可以在Zuul網(wǎng)關(guān)的application.yml配置里通過下面的方式禁用:
zuul: routes: users: path: /users/** sensitiveHeaders: Cookie,Set-Cookie,Authorization serviceId: user
剛才說了我們的某個(gè)服務(wù)有時(shí)候需要調(diào)用另一個(gè)服務(wù),這時(shí)候,這個(gè)請(qǐng)求不是客戶端發(fā)起,他的請(qǐng)求的header里面也不會(huì)有任何驗(yàn)證信息。這時(shí)候,要么,通過防火墻等設(shè)置,保證服務(wù)間調(diào)用的接口,只能某幾個(gè)地址訪問;要么,就通過某種方式設(shè)置header。
同時(shí),如果你想在某個(gè)服務(wù)里面獲得這個(gè)請(qǐng)求的真是IP,(因?yàn)檎?qǐng)求的通過網(wǎng)關(guān)轉(zhuǎn)發(fā)而來,你直接通過request獲得ip得到的是網(wǎng)關(guān)的IP),就可以從headerX-Forwarded-Host獲得。如果想禁用這個(gè)header,也可以:
zuul.addProxyHeaders = false
如果你使用RestTemplate的方式調(diào)用,可以在請(qǐng)求里面添加一個(gè)有header的Options。
也可以通過如下的攔截器的方式設(shè)置,它對(duì)RestTemplate方式和FeignClient的方式都可以起作用:
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
String authToken = getToken();
template.header(AUTH_TOKEN_HEADER, authToken);
}
};
} 網(wǎng)頁名稱:SpringCloudNetflix概覽和架構(gòu)設(shè)計(jì)
鏈接分享:http://m.fisionsoft.com.cn/article/ccsisso.html


咨詢
建站咨詢
