偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

基于Spring Cloud的微服務(wù)落地

開發(fā) 開發(fā)工具 前端
微服務(wù)架構(gòu)模式的核心在于如何識(shí)別服務(wù)的邊界,設(shè)計(jì)出合理的微服務(wù)。但如果要將微服務(wù)架構(gòu)運(yùn)用到生產(chǎn)項(xiàng)目上,并且能夠發(fā)揮該架構(gòu)模式的重要作用,則需要微服務(wù)框架的支持。

微服務(wù)架構(gòu)模式的核心在于如何識(shí)別服務(wù)的邊界,設(shè)計(jì)出合理的微服務(wù)。但如果要將微服務(wù)架構(gòu)運(yùn)用到生產(chǎn)項(xiàng)目上,并且能夠發(fā)揮該架構(gòu)模式的重要作用,則需要微服務(wù)框架的支持。

[[231374]]

在Java生態(tài)圈,目前使用較多的微服務(wù)框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud。它包括:

  • Spring Cloud Config:配置管理工具,支持使用Git存儲(chǔ)配置內(nèi)容,可以實(shí)現(xiàn)應(yīng)用配置的外部化存儲(chǔ),支持客戶端配置信息刷新、加密/解密配置內(nèi)容等。
  • Spring Cloud Netflix:對(duì)Netflix OSS進(jìn)行了整合。其中又包括:
  • Eureka:服務(wù)治理組件,包含服務(wù)注冊(cè)中心、服務(wù)注冊(cè)與發(fā)現(xiàn)。
  • Hystrix:容器管理組件,實(shí)現(xiàn)斷路器模式,倘若依賴的服務(wù)出現(xiàn)延遲或故障,則提供強(qiáng)大的容錯(cuò)功能。
  • Ribbon:客戶端負(fù)載均衡的服務(wù)調(diào)用組件。
  • Feign:基于Ribbon和Hystrix的聲明式服務(wù)調(diào)用組件。
  • Zuul:網(wǎng)關(guān)組件,提供智能路由、訪問(wèn)過(guò)濾等功能。
  • Archaius:外部化配置組件。
  • Spring Cloud Bus:事件、消息總線。
  • Spring Cloud Cluster:針對(duì)ZooKeeper、Redis、Hazelcast、Consul的選舉算法和通用狀態(tài)模式的實(shí)現(xiàn)。
  • Spring Cloud Cloudfoundry:與Pivotal Cloudfoundry的整合支持。
  • Spring Cloud Consul:服務(wù)發(fā)現(xiàn)與配置管理工具。
  • Spring Cloud Stream:通過(guò)Redis、Rabbit或者Kafka實(shí)現(xiàn)的消息驅(qū)動(dòng)的微服務(wù)。
  • Spirng Cloud AWS:簡(jiǎn)化和整合Amazon Web Service。
  • Spring Cloud Security:安全工具包,提供Zuul代理中對(duì)OAuth2客戶端請(qǐng)求的中繼器。
  • Spring Cloud Sleuth:Spring Cloud應(yīng)用的分布式跟蹤實(shí)現(xiàn),可以整合Zipkin。
  • Spring Cloud ZooKeeper:基于ZooKeeper的服務(wù)發(fā)現(xiàn)與配置管理組件。
  • Spring Cloud Starters:Spring Cloud的基礎(chǔ)組件,是基于Spring Boot風(fēng)格項(xiàng)目的基礎(chǔ)依賴模塊。
  • Spring Cloud CLI:用于在Groovy中快速創(chuàng)建Spring Cloud應(yīng)用的Spring Boot CLI插件。

服務(wù)治理

當(dāng)一個(gè)系統(tǒng)的微服務(wù)數(shù)量越來(lái)越多的時(shí)候,我們就需要對(duì)服務(wù)進(jìn)行治理,提供統(tǒng)一的服務(wù)注冊(cè)中心,然后在其框架下提供發(fā)現(xiàn)服務(wù)的功能。這樣就避免了對(duì)多個(gè)微服務(wù)的配置,以及微服務(wù)之間以及與客戶端之間的耦合。

Spring Cloud Eureka是對(duì)Netflix Eureka的包裝,用以實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn)。Eureka服務(wù)端即服務(wù)注冊(cè)中心,支持高可用配置。它依托于強(qiáng)一致性提供良好的服務(wù)實(shí)例可用性,并支持集群模式部署。Eureka客戶端則負(fù)責(zé)處理服務(wù)的注冊(cè)與發(fā)現(xiàn)??蛻舳朔?wù)通過(guò)annotation與參數(shù)配置的方式,嵌入在客戶端應(yīng)用程序代碼中。在運(yùn)行應(yīng)用程序時(shí),Eureka客戶端向注冊(cè)中心注冊(cè)自身提供的服務(wù),并周期性地發(fā)送心跳更新它的服務(wù)租約。

