微服務(wù)架構(gòu)模式的核心在于如何識別服務(wù)的邊界预吆,設(shè)計出合理的微服務(wù)鳞绕。但如果要將微服務(wù)架構(gòu)運用到生產(chǎn)項目上失仁,并且能夠發(fā)揮該架構(gòu)模式的重要作用,則需要微服務(wù)框架的支持们何。
在Java生態(tài)圈萄焦,目前使用較多的微服務(wù)框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud。它包括:
Spring Cloud Config:配置管理工具冤竹,支持使用Git存儲配置內(nèi)容拂封,可以實現(xiàn)應(yīng)用配置的外部化存儲,支持客戶端配置信息刷新鹦蠕、加密/解密配置內(nèi)容等冒签。
Spring Cloud Netflix:對Netflix OSS進行了整合。其中又包括:
Eureka:服務(wù)治理組件钟病,包含服務(wù)注冊中心萧恕、服務(wù)注冊與發(fā)現(xiàn)。
Hystrix:容器管理組件肠阱,實現(xiàn)斷路器模式廊鸥,倘若依賴的服務(wù)出現(xiàn)延遲或故障,則提供強大的容錯功能辖所。
Ribbon:客戶端負載均衡的服務(wù)調(diào)用組件。
Feign:基于Ribbon和Hystrix的聲明式服務(wù)調(diào)用組件磨德。
Zuul:網(wǎng)關(guān)組件缘回,提供智能路由、訪問過濾等功能典挑。
Archaius:外部化配置組件酥宴。
Spring Cloud Bus:事件、消息總線您觉。
Spring Cloud Cluster:針對ZooKeeper拙寡、Redis、Hazelcast琳水、Consul的選舉算法和通用狀態(tài)模式的實現(xiàn)肆糕。
Spring Cloud Cloudfoundry:與Pivotal Cloudfoundry的整合支持般堆。
Spring Cloud Consul:服務(wù)發(fā)現(xiàn)與配置管理工具。
Spring Cloud Stream:通過Redis诚啃、Rabbit或者Kafka實現(xiàn)的消息驅(qū)動的微服務(wù)淮摔。
Spirng Cloud AWS:簡化和整合Amazon Web Service。
Spring Cloud Security:安全工具包始赎,提供Zuul代理中對OAuth2客戶端請求的中繼器和橙。
Spring Cloud Sleuth:Spring Cloud應(yīng)用的分布式跟蹤實現(xiàn),可以整合Zipkin造垛。
Spring Cloud ZooKeeper:基于ZooKeeper的服務(wù)發(fā)現(xiàn)與配置管理組件魔招。
Spring Cloud Starters:Spring Cloud的基礎(chǔ)組件,是基于Spring Boot風(fēng)格項目的基礎(chǔ)依賴模塊五辽。
Spring Cloud CLI:用于在Groovy中快速創(chuàng)建Spring Cloud應(yīng)用的Spring Boot CLI插件办斑。
服務(wù)治理
當一個系統(tǒng)的微服務(wù)數(shù)量越來越多的時候,我們就需要對服務(wù)進行治理奔脐,提供統(tǒng)一的服務(wù)注冊中心俄周,然后在其框架下提供發(fā)現(xiàn)服務(wù)的功能。這樣就避免了對多個微服務(wù)的配置髓迎,以及微服務(wù)之間以及與客戶端之間的耦合峦朗。
Spring Cloud Eureka是對Netflix Eureka的包裝,用以實現(xiàn)服務(wù)注冊與發(fā)現(xiàn)排龄。Eureka服務(wù)端即服務(wù)注冊中心波势,支持高可用配置。它依托于強一致性提供良好的服務(wù)實例可用性橄维,并支持集群模式部署尺铣。Eureka客戶端則負責(zé)處理服務(wù)的注冊與發(fā)現(xiàn)≌瑁客戶端服務(wù)通過annotation與參數(shù)配置的方式凛忿,嵌入在客戶端應(yīng)用程序代碼中。在運行應(yīng)用程序時竞川,Eureka客戶端向注冊中心注冊自身提供的服務(wù)店溢,并周期性地發(fā)送心跳更新它的服務(wù)租約。
搭建服務(wù)注冊中心
服務(wù)注冊中心是一個獨立部署的服務(wù)(你可以認為它也是一個微服務(wù))委乌,所以需要單獨為它創(chuàng)建一個項目床牧,并在pom.xml中添加Eureka的依賴:
org.springframework.cloudspring-cloud-starter-eureka-server
創(chuàng)建Spring Boot Application:
@EnableEurekaServer@SpringBootApplicationpublic class Application {publicstaticvoidmain(String[] args) {? ? ? ? new SpringApplicationBuilder(Application.class).web(true).run(args);? ? }}
注冊服務(wù)提供者
要讓自己編寫的微服務(wù)能夠注冊到Eureka服務(wù)器中,需要在服務(wù)的Spring Boot Application中添加 @EnableDiscoveryClient 注解遭贸,如此才能讓Eureka服務(wù)器發(fā)現(xiàn)該服務(wù)戈咳。當然,pom.xml文件中也需要添加相關(guān)依賴:
org.springframework.cloudspring-cloud-starter-eureka
同時,我們還需要為服務(wù)命名著蛙,并指定地址删铃。這些信息都可以在application.properties配置文件中配置:
spring.application.name=demo-serviceeureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
說明:Spring更推薦使用yml文件來維護系統(tǒng)的配置,yml文件可以體現(xiàn)出配置節(jié)的層次關(guān)系册踩,表現(xiàn)力比單純的key-value形式更好泳姐。如果結(jié)合使用后面講到的Spring Cloud Config,則客戶端的配置文件必須命名為bootstrap.properties或者bootstrap.yml暂吉。與上述配置相同的yml文件配置為:
spring:application:name: demo-serviceeureka:client:serviceUrl:defaultZone:http://localhost:1111/eureka/
服務(wù)發(fā)現(xiàn)與消費
在微服務(wù)架構(gòu)下胖秒,許多微服務(wù)可能會扮演雙重身份。一方面它是服務(wù)的提供者慕的,另一方面它又可能是服務(wù)的消費者阎肝。注冊在Eureka Server中的微服務(wù)可能會被別的服務(wù)消費。此時肮街,就相當于在服務(wù)中創(chuàng)建另一個服務(wù)的客戶端风题,并通過RestTemplate發(fā)起對服務(wù)的調(diào)用。為了更好地提高性能嫉父,可以在服務(wù)的客戶端引入Ribbon沛硅,作為客戶端負載均衡。
現(xiàn)在假定我們要為demo-service創(chuàng)建一個服務(wù)消費者demo-consumer绕辖。該消費者自身也是一個Spring Boot微服務(wù)摇肌,同時也能夠被Eureka服務(wù)器注冊。這時仪际,就需要在該服務(wù)的pom.xml中添加eureka與ribbon的依賴:
org.springframework.cloudspring-cloud-starter-eurekaorg.springframework.cloudspring-cloud-starter-ribbon
然后在主應(yīng)用類 ConosumerApplication 中注入 RestTemplate 围小,并引入 @LoadBalanced 注解開啟客戶端負載均衡:
@EnableDiscoveryClient@SpringBootApplicationpublic class ConsumerApplication {@Bean@LoadBalancedRestTemplate restTemplate() {? ? ? ? return new RestTemplate();? ? }? ? public static void main(String[] args) {? ? ? ? SpringApplication.run(ConsumerApplication.class, args)? ? }}
假設(shè)消費demo-service的客戶端代碼寫在demo-consumer服務(wù)的其中一個Controller中:
@RestControllerpublicclass ConsumerController {@AutowiredRestTemplate restTemplate;@RequestMapping(value = "/demo-consumer", method = RequestMethod.Get)publicString helloConsumer() {returnrestTemplate.getForEntity("http://demo-service/demo", String.class).getBody();? ? }}
通過 RestTemplate 就可以發(fā)起對demo-service的消費調(diào)用。
聲明式服務(wù)調(diào)用
通過Ribbon和Hystrix可以實現(xiàn)對微服務(wù)的調(diào)用以及容錯保護树碱,但Spring Cloud還提供了另一種更簡單的聲明式服務(wù)調(diào)用方式肯适,即Spring Cloud Feign。Feign實際上就是對Ribbon與Hystrix的進一步封裝成榜。通過Feign框舔,我們只需創(chuàng)建一個接口并用annotation的方式配置,就可以完成對服務(wù)供應(yīng)方的接口(REST API)綁定赎婚。
假設(shè)我們有三個服務(wù):
Notification Service
Account Service
Statistics Service
服務(wù)之間的依賴關(guān)系如下圖所示:
要使用Feign來完成聲明式的服務(wù)調(diào)用雨饺,需要在作為調(diào)用者的服務(wù)中創(chuàng)建Client。Client通過Eureka Server調(diào)用注冊的對應(yīng)服務(wù)惑淳,這樣可以解除服務(wù)之間的耦合。結(jié)構(gòu)如下圖所示:
為了使用Feign饺窿,需要對應(yīng)微服務(wù)的pom.xml文件中添加如下依賴:
org.springframework.cloudspring-cloud-starter-feign
同時歧焦,還需要在被消費的微服務(wù)Application中添加 @EnableFeignClients 注解。例如在Statistics服務(wù)的應(yīng)用程序類中:
@SpringBootApplication@EnableDiscoveryClient@EnableFeignClientspublic class StatisticsApplication {publicstaticvoidmain(String[] args) {? ? ? ? SpringApplication.run(StatisticsApplication.class, args);? ? }}
由于Account服務(wù)需要調(diào)用Statistics服務(wù),因此需要在Account服務(wù)項目中增加對應(yīng)的client接口:
@FeignClient(name ="statistics-service")public interface StatisticsServiceClient {@RequestMapping(method = RequestMethod.PUT, value ="/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)? ? void updateStatistics(@PathVariable("accountName") String accountName, Account account);}
StatisticsServiceClient接口的 updateStatistics() 方法會調(diào)用URI為 /statistics/{accountName} 的REST服務(wù)绢馍,且HTTP動詞為put向瓷。這個服務(wù)其實對應(yīng)就是Statistics Service中StatisticsController類中的 saveStatistics() 方法:
@RestControllerpublic class StatisticsController {@Autowiredprivate StatisticsService statisticsService;@RequestMapping(value ="/{accountName}", method = RequestMethod.PUT)? ? public void saveStatistics(@PathVariableString accountName,@Valid@RequestBodyAccount account) {? ? ? ? statisticsService.save(accountName, account);? ? }}
在Account服務(wù)中,如果要調(diào)用Statistics服務(wù)舰涌,都應(yīng)該通過StatisticsServiceClient接口進行調(diào)用猖任。例如,Account服務(wù)中的AccountServiceImpl要調(diào)用 updateStatistics() 方法瓷耙,就可以在該類的實現(xiàn)中通過 @autowired 注入StatisticsServiceClient接口:
@Servicepublicclass AccountServiceImpl implements AccountService {@AutowiredprivateStatisticsServiceClient statisticsClient;@AutowiredprivateAccountRepository repository;@Overridepublic void saveChanges(String name, Account update) {//...statisticsClient.updateStatistics(name, account);? ? }}
Notification服務(wù)對Account服務(wù)的調(diào)用如法炮制朱躺。
服務(wù)容錯保護
在微服務(wù)架構(gòu)中,微服務(wù)之間可能存在依賴關(guān)系搁痛,例如Notification Service會調(diào)用Account Service长搀,Account Service調(diào)用Statistics Service。真實產(chǎn)品中鸡典,微服務(wù)之間的調(diào)用會更加尋常源请。倘若上游服務(wù)出現(xiàn)了故障,就可能會因為依賴關(guān)系而導(dǎo)致故障的蔓延彻况,最終導(dǎo)致整個系統(tǒng)的癱瘓谁尸。
Spring Cloud Hystrix通過實現(xiàn)斷路器(Circuit Breaker)模式以及線程隔離等功能,實現(xiàn)服務(wù)的容錯保護纽甘。
仍然參考前面的例子×悸現(xiàn)在系統(tǒng)的微服務(wù)包括:
上游服務(wù):demo-service
下游服務(wù):demo-consumer
Eureka服務(wù)器:eureka-server
假設(shè)上游服務(wù)可能會出現(xiàn)故障,為保證系統(tǒng)的健壯性贷腕,需要在下游服務(wù)中加入容錯包含功能背镇。首先需要在demo-consumer服務(wù)中添加對hystrix的依賴:
org.springframework.cloudspring-cloud-starter-hystrix
然后在demo-consumer的應(yīng)用程序類中加入 @EnableCircuitBreaker 開啟斷路器功能:
@EnableCircuitBreaker@EnableDiscoveryClient@SpringBootApplicationpublic class ConsumerApplication {@Bean@LoadBalancedRestTemplate restTemplate() {? ? ? ? return new RestTemplate();? ? }? ? public static void main(String[] args) {? ? ? ? SpringApplication.run(ConsumerApplication.class, args)? ? }}
注意:Spring Cloud提供了 @SpringCloudApplication 注解簡化如上代碼。該注解事實上已經(jīng)包含了前面所述的三個注解泽裳。 @SpringCloudApplication 注解的定義如下所示:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootApplication@EnableDiscoveryClient@EnableCircuitBreakerpublic@interfaceSpringCloudApplication {}
接下來瞒斩,需要引入一個新的服務(wù)類來封裝hystrix提供的斷路器保護功能,主要是定義當故障發(fā)生時需要執(zhí)行的回調(diào)邏輯涮总,即代碼中指定的fallbackMethod:
@Servicepublic class ConsumerService {@AutowiredRestTemplate restTemplate;@HystrixCommand(fallbackMethod ="consumerFallback")? ? public String consume() {? ? ? ? return restTemplate.getForEntity("http://demo-service/demo", String.class).getBody();? ? }? ? public String consumerFallback() {? ? ? ? return "error";? ? }}@RestControllerpublic class ConsumerController {@AutowiredConsumerService consumerService;@RequestMapping(value ="/demo-consumer", method = RequestMethod.Get)? ? public String helloConsumer() {? ? ? ? return consumerService.consume();? ? }}
服務(wù)監(jiān)控
微服務(wù)架構(gòu)將服務(wù)的粒度分解的足夠細胸囱,這使得它在保證服務(wù)足夠靈活、足夠獨立的優(yōu)勢下瀑梗,也帶來了管理和監(jiān)控上的挑戰(zhàn)烹笔,服務(wù)與服務(wù)之間的依賴也變得越來越復(fù)雜。因此抛丽,對服務(wù)健康度和運行指標的監(jiān)控就變得非常重要谤职。
Hystrix提供了Dashboard用以監(jiān)控Hystrix的各項指標信息。為了監(jiān)控整個系統(tǒng)的微服務(wù)亿鲜,我們需要為Hystrix Dashboard建立一個Spring Boot微服務(wù)允蜈。在該服務(wù)項目的pom文件中,添加如下依賴:
org.springframework.cloudspring-cloud-starter-hystrixorg.springframework.cloudspring-cloud-starter-hystrix-dashboardorg.springframework.cloudspring-cloud-starter-actuator
服務(wù)的Application類需要添加 @EnableHystrixDashboard ,以啟用Hystrix Dashboard功能饶套。同時漩蟆,可能需要根據(jù)實際情況修改application.properties配置文件,例如選擇可用的端口號等妓蛮。
如果要實現(xiàn)對集群的監(jiān)控怠李,則需要加入Turbine。
API網(wǎng)關(guān)
理論上蛤克,客戶端可以直接向每個微服務(wù)直接發(fā)送請求捺癞。但是這種方式是存在挑戰(zhàn)和限制的,調(diào)用者需要知道所有端點的地址咖耘,分別對每一段信息執(zhí)行http請求翘簇,然后將結(jié)果合并到客戶端。
一般而言儿倒,針對微服務(wù)架構(gòu)模式的系統(tǒng)版保,采用的都是前后端分離的架構(gòu)。為了明顯地隔離開前端與后端的邊界夫否,我們通吵估纾可以專門為前端的消費者定義更加粗粒度的Open Service。這些Open Service是對外的RESTful API服務(wù)凰慈,可以通過F5汞幢、Nginx等網(wǎng)絡(luò)設(shè)備或工具軟件實現(xiàn)對各個微服務(wù)的路由與負載均衡,并公開給外部的客戶端調(diào)用(注意微谓,內(nèi)部微服務(wù)之間的調(diào)用并不需要通過Open Service)森篷。這種對外公開的Open Service通常又被稱為邊緣服務(wù)(edge service)。
如果這些Open Service需要我們自己去開發(fā)實現(xiàn)并進行服務(wù)的運維豺型,在系統(tǒng)規(guī)模不斷增大的情況下仲智,會變得越來越困難。例如姻氨,當增加了新的微服務(wù)又或者IP地址發(fā)生變動時钓辆,都需要運維人員手工維護這些路由規(guī)則與服務(wù)實例列表。又例如針對所有垂直分隔的微服務(wù)肴焊,不可避免存在重用的橫切關(guān)注點前联,例如用戶身份認證、授權(quán)或簽名校驗等機制娶眷。我們不能在所有微服務(wù)中都去添加這些相同的功能似嗤,因為這會造成橫切關(guān)注點的冗余。
解決的辦法是引入API網(wǎng)關(guān)(API Gateway)届宠。它是系統(tǒng)的單個入口點双谆,用于通過將請求路由到適當?shù)暮蠖朔?wù)或者通過調(diào)用多個后端服務(wù)并聚合結(jié)果來處理請求壳咕。此外,它還可以用于認證顽馋、insights、壓力測試幌羞、金絲雀測試(canary testing)寸谜、服務(wù)遷移、靜態(tài)響應(yīng)處理和主動變換管理属桦。Spring Cloud為API網(wǎng)關(guān)提供的解決方案就是Spring Cloud Zuul熊痴,它是對Netflix Zuul的包裝。
路由規(guī)則與服務(wù)實例維護
Zuul解決路由規(guī)則與服務(wù)實例維護的方法是通過Spring Cloud Eureka聂宾。API Gateway自身就是一個Spring Boot服務(wù)果善,該服務(wù)自身被注冊為Eureka服務(wù)治理下的應(yīng)用,同時它會從Eureka中獲得所有其他微服務(wù)的實例信息系谐。這樣的設(shè)計符合DRY原則巾陕,因為Eureka已經(jīng)維護了一套服務(wù)實例信息,Zuul直接重用了這些信息纪他,無需人工介入鄙煤。
對于路由規(guī)則,Zuul默認會將服務(wù)名作為ContextPath創(chuàng)建路由映射茶袒,基本上這種路由映射機制就可以滿足微服務(wù)架構(gòu)的路由需求梯刚。倘若需要一些特殊的配置,Zuul也允許我們自定義路由規(guī)則薪寓,可以通過在API網(wǎng)關(guān)的Application類中創(chuàng)建PatternServiceRouteMapper來定義自己的規(guī)則亡资。
橫切關(guān)注點
諸如授權(quán)認證、簽名校驗等業(yè)務(wù)邏輯本身與微服務(wù)應(yīng)用所要處理的業(yè)務(wù)邏輯沒有直接關(guān)系向叉,我們將這些可能橫跨多個微服務(wù)的功能稱為“橫切關(guān)注點”锥腻。這些橫切關(guān)注點往往會作為“裝飾”功能在服務(wù)方法的前后被調(diào)用。Spring Cloud Zuul提供了一套過濾器機制植康,允許開發(fā)者創(chuàng)建各種過濾器旷太,并指定哪些規(guī)則的請求需要執(zhí)行哪個過濾器。
自定義的過濾器繼承自ZuulFilter類销睁。例如我們要求客戶端發(fā)過來的請求在路由之前需要先驗證請求中是否包含accessToken參數(shù)供璧,如果有就進行路由,否則就拒絕冻记,并返回401 Unauthorized錯誤睡毒,則可以定義AccessFilter類:
publicclass AccessFilter extends ZuulFilter {privatestaticLogger log = LoggerFactory.getLogger(AccessFilter.class);@Overridepublic String filterType() {return"pre"}@Overridepublic int filterOrder() {return0;? ? }@Overridepublic boolean shouldFilter() {returntrue;? ? }@Overridepublic Object run() {? ? ? ? RequestContext ctx = RequestContext.getCurrentContext();? ? ? ? HttpServletRequest request = ctx.getRequest();? ? ? ? ? ? ? ? log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());? ? ? ? Object accessToken = request.getParameter("accessToken");if(accessToken ==null) {? ? ? ? ? ? log.warn("access token is empty");? ? ? ? ? ? ctx.setSendZuulResponse(false);? ? ? ? ? ? ctx.setResponseStatusCode(401);returnnull;? ? ? ? }? ? ? ? log.info("access token ok");returnnull;? ? }}
要讓該自定義過濾器生效,還需要在Zuul服務(wù)的Application中創(chuàng)建具體的Bean:
@EnableZuulProxy@SpringCloudApplicationpublic class ZuulApplication {publicstaticvoidmain(String[] args) {? ? ? ? new SpringApplicatonBuilder(ZuulApplication.class).web(true).run(args);? ? }@Beanpublic AccessFilter accessFilter() {? ? ? ? return new AccessFilter();? ? }}
Zuul一共提供了四種過濾器:
pre filter
routing filter
post filter
error filter
下圖來自官網(wǎng)冗栗,它展現(xiàn)了客戶端請求到達Zuul API網(wǎng)關(guān)的生命周期與過濾過程:
通過starter添加Zuul的依賴時演顾,自身包含了spring-cloud-starter-hystrix與spring-cloud-starter-ribbon模塊的依賴供搀,因此Zuul自身就擁有線程隔離與斷路器的服務(wù)容錯功能,以及客戶端負載均衡钠至。但是葛虐,倘若我們使用path與url的映射關(guān)系來配置路由規(guī)則,則路由轉(zhuǎn)發(fā)的請求并不會采用HystrixCommand來包裝棉钧,因而這類路由是沒有服務(wù)容錯與客戶端負載均衡作用的屿脐。所以在使用Zuul時,應(yīng)盡量使用path和serviceId的組合對路由進行配置宪卿。
微服務(wù)技術(shù)是程序員繞不開的話題的诵,想要了解更多微服務(wù)架構(gòu)知識點的,可以關(guān)注我一下佑钾,我后續(xù)也會整理更多關(guān)于微服務(wù)架構(gòu)這一塊的知識點分享出來西疤,另外順便給大家推薦一個交流學(xué)習(xí)群:650385180,里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring休溶,MyBatis代赁,Netty源碼分析,高并發(fā)邮偎、高性能管跺、分布式、微服務(wù)架構(gòu)的原理禾进,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系豁跑。
分布式配置中心
為什么要引入一個分布式配置中心?一個微服務(wù)就需要至少一個配置文件泻云,怎么管理分散在各個微服務(wù)中的配置文件呢艇拍?如果微服務(wù)采用的是不同的技術(shù)棧,如何來統(tǒng)一微服務(wù)的配置呢宠纯?微服務(wù)是部署在不同的節(jié)點中卸夕,顯然我們無法在單機中實現(xiàn)對分布式節(jié)點的配置管理。這就是引入Spring Cloud Config的目的婆瓜。
Spring Cloud Config提供了服務(wù)端和客戶端支持快集。服務(wù)端是一個獨立的微服務(wù),同樣可以注冊到Eureka服務(wù)器中廉白。每個需要使用分布式配置中心的微服務(wù)都是Spring Cloud Config的客戶端个初。Spring Cloud Config默認實現(xiàn)基于Git倉庫,既可以進行版本管理猴蹂,還可以通過本地Git庫起到緩存作用院溺。Spring Cloud Config不限于基于Spring Cloud開發(fā)的系統(tǒng),而是可以用于任何語言開發(fā)的程序,并支持自定義實現(xiàn)顷啼。
配置中心服務(wù)端
Spring Cloud Config Server作為配置中心服務(wù)端,提供如下功能:
拉取配置時更新git倉庫副本锯厢,保證是最新結(jié)果
支持數(shù)據(jù)結(jié)構(gòu)豐富谆膳,yml, json, properties等
配合Eureke可實現(xiàn)服務(wù)發(fā)現(xiàn)叭爱,配合cloud bus可實現(xiàn)配置推送更新
配置存儲基于git倉庫,可進行版本管理
簡單可靠漱病,有豐富的配套方案
建立一個Config服務(wù)涤伐,需要添加如下依賴:
org.springframework.cloudspring-cloud-config-server
服務(wù)的Application類需要添加 @EnableConfigServer 注解:
@SpringBootApplication@EnableConfigServerpublic class ConfigApplication {publicstaticvoidmain(String[] args) {? ? ? ? SpringApplication.run(ConfigApplication.class, args);? ? }}
配置服務(wù)的基本信息和Git倉庫的信息放在application.yml文件中:
spring:? cloud:? ? config:? ? ? server:? ? ? ? git:? ? ? ? ? ? uri:http://localhost/workspace/springcloud-demo? ? ? ? ? ? username:user? ? ? ? ? ? password:passwordserver:? port:8888security:? user:? ? password:${CONFIG_SERVICE_PASSWORD}
Git庫與配置服務(wù)
在Config服務(wù)中配置了Git服務(wù)器以及Git庫的信息后,我們就可以在git庫中提交配置文件缨称。存儲在git庫中配置文件的名字以及分支名(默認為master分支)會組成訪問Config服務(wù)的URI。假設(shè)有一個服務(wù)為Notification服務(wù)祝迂,則它在配置中心服務(wù)端的配置文件為notification-dev.yml睦尽,內(nèi)容如下:
devMode:truespring:? ? application:? ? ? ? name:notification? ? jdbc:? ? ? ? host:localhost? ? ? ? port:3306? ? ? ? user:root? ? ? ? password:123456logging:? ? file:demo
配置中心客戶端
需要讀取配置中心服務(wù)端信息的微服務(wù)都是配置中心的客戶端,為了能夠讀取配置服務(wù)端的信息型雳,這些微服務(wù)需要:
在pom中添加對spring-cloud-starter-config的依賴
在bootstrap.properties或者bootstrap.yml中配置獲取配置的config-server位置
例如当凡,Account服務(wù)的配置是由Spring Cloud Config進行管理的。在它的資源目錄下纠俭,提供了bootstrap.yml配置文件沿量,內(nèi)容如下所示:
spring:? application:? ? name:account-service? cloud:? ? config:? ? ? uri:http://config:8888? ? ? fail-fast:true? ? ? password:${CONFIG_SERVICE_PASSWORD}? ? ? username:user
注意,該配置文件除了配置了該Account服務(wù)應(yīng)用的name之外冤荆,主要是支持該應(yīng)用獲得配置服務(wù)端的信息朴则。微服務(wù)自身的配置信息則統(tǒng)一放到配置中心服務(wù)端的文件中,并由Git庫進行管理钓简。例如乌妒,Account服務(wù)的詳細配置在配置中心服務(wù)端的account-dev.yml文件中:
security:? oauth2:? ? client:? ? ? clientId:account-service? ? ? clientSecret:${ACCOUNT_SERVICE_PASSWORD}? ? ? accessTokenUri:http://auth-service:5000/uaa/oauth/token? ? ? grant-type:client_credentials? ? ? scope:serverspring:? data:? ? mongodb:? ? ? host:account-mongodb? ? ? username:user? ? ? password:${MONGODB_PASSWORD}? ? ? database:piggymetrics? ? ? port:27017server:? context-path:/accounts? port:6000
Spring Cloud Config通過Git實現(xiàn)分布式的配置管理。當配置中心服務(wù)端的配置信息發(fā)生變更時外邓,各個作為配置客戶端的微服務(wù)會向Git庫提交pull更新撤蚊,獲得最新的配置信息。
當然损话,Spring Cloud Config還可以使用SVN庫進行配置管理侦啸,也支持簡單的本地文件系統(tǒng)的存儲方式。此時需要將 spring.profiles.active 設(shè)置為native丧枪,并設(shè)置搜索配置文件的路徑光涂。如果不配置路徑,默認在 src/main/resources 目錄下搜索豪诲。如下配置文件:
spring:cloud:config:server:native:search-locations:classpath:/sharedprofiles:active: native
搜索路徑放在classpath下的shared目錄下顶捷,那么在代碼中,目錄就是 resources/shared 屎篱。如果使用本地文件系統(tǒng)管理配置文件服赎,則無法支持分布式配置管理以及版本管理葵蒂,因此在生產(chǎn)系統(tǒng)下,還是推薦使用Git庫的方式重虑。
總結(jié)
在實施微服務(wù)時践付,我們可以將微服務(wù)視為兩個不同的邊界。一個是與前端UI的通信缺厉,稱為Open Service(Edge Service)永高,通過引入API Gateway來實現(xiàn)與前端UI的通信。另一個是在邊界內(nèi)業(yè)務(wù)微服務(wù)之間的通信提针,通過Feign實現(xiàn)微服務(wù)之間的協(xié)作命爬。所有的微服務(wù)都會通過Eureka來完成微服務(wù)的注冊與發(fā)現(xiàn)。一個典型的基于Spring Cloud的微服務(wù)架構(gòu)如下所示:
微服務(wù)的集成可以通過Feign+Ribbon以RESTful方式實現(xiàn)通信辐脖,也可以基于RPC方式(可以結(jié)合Protocol Buffer)完成服務(wù)之間的通信饲宛,甚至可以通過發(fā)布事件與訂閱事件的機制。事件機制可以使微服務(wù)之間更加松散耦合嗜价。這時艇抠,我們可以引入RabbitMQ或Kafka來做到服務(wù)與服務(wù)之間的解耦。事件機制是異步和非阻塞的久锥,在某些業(yè)務(wù)場景下家淤,它的性能會更加的好。Spring Cloud也提供了相關(guān)的組件Spring Cloud Stream來支持這種事件機制瑟由。
對于微服務(wù)之間的協(xié)作絮重,到底選擇Feign這種REST方式、事件機制或者RPC方式错妖,取決于業(yè)務(wù)場景是否需要同步方式绿鸣,還是異步方式;是高性能高并發(fā)暂氯,還是普通方式潮模;是要求徹底解耦,還是做到一般的松散耦合痴施。我們需要針對實際情況作出實際的判斷擎厢,作出正確的選擇。沒有誰壞誰好之分辣吃,而是看誰更加的適合动遭。