搭建和配置一個服務(wù)提供者
我們知道,SpringCloud構(gòu)建微服務(wù)是基于SpringBoot開發(fā)的。
1、 創(chuàng)建一個SpringBoot工程,并且添加SpringBoot的相關(guān)依賴;
2、 創(chuàng)建服務(wù)提供者的訪問方法,也就是后續(xù)消費(fèi)者如何訪問提供者;
Spring Cloud是基于rest的訪問,所以我們添加一個Controller,在該Controller中提供一個訪問入口:
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "Hello Spring Cloud";
}
}
3、 啟動運(yùn)行該SpringBoot程序,訪問該controller;
服務(wù)消費(fèi)者也是一個SpringBoot項(xiàng)目,服務(wù)消費(fèi)者主要用來消費(fèi)服務(wù)提供者提供的服務(wù);
1、 創(chuàng)建一個SpringBoot工程,并且添加SpringBoot的相關(guān)依賴;
2、開發(fā)一個消費(fèi)者方法,去消費(fèi)服務(wù)提供者提供的服務(wù),這個消費(fèi)者方法也是一個Controller:
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value="/cloud/hello")
public String helloController() {
return restTemplate.getForEntity("http://localhost:9100/hello", String.class).getBody();
}
}
3、啟動該SpringBoot程序,測試服務(wù)消費(fèi)者調(diào)用服務(wù)提供者;
在微服務(wù)架構(gòu)中,服務(wù)注冊與發(fā)現(xiàn)是核心組件之一,手動指定每個服務(wù)是很低效的,Spring Cloud提供了多種服務(wù)注冊與發(fā)現(xiàn)的實(shí)現(xiàn)方式,例如:Eureka、Consul、Zookeeper。
Spring Cloud支持得最好的是Eureka,其次是Consul,再次是Zookeeper。
服務(wù)注冊:將服務(wù)所在主機(jī)、端口、版本號、通信協(xié)議等信息登記到注冊中心上;
服務(wù)發(fā)現(xiàn):服務(wù)消費(fèi)者向注冊中心請求已經(jīng)登記的服務(wù)列表,然后得到某個服務(wù)的主機(jī)、端口、版本號、通信協(xié)議等信息,從而實(shí)現(xiàn)對具體服務(wù)的調(diào)用;
Eureka是一個服務(wù)治理組件,它主要包括服務(wù)注冊和服務(wù)發(fā)現(xiàn),主要用來搭建服務(wù)注冊中心。
Eureka 是一個基于 REST 的服務(wù),用來定位服務(wù),進(jìn)行中間層服務(wù)器的負(fù)載均衡和故障轉(zhuǎn)移;
Eureka是Netflix 公司開發(fā)的,Spring Cloud 封裝了 Netflix 公司開發(fā)的 Eureka 模塊來實(shí)現(xiàn)服務(wù)注冊和發(fā)現(xiàn),也就是說Spring Cloud對Netflix Eureka 做了二次封裝;
Eureka 采用了C-S(客戶端/服務(wù)端)的設(shè)計架構(gòu),也就是Eureka由兩個組件組成:Eureka服務(wù)端和Eureka客戶端。Eureka Server 作為服務(wù)注冊的服務(wù)端,它是服務(wù)注冊中心,而系統(tǒng)中的其他微服務(wù),使用 Eureka 的客戶端連接到 Eureka Server服務(wù)端,并維持心跳連接,Eureka客戶端是一個Java客戶端,用來簡化與服務(wù)器的交互、負(fù)載均衡,服務(wù)的故障切換等;
有了Eureka注冊中心,系統(tǒng)的維護(hù)人員就可以通過 Eureka Server 來監(jiān)控系統(tǒng)中各個微服務(wù)是否正常運(yùn)行。
著名的CAP理論指出,一個分布式系統(tǒng)不可能同時滿足C(一致性)、A(可用性)和P(分區(qū)容錯性)。
由于分區(qū)容錯性在是分布式系統(tǒng)中必須要保證的,因此我們只能在A和C之間進(jìn)行權(quán)衡,在此Zookeeper保證的是CP, 而Eureka則是AP。
在ZooKeeper中,當(dāng)master節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與其他節(jié)點(diǎn)失去聯(lián)系時,剩余節(jié)點(diǎn)會重新進(jìn)行l(wèi)eader選舉,但是問題在于,選舉leader需要一定時間, 且選舉期間整個ZooKeeper集群都是不可用的,這就導(dǎo)致在選舉期間注冊服務(wù)癱瘓。在云部署的環(huán)境下,因網(wǎng)絡(luò)問題使得ZooKeeper集群失去master節(jié)點(diǎn)是大概率事件,雖然服務(wù)最終能夠恢復(fù),但是在選舉時間內(nèi)導(dǎo)致服務(wù)注冊長期不可用是難以容忍的。
Eureka優(yōu)先保證可用性,Eureka各個節(jié)點(diǎn)是平等的,某幾個節(jié)點(diǎn)掛掉不會影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊和查詢服務(wù)。而Eureka的客戶端在向某個Eureka注冊或時如果發(fā)現(xiàn)連接失敗,則會自動切換至其它節(jié)點(diǎn),只要有一臺Eureka還在,就能保證注冊服務(wù)可用(保證可用性),只不過查到的信息可能不是最新的(不保證強(qiáng)一致性)。
所以Eureka在網(wǎng)絡(luò)故障導(dǎo)致部分節(jié)點(diǎn)失去聯(lián)系的情況下,只要有一個節(jié)點(diǎn)可用,那么注冊和查詢服務(wù)就可以正常使用,而不會像zookeeper那樣使整個注冊服務(wù)癱瘓,Eureka優(yōu)先保證了可用性。
Spring Cloud要使用Eureka注冊中心非常簡單和方便,Spring Cloud中的Eureka服務(wù)注冊中心實(shí)際上也是一個Spring Boot工程,我們只需通過引入相關(guān)依賴和注解配置就能讓Spring Boot構(gòu)建的微服務(wù)應(yīng)用輕松地與Eureka進(jìn)行整合。
具體步驟如下:
1、 創(chuàng)建一個SpringBoot項(xiàng)目,并且添加SpringBoot的相關(guān)依賴;
03-springcloud-eureka-server
2、 添加eureka的依賴:
<!--Spring Cloud的eureka-server起步依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3、 在Spring Boot的入口類上添加一個@EnableEurekaServer注解,用于
開啟Eureka注冊中心服務(wù)端
4、 在application.properties文件中配置Eureka服務(wù)注冊中心信息:
#內(nèi)嵌定時tomcat的端口
server.port=8761
#設(shè)置該服務(wù)注冊中心的hostname
eureka.instance.hostname=localhost
#由于我們目前創(chuàng)建的應(yīng)用是一個服務(wù)注冊中心,而不是普通的應(yīng)用,默認(rèn)情況下,這個應(yīng)用會向注冊中心(也是它自己)注冊它自己,設(shè)置為false表示禁止這種自己向自己注冊的默認(rèn)行為
eureka.client.register-with-eureka=false
#表示不去檢索其他的服務(wù),因?yàn)榉?wù)注冊中心本身的職責(zé)就是維護(hù)服務(wù)實(shí)例,它不需要去檢索其他服務(wù)
eureka.client.fetch-registry=false
#指定服務(wù)注冊中心的位置
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
啟動與測試Eureka服務(wù)注冊中心
1、完成上面的項(xiàng)目搭建后,我們就可以啟動SpringBoot程序,main方法運(yùn)行;
2、啟動成功之后,通過在瀏覽器地址欄訪問我們的注冊中心;
我們前面搭建了服務(wù)提供者項(xiàng)目,接下來我們就可以將該服務(wù)提供者注冊到Eureke注冊中心,步驟如下:
1、在該服務(wù)提供者中添加eureka的依賴,因?yàn)榉?wù)提供者向注冊中心注冊服務(wù),需要連接eureka,所以需要eureka客戶端的支持;
<!--SpringCloud集成eureka客戶端的起步依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、激活Eureka中的EnableEurekaClient功能:
在Spring Boot的入口函數(shù)處,通過添加@EnableEurekaClient注解來表明自己是一個eureka客戶端,讓我的服務(wù)提供者可以連接eureka注冊中心;
3、配置服務(wù)名稱和注冊中心地址
spring.application.name=02-springcloud-service-provider
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4、啟動服務(wù)提供者SpringBoot程序的main方法運(yùn)行;
5、啟動運(yùn)行之后,通過在瀏覽器地址欄訪問我們之前搭建好的eureka注冊中心,就可以看到有一個服務(wù)已經(jīng)注冊成功了;
我們已經(jīng)搭建一個服務(wù)注冊中心,同時也向這個服務(wù)注冊中心注冊了服務(wù),接下來我們就可以發(fā)現(xiàn)和消費(fèi)服務(wù)了,這其中服務(wù)的發(fā)現(xiàn)由eureka客戶端實(shí)現(xiàn),而服務(wù)的消費(fèi)由Ribbon實(shí)現(xiàn),也就是說服務(wù)的調(diào)用需要eureka客戶端和Ribbon兩者配合起來才能實(shí)現(xiàn);
Eureka客戶端是一個Java客戶端,用來連接Eureka服務(wù)端,與服務(wù)端進(jìn)行交互、負(fù)載均衡,服務(wù)的故障切換等;
Ribbon是一個基于HTTP 和 TCP 的客戶端負(fù)載均衡器,當(dāng)使用Ribbon對服務(wù)進(jìn)行訪問的時候,它會擴(kuò)展Eureka客戶端的服務(wù)發(fā)現(xiàn)功能,實(shí)現(xiàn)從Eureka注冊中心中獲取服務(wù)端列表,并通過Eureka客戶端來確定服務(wù)端是否己經(jīng)啟動。Ribbon在Eureka客戶端服務(wù)發(fā)現(xiàn)的基礎(chǔ)上,實(shí)現(xiàn)了對服務(wù)實(shí)例的選擇策略,從而實(shí)現(xiàn)對服務(wù)的負(fù)載均衡消費(fèi)。
接下來我們來讓服務(wù)消費(fèi)者去消費(fèi)服務(wù):
我們前面搭建了服務(wù)消費(fèi)者項(xiàng)目,接下來我們就可以使用該服務(wù)消費(fèi)者通過注冊中心去調(diào)用服務(wù)提供者,步驟如下:
1、在該消費(fèi)者項(xiàng)目中添加eureka的依賴,因?yàn)榉?wù)消費(fèi)者從注冊中心獲取服務(wù),需要連接eureka,所以需要eureka客戶端的支持;
<!--SpringCloud集成eureka客戶端的起步依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、激活Eureka中的EnableEurekaClient功能:
在Spring Boot的入口函數(shù)處,通過添加@EnableEurekaClient注解來表明自己是一個eureka客戶端,讓我的服務(wù)消費(fèi)者可以使用eureka注冊中心;
3、配置服務(wù)的名稱和注冊中心的地址:
spring.application.name=03-springcloud-web-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4、前面我介紹了服務(wù)的發(fā)現(xiàn)由eureka客戶端實(shí)現(xiàn),而服務(wù)的真正調(diào)用由ribbon實(shí)現(xiàn),所以我們需要在調(diào)用服務(wù)提供者時使用ribbon來調(diào)用:
@LoadBalanced
@Bean
public RestTemplate restTemplate () {
return new RestTemplate();
}
加入了ribbon的支持,那么在調(diào)用時,即可改為使用服務(wù)名稱來訪問:
restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/cloud/hello", String.class).getBody();
5、完成上面的步驟后,我們就可以啟動消費(fèi)者的SpringBoot程序,main方法運(yùn)行;
6、啟動成功之后,通過在瀏覽器地址欄訪問我們的消費(fèi)者,看是否可以正常調(diào)用遠(yuǎn)程服務(wù)提供者提供的服務(wù);