搭建服務(wù)注冊(cè)中心

服務(wù)注冊(cè)中心是一個(gè)獨(dú)立部署的服務(wù)(你可以認(rèn)為它也是一個(gè)微服務(wù)),所以需要單獨(dú)為它創(chuàng)建一個(gè)項(xiàng)目,并在pom.xml中添加Eureka的依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-eureka-server</artifactId> 
  4. </dependency> 

創(chuàng)建Spring Boot Application:

  1. @EnableEurekaServer 
  2. @SpringBootApplication 
  3. public class Application { 
  4.     public static void main(String[] args) { 
  5.         new SpringApplicationBuilder(Application.class).web(true).run(args); 
  6.     } 

注冊(cè)服務(wù)提供者

要讓自己編寫的微服務(wù)能夠注冊(cè)到Eureka服務(wù)器中,需要在服務(wù)的Spring Boot Application中添加@EnableDiscoveryClient注解,如此才能讓Eureka服務(wù)器發(fā)現(xiàn)該服務(wù)。當(dāng)然,pom.xml文件中也需要添加相關(guān)依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-eureka</artifactId> 
  4. </dependency> 

同時(shí),我們還需要為服務(wù)命名,并指定地址。這些信息都可以在application.properties配置文件中配置:

  1. spring.application.name=demo-service 
  2. eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ 

說(shuō)明:Spring更推薦使用yml文件來(lái)維護(hù)系統(tǒng)的配置,yml文件可以體現(xiàn)出配置節(jié)的層次關(guān)系,表現(xiàn)力比單純的key-value形式更好。如果結(jié)合使用后面講到的Spring Cloud Config,則客戶端的配置文件必須命名為bootstrap.properties或者bootstrap.yml。與上述配置相同的yml文件配置為:

  1. spring: 
  2.   application: 
  3.     name: demo-service 
  4.  
  5. eureka: 
  6.   client: 
  7.     serviceUrl:  
  8.       defaultZone: http://localhost:1111/eureka/ 

服務(wù)發(fā)現(xiàn)與消費(fèi)

在微服務(wù)架構(gòu)下,許多微服務(wù)可能會(huì)扮演雙重身份。一方面它是服務(wù)的提供者,另一方面它又可能是服務(wù)的消費(fèi)者。注冊(cè)在Eureka Server中的微服務(wù)可能會(huì)被別的服務(wù)消費(fèi)。此時(shí),就相當(dāng)于在服務(wù)中創(chuàng)建另一個(gè)服務(wù)的客戶端,并通過(guò)RestTemplate發(fā)起對(duì)服務(wù)的調(diào)用。為了更好地提高性能,可以在服務(wù)的客戶端引入Ribbon,作為客戶端負(fù)載均衡。

現(xiàn)在假定我們要為demo-service創(chuàng)建一個(gè)服務(wù)消費(fèi)者demo-consumer。該消費(fèi)者自身也是一個(gè)Spring Boot微服務(wù),同時(shí)也能夠被Eureka服務(wù)器注冊(cè)。這時(shí),就需要在該服務(wù)的pom.xml中添加eureka與ribbon的依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-eureka</artifactId> 
  4. </dependency> 
  5. <dependency> 
  6.     <groupId>org.springframework.cloud</groupId> 
  7.     <artifactId>spring-cloud-starter-ribbon</artifactId> 
  8. </dependency> 

然后在主應(yīng)用類ConosumerApplication中注入RestTemplate,并引入@LoadBalanced注解開啟客戶端負(fù)載均衡:

  1. @EnableDiscoveryClient 
  2. @SpringBootApplication 
  3. public class ConsumerApplication { 
  4.     @Bean 
  5.     @LoadBalanced 
  6.     RestTemplate restTemplate() { 
  7.         return new RestTemplate(); 
  8.     } 
  9.     public static void main(String[] args) { 
  10.         SpringApplication.run(ConsumerApplication.class, args) 
  11.     } 

假設(shè)消費(fèi)demo-service的客戶端代碼寫在demo-consumer服務(wù)的其中一個(gè)Controller中:

  1. @RestController 
  2. public class ConsumerController { 
  3.     @Autowired 
  4.     RestTemplate restTemplate; 
  5.  
  6.     @RequestMapping(value = "/demo-consumer"method = RequestMethod.Get) 
  7.     public String helloConsumer() { 
  8.         return restTemplate.getForEntity("http://demo-service/demo", String.class).getBody();  
  9.     } 

通過(guò)RestTemplate就可以發(fā)起對(duì)demo-service的消費(fèi)調(diào)用。

聲明式服務(wù)調(diào)用

通過(guò)Ribbon和Hystrix可以實(shí)現(xiàn)對(duì)微服務(wù)的調(diào)用以及容錯(cuò)保護(hù),但Spring Cloud還提供了另一種更簡(jiǎn)單的聲明式服務(wù)調(diào)用方式,即Spring Cloud Feign。Feign實(shí)際上就是對(duì)Ribbon與Hystrix的進(jìn)一步封裝。通過(guò)Feign,我們只需創(chuàng)建一個(gè)接口并用annotation的方式配置,就可以完成對(duì)服務(wù)供應(yīng)方的接口(REST API)綁定。

假設(shè)我們有三個(gè)服務(wù):

  • Notification Service
  • Account Service
  • Statistics Service

服務(wù)之間的依賴關(guān)系如下圖所示:

要使用Feign來(lái)完成聲明式的服務(wù)調(diào)用,需要在作為調(diào)用者的服務(wù)中創(chuàng)建Client。Client通過(guò)Eureka Server調(diào)用注冊(cè)的對(duì)應(yīng)服務(wù),這樣可以解除服務(wù)之間的耦合。結(jié)構(gòu)如下圖所示:

為了使用Feign,需要對(duì)應(yīng)微服務(wù)的pom.xml文件中添加如下依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-feign</artifactId> 
  4. </dependency> 

同時(shí),還需要在被消費(fèi)的微服務(wù)Application中添加@EnableFeignClients注解。例如在Statistics服務(wù)的應(yīng)用程序類中:

  1. @SpringBootApplication 
  2. @EnableDiscoveryClient 
  3. @EnableFeignClients 
  4. public class StatisticsApplication { 
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(StatisticsApplication.class, args); 
  7.     } 

由于Account服務(wù)需要調(diào)用Statistics服務(wù),因此需要在Account服務(wù)項(xiàng)目中增加對(duì)應(yīng)的client接口:

  1. @FeignClient(name = "statistics-service"
  2. public interface StatisticsServiceClient { 
  3.  
  4.     @RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}"consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) 
  5.     void updateStatistics(@PathVariable("accountName") String accountName, Account account); 
  6.  

StatisticsServiceClient接口的updateStatistics()方法會(huì)調(diào)用URI為/statistics/{accountName}的REST服務(wù),且HTTP動(dòng)詞為put。這個(gè)服務(wù)其實(shí)對(duì)應(yīng)就是Statistics Service中StatisticsController類中的saveStatistics()方法:

  1. @RestController 
  2. public class StatisticsController { 
  3.  
  4.     @Autowired 
  5.     private StatisticsService statisticsService; 
  6.  
  7.     @RequestMapping(value = "/{accountName}"method = RequestMethod.PUT) 
  8.     public void saveStatistics(@PathVariable String accountName, @Valid @RequestBody Account account) { 
  9.         statisticsService.save(accountName, account); 
  10.     } 

在Account服務(wù)中,如果要調(diào)用Statistics服務(wù),都應(yīng)該通過(guò)StatisticsServiceClient接口進(jìn)行調(diào)用。例如,Account服務(wù)中的AccountServiceImpl要調(diào)用updateStatistics()方法,就可以在該類的實(shí)現(xiàn)中通過(guò)@autowired注入StatisticsServiceClient接口:

  1. @Service 
  2. public class AccountServiceImpl implements AccountService { 
  3.     @Autowired 
  4.     private StatisticsServiceClient statisticsClient; 
  5.  
  6.     @Autowired 
  7.     private AccountRepository repository; 
  8.  
  9.     @Override 
  10.     public void saveChanges(String name, Account update) { 
  11.  
  12.         //... 
  13.         statisticsClient.updateStatistics(name, account); 
  14.     } 

Notification服務(wù)對(duì)Account服務(wù)的調(diào)用如法炮制。

服務(wù)容錯(cuò)保護(hù)

在微服務(wù)架構(gòu)中,微服務(wù)之間可能存在依賴關(guān)系,例如Notification Service會(huì)調(diào)用Account Service,Account Service調(diào)用Statistics Service。真實(shí)產(chǎn)品中,微服務(wù)之間的調(diào)用會(huì)更加尋常。倘若上游服務(wù)出現(xiàn)了故障,就可能會(huì)因?yàn)橐蕾囮P(guān)系而導(dǎo)致故障的蔓延,最終導(dǎo)致整個(gè)系統(tǒng)的癱瘓。

Spring Cloud Hystrix通過(guò)實(shí)現(xiàn)斷路器(Circuit Breaker)模式以及線程隔離等功能,實(shí)現(xiàn)服務(wù)的容錯(cuò)保護(hù)。

仍然參考前面的例子?,F(xiàn)在系統(tǒng)的微服務(wù)包括:

  • 上游服務(wù):demo-service
  • 下游服務(wù):demo-consumer
  • Eureka服務(wù)器:eureka-server

假設(shè)上游服務(wù)可能會(huì)出現(xiàn)故障,為保證系統(tǒng)的健壯性,需要在下游服務(wù)中加入容錯(cuò)包含功能。首先需要在demo-consumer服務(wù)中添加對(duì)hystrix的依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-hystrix</artifactId> 
  4. </dependency> 

然后在demo-consumer的應(yīng)用程序類中加入@EnableCircuitBreaker開啟斷路器功能:

  1. @EnableCircuitBreaker 
  2. @EnableDiscoveryClient 
  3. @SpringBootApplication 
  4. public class ConsumerApplication { 
  5.     @Bean 
  6.     @LoadBalanced 
  7.     RestTemplate restTemplate() { 
  8.         return new RestTemplate(); 
  9.     } 
  10.     public static void main(String[] args) { 
  11.         SpringApplication.run(ConsumerApplication.class, args) 
  12.     } 

注意:Spring Cloud提供了@SpringCloudApplication注解簡(jiǎn)化如上代碼。該注解事實(shí)上已經(jīng)包含了前面所述的三個(gè)注解。@SpringCloudApplication注解的定義如下所示:

  1. @Target(ElementType.TYPE) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. @Documented 
  4. @Inherited 
  5. @SpringBootApplication 
  6. @EnableDiscoveryClient 
  7. @EnableCircuitBreaker 
  8. public @interface SpringCloudApplication {} 

接下來(lái),需要引入一個(gè)新的服務(wù)類來(lái)封裝hystrix提供的斷路器保護(hù)功能,主要是定義當(dāng)故障發(fā)生時(shí)需要執(zhí)行的回調(diào)邏輯,即代碼中指定的fallbackMethod:

  1. @Service 
  2. public class ConsumerService { 
  3.     @Autowired 
  4.     RestTemplate restTemplate; 
  5.  
  6.     @HystrixCommand(fallbackMethod = "consumerFallback"
  7.     public String consume() { 
  8.         return restTemplate.getForEntity("http://demo-service/demo", String.class).getBody();  
  9.     } 
  10.  
  11.     public String consumerFallback() { 
  12.         return "error"; 
  13.     } 
  14.  
  15. @RestController 
  16. public class ConsumerController { 
  17.     @Autowired 
  18.     ConsumerService consumerService; 
  19.  
  20.     @RequestMapping(value = "/demo-consumer"method = RequestMethod.Get) 
  21.     public String helloConsumer() { 
  22.         return consumerService.consume();  
  23.     } 

服務(wù)監(jiān)控

微服務(wù)架構(gòu)將服務(wù)的粒度分解的足夠細(xì),這使得它在保證服務(wù)足夠靈活、足夠獨(dú)立的優(yōu)勢(shì)下,也帶來(lái)了管理和監(jiān)控上的挑戰(zhàn),服務(wù)與服務(wù)之間的依賴也變得越來(lái)越復(fù)雜。因此,對(duì)服務(wù)健康度和運(yùn)行指標(biāo)的監(jiān)控就變得非常重要。

Hystrix提供了Dashboard用以監(jiān)控Hystrix的各項(xiàng)指標(biāo)信息。為了監(jiān)控整個(gè)系統(tǒng)的微服務(wù),我們需要為Hystrix Dashboard建立一個(gè)Spring Boot微服務(wù)。在該服務(wù)項(xiàng)目的pom文件中,添加如下依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-hystrix</artifactId> 
  4. </dependency> 
  5. <dependency> 
  6.     <groupId>org.springframework.cloud</groupId> 
  7.     <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> 
  8. </dependency> 
  9. <dependency> 
  10.     <groupId>org.springframework.cloud</groupId> 
  11.     <artifactId>spring-cloud-starter-actuator</artifactId> 
  12. </dependency> 

服務(wù)的Application類需要添加@EnableHystrixDashboard,以啟用Hystrix Dashboard功能。同時(shí),可能需要根據(jù)實(shí)際情況修改application.properties配置文件,例如選擇可用的端口號(hào)等。

如果要實(shí)現(xiàn)對(duì)集群的監(jiān)控,則需要加入Turbine。

API網(wǎng)關(guān)

理論上,客戶端可以直接向每個(gè)微服務(wù)直接發(fā)送請(qǐng)求。但是這種方式是存在挑戰(zhàn)和限制的,調(diào)用者需要知道所有端點(diǎn)的地址,分別對(duì)每一段信息執(zhí)行http請(qǐng)求,然后將結(jié)果合并到客戶端。

一般而言,針對(duì)微服務(wù)架構(gòu)模式的系統(tǒng),采用的都是前后端分離的架構(gòu)。為了明顯地隔離開前端與后端的邊界,我們通常可以專門為前端的消費(fèi)者定義更加粗粒度的Open Service。這些Open Service是對(duì)外的RESTful API服務(wù),可以通過(guò)F5、Nginx等網(wǎng)絡(luò)設(shè)備或工具軟件實(shí)現(xiàn)對(duì)各個(gè)微服務(wù)的路由與負(fù)載均衡,并公開給外部的客戶端調(diào)用(注意,內(nèi)部微服務(wù)之間的調(diào)用并不需要通過(guò)Open Service)。這種對(duì)外公開的Open Service通常又被稱為邊緣服務(wù)(edge service)。

如果這些Open Service需要我們自己去開發(fā)實(shí)現(xiàn)并進(jìn)行服務(wù)的運(yùn)維,在系統(tǒng)規(guī)模不斷增大的情況下,會(huì)變得越來(lái)越困難。例如,當(dāng)增加了新的微服務(wù)又或者IP地址發(fā)生變動(dòng)時(shí),都需要運(yùn)維人員手工維護(hù)這些路由規(guī)則與服務(wù)實(shí)例列表。又例如針對(duì)所有垂直分隔的微服務(wù),不可避免存在重用的橫切關(guān)注點(diǎn),例如用戶身份認(rèn)證、授權(quán)或簽名校驗(yàn)等機(jī)制。我們不能在所有微服務(wù)中都去添加這些相同的功能,因?yàn)檫@會(huì)造成橫切關(guān)注點(diǎn)的冗余。

解決的辦法是引入API網(wǎng)關(guān)(API Gateway)。它是系統(tǒng)的單個(gè)入口點(diǎn),用于通過(guò)將請(qǐng)求路由到適當(dāng)?shù)暮蠖朔?wù)或者通過(guò)調(diào)用多個(gè)后端服務(wù)并聚合結(jié)果來(lái)處理請(qǐng)求。此外,它還可以用于認(rèn)證、insights、壓力測(cè)試、金絲雀測(cè)試(canary testing)、服務(wù)遷移、靜態(tài)響應(yīng)處理和主動(dòng)變換管理。Spring Cloud為API網(wǎng)關(guān)提供的解決方案就是Spring Cloud Zuul,它是對(duì)Netflix Zuul的包裝。

路由規(guī)則與服務(wù)實(shí)例維護(hù)

Zuul解決路由規(guī)則與服務(wù)實(shí)例維護(hù)的方法是通過(guò)Spring Cloud Eureka。API Gateway自身就是一個(gè)Spring Boot服務(wù),該服務(wù)自身被注冊(cè)為Eureka服務(wù)治理下的應(yīng)用,同時(shí)它會(huì)從Eureka中獲得所有其他微服務(wù)的實(shí)例信息。這樣的設(shè)計(jì)符合DRY原則,因?yàn)镋ureka已經(jīng)維護(hù)了一套服務(wù)實(shí)例信息,Zuul直接重用了這些信息,無(wú)需人工介入。

對(duì)于路由規(guī)則,Zuul默認(rèn)會(huì)將服務(wù)名作為ContextPath創(chuàng)建路由映射,基本上這種路由映射機(jī)制就可以滿足微服務(wù)架構(gòu)的路由需求。倘若需要一些特殊的配置,Zuul也允許我們自定義路由規(guī)則,可以通過(guò)在API網(wǎng)關(guān)的Application類中創(chuàng)建PatternServiceRouteMapper來(lái)定義自己的規(guī)則。

橫切關(guān)注點(diǎn)

諸如授權(quán)認(rèn)證、簽名校驗(yàn)等業(yè)務(wù)邏輯本身與微服務(wù)應(yīng)用所要處理的業(yè)務(wù)邏輯沒有直接關(guān)系,我們將這些可能橫跨多個(gè)微服務(wù)的功能稱為“橫切關(guān)注點(diǎn)”。這些橫切關(guān)注點(diǎn)往往會(huì)作為“裝飾”功能在服務(wù)方法的前后被調(diào)用。Spring Cloud Zuul提供了一套過(guò)濾器機(jī)制,允許開發(fā)者創(chuàng)建各種過(guò)濾器,并指定哪些規(guī)則的請(qǐng)求需要執(zhí)行哪個(gè)過(guò)濾器。

自定義的過(guò)濾器繼承自ZuulFilter類。例如我們要求客戶端發(fā)過(guò)來(lái)的請(qǐng)求在路由之前需要先驗(yàn)證請(qǐng)求中是否包含accessToken參數(shù),如果有就進(jìn)行路由,否則就拒絕,并返回401 Unauthorized錯(cuò)誤,則可以定義AccessFilter類:

  1. public class AccessFilter extends ZuulFilter { 
  2.     private static Logger log = LoggerFactory.getLogger(AccessFilter.class); 
  3.  
  4.     @Override 
  5.     public String filterType() { 
  6.         return "pre" 
  7.     } 
  8.  
  9.     @Override 
  10.     public int filterOrder() { 
  11.         return 0; 
  12.     } 
  13.  
  14.     @Override 
  15.     public boolean shouldFilter() { 
  16.         return true; 
  17.     } 
  18.      
  19.     @Override 
  20.     public Object run() { 
  21.         RequestContext ctx = RequestContext.getCurrentContext(); 
  22.         HttpServletRequest request = ctx.getRequest(); 
  23.          
  24.         log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); 
  25.  
  26.         Object accessToken = request.getParameter("accessToken"); 
  27.         if (accessToken == null) { 
  28.             log.warn("access token is empty"); 
  29.             ctx.setSendZuulResponse(false); 
  30.             ctx.setResponseStatusCode(401); 
  31.             return null; 
  32.         } 
  33.         log.info("access token ok"); 
  34.         return null; 
  35.     } 

要讓該自定義過(guò)濾器生效,還需要在Zuul服務(wù)的Application中創(chuàng)建具體的Bean:

  1. @EnableZuulProxy 
  2. @SpringCloudApplication 
  3. public class ZuulApplication { 
  4.     public static void main(String[] args) { 
  5.         new SpringApplicatonBuilder(ZuulApplication.class).web(true).run(args); 
  6.     } 
  7.  
  8.     @Bean 
  9.     public AccessFilter accessFilter() { 
  10.         return new AccessFilter(); 
  11.     } 

Zuul一共提供了四種過(guò)濾器:

  • pre filter
  • routing filter
  • post filter
  • error filter

下圖來(lái)自官網(wǎng),它展現(xiàn)了客戶端請(qǐng)求到達(dá)Zuul API網(wǎng)關(guān)的生命周期與過(guò)濾過(guò)程:

通過(guò)starter添加Zuul的依賴時(shí),自身包含了spring-cloud-starter-hystrix與spring-cloud-starter-ribbon模塊的依賴,因此Zuul自身就擁有線程隔離與斷路器的服務(wù)容錯(cuò)功能,以及客戶端負(fù)載均衡。但是,倘若我們使用path與url的映射關(guān)系來(lái)配置路由規(guī)則,則路由轉(zhuǎn)發(fā)的請(qǐng)求并不會(huì)采用HystrixCommand來(lái)包裝,因而這類路由是沒有服務(wù)容錯(cuò)與客戶端負(fù)載均衡作用的。所以在使用Zuul時(shí),應(yīng)盡量使用path和serviceId的組合對(duì)路由進(jìn)行配置。

分布式配置中心

為什么要引入一個(gè)分布式配置中心?一個(gè)微服務(wù)就需要至少一個(gè)配置文件,怎么管理分散在各個(gè)微服務(wù)中的配置文件呢?如果微服務(wù)采用的是不同的技術(shù)棧,如何來(lái)統(tǒng)一微服務(wù)的配置呢?微服務(wù)是部署在不同的節(jié)點(diǎn)中,顯然我們無(wú)法在單機(jī)中實(shí)現(xiàn)對(duì)分布式節(jié)點(diǎn)的配置管理。這就是引入Spring Cloud Config的目的。

Spring Cloud Config提供了服務(wù)端和客戶端支持。服務(wù)端是一個(gè)獨(dú)立的微服務(wù),同樣可以注冊(cè)到Eureka服務(wù)器中。每個(gè)需要使用分布式配置中心的微服務(wù)都是Spring Cloud Config的客戶端。Spring Cloud Config默認(rèn)實(shí)現(xiàn)基于Git倉(cāng)庫(kù),既可以進(jìn)行版本管理,還可以通過(guò)本地Git庫(kù)起到緩存作用。Spring Cloud Config不限于基于Spring Cloud開發(fā)的系統(tǒng),而是可以用于任何語(yǔ)言開發(fā)的程序,并支持自定義實(shí)現(xiàn)。

配置中心服務(wù)端

Spring Cloud Config Server作為配置中心服務(wù)端,提供如下功能:

  • 拉取配置時(shí)更新git倉(cāng)庫(kù)副本,保證是***結(jié)果
  • 支持?jǐn)?shù)據(jù)結(jié)構(gòu)豐富,yml, json, properties等
  • 配合Eureke可實(shí)現(xiàn)服務(wù)發(fā)現(xiàn),配合cloud bus可實(shí)現(xiàn)配置推送更新
  • 配置存儲(chǔ)基于git倉(cāng)庫(kù),可進(jìn)行版本管理
  • 簡(jiǎn)單可靠,有豐富的配套方案

建立一個(gè)Config服務(wù),需要添加如下依賴:

  1. <dependency> 
  2.     <groupId>org.springframework.cloud</groupId> 
  3.     <artifactId>spring-cloud-config-server</artifactId> 
  4. </dependency> 

服務(wù)的Application類需要添加@EnableConfigServer注解:

  1. @SpringBootApplication 
  2. @EnableConfigServer 
  3. public class ConfigApplication { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(ConfigApplication.class, args); 
  7.     } 

配置服務(wù)的基本信息和Git倉(cāng)庫(kù)的信息放在application.yml文件中:

  1. spring: 
  2.   cloud: 
  3.     config: 
  4.       server: 
  5.         git: 
  6.             uri: http://localhost/workspace/springcloud-demo 
  7.             username: user 
  8.             password: password 
  9.  
  10. server: 
  11.   port: 8888 
  12.  
  13. security: 
  14.   user: 
  15.     password: ${CONFIG_SERVICE_PASSWORD} 

Git庫(kù)與配置服務(wù)

在Config服務(wù)中配置了Git服務(wù)器以及Git庫(kù)的信息后,我們就可以在git庫(kù)中提交配置文件。存儲(chǔ)在git庫(kù)中配置文件的名字以及分支名(默認(rèn)為master分支)會(huì)組成訪問(wèn)Config服務(wù)的URI。假設(shè)有一個(gè)服務(wù)為Notification服務(wù),則它在配置中心服務(wù)端的配置文件為notification-dev.yml,內(nèi)容如下:

  1. devMode:  true 
  2. spring: 
  3.     application: 
  4.         name: notification 
  5.     jdbc: 
  6.         host: localhost 
  7.         port: 3306 
  8.         user: root 
  9.         password: 123456 
  10. logging: 
  11.     file: demo 

配置中心客戶端

需要讀取配置中心服務(wù)端信息的微服務(wù)都是配置中心的客戶端,為了能夠讀取配置服務(wù)端的信息,這些微服務(wù)需要:

  • 在pom中添加對(duì)spring-cloud-starter-config的依賴
  • 在bootstrap.properties或者bootstrap.yml中配置獲取配置的config-server位置

例如,Account服務(wù)的配置是由Spring Cloud Config進(jìn)行管理的。在它的資源目錄下,提供了bootstrap.yml配置文件,內(nèi)容如下所示:

  1. spring: 
  2.   application: 
  3.     name: account-service 
  4.   cloud: 
  5.     config: 
  6.       uri: http://config:8888 
  7.       fail-fast: true 
  8.       password: ${CONFIG_SERVICE_PASSWORD} 
  9.       username: user 

注意,該配置文件除了配置了該Account服務(wù)應(yīng)用的name之外,主要是支持該應(yīng)用獲得配置服務(wù)端的信息。微服務(wù)自身的配置信息則統(tǒng)一放到配置中心服務(wù)端的文件中,并由Git庫(kù)進(jìn)行管理。例如,Account服務(wù)的詳細(xì)配置在配置中心服務(wù)端的account-dev.yml文件中:

  1. security: 
  2.   oauth2: 
  3.     client: 
  4.       clientId: account-service 
  5.       clientSecret: ${ACCOUNT_SERVICE_PASSWORD} 
  6.       accessTokenUri: http://auth-service:5000/uaa/oauth/token 
  7.       grant-type: client_credentials 
  8.       scope: server 
  9.  
  10. spring: 
  11.   data: 
  12.     mongodb: 
  13.       host: account-mongodb 
  14.       username: user 
  15.       password: ${MONGODB_PASSWORD} 
  16.       database: piggymetrics 
  17.       port: 27017 
  18.  
  19. server: 
  20.   context-path: /accounts 
  21.   port: 6000 

Spring Cloud Config通過(guò)Git實(shí)現(xiàn)分布式的配置管理。當(dāng)配置中心服務(wù)端的配置信息發(fā)生變更時(shí),各個(gè)作為配置客戶端的微服務(wù)會(huì)向Git庫(kù)提交pull更新,獲得***的配置信息。

當(dāng)然,Spring Cloud Config還可以使用SVN庫(kù)進(jìn)行配置管理,也支持簡(jiǎn)單的本地文件系統(tǒng)的存儲(chǔ)方式。此時(shí)需要將spring.profiles.active設(shè)置為native,并設(shè)置搜索配置文件的路徑。如果不配置路徑,默認(rèn)在src/main/resources目錄下搜索。如下配置文件:

  1. spring: 
  2.   cloud: 
  3.     config: 
  4.       server: 
  5.         native: 
  6.           search-locations: classpath:/shared 
  7.   profiles: 
  8.     active: native 

搜索路徑放在classpath下的shared目錄下,那么在代碼中,目錄就是resources/shared。如果使用本地文件系統(tǒng)管理配置文件,則無(wú)法支持分布式配置管理以及版本管理,因此在生產(chǎn)系統(tǒng)下,還是推薦使用Git庫(kù)的方式。

總結(jié)

在實(shí)施微服務(wù)時(shí),我們可以將微服務(wù)視為兩個(gè)不同的邊界。一個(gè)是與前端UI的通信,稱為Open Service(Edge Service),通過(guò)引入API Gateway來(lái)實(shí)現(xiàn)與前端UI的通信。另一個(gè)是在邊界內(nèi)業(yè)務(wù)微服務(wù)之間的通信,通過(guò)Feign實(shí)現(xiàn)微服務(wù)之間的協(xié)作。所有的微服務(wù)都會(huì)通過(guò)Eureka來(lái)完成微服務(wù)的注冊(cè)與發(fā)現(xiàn)。一個(gè)典型的基于Spring Cloud的微服務(wù)架構(gòu)如下所示:

微服務(wù)的集成可以通過(guò)Feign+Ribbon以RESTful方式實(shí)現(xiàn)通信,也可以基于RPC方式(可以結(jié)合Protocol Buffer)完成服務(wù)之間的通信,甚至可以通過(guò)發(fā)布事件與訂閱事件的機(jī)制。事件機(jī)制可以使微服務(wù)之間更加松散耦合。這時(shí),我們可以引入RabbitMQ或Kafka來(lái)做到服務(wù)與服務(wù)之間的解耦。事件機(jī)制是異步和非阻塞的,在某些業(yè)務(wù)場(chǎng)景下,它的性能會(huì)更加的好。Spring Cloud也提供了相關(guān)的組件Spring Cloud Stream來(lái)支持這種事件機(jī)制。

對(duì)于微服務(wù)之間的協(xié)作,到底選擇Feign這種REST方式、事件機(jī)制或者RPC方式,取決于業(yè)務(wù)場(chǎng)景是否需要同步方式,還是異步方式;是高性能高并發(fā),還是普通方式;是要求徹底解耦,還是做到一般的松散耦合。我們需要針對(duì)實(shí)際情況作出實(shí)際的判斷,作出正確的選擇。沒有誰(shuí)壞誰(shuí)好之分,而是看誰(shuí)更加的適合。

【本文為51CTO專欄作者“張逸”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專欄
相關(guān)推薦

2017-09-05 14:05:11

微服務(wù)spring clou路由

2024-08-20 09:59:22

2023-12-19 09:33:40

微服務(wù)監(jiān)控

2021-12-14 06:59:39

微服務(wù)Kubernetes架構(gòu)

2024-02-06 18:05:54

微服務(wù)SpringCloud

2024-08-05 10:03:53

2017-06-26 09:06:10

Spring Clou微服務(wù)架構(gòu)

2017-12-20 15:37:39

Spring Clou微服務(wù)架構(gòu)

2024-07-10 10:51:39

SpringEureka數(shù)據(jù)中心

2017-09-04 16:15:44

服務(wù)網(wǎng)關(guān)架構(gòu)

2020-06-30 07:58:39

微服務(wù)Spring BootCloud

2024-11-21 16:09:22

2021-10-19 14:02:12

服務(wù)器SpringSecurity

2017-07-03 09:50:07

Spring Clou微服務(wù)架構(gòu)

2022-02-12 21:08:56

微服務(wù)SpringIstio

2017-08-10 11:15:05

Spring Clou微服務(wù)架構(gòu)

2017-08-09 15:50:47

Spring Clou微服務(wù)架構(gòu)

2024-06-05 12:03:43

微服務(wù)架構(gòu)場(chǎng)景

2018-01-25 11:31:29

IBM微服務(wù)架構(gòu)

2018-06-25 08:00:18

Spring Clou架構(gòu)數(shù)據(jù)中臺(tái)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)