摘要:服務(wù)消費(fèi)者可以使用多種模型來(lái)發(fā)現(xiàn)服務(wù)??蛻?hù)端將定期與服務(wù)發(fā)現(xiàn)層進(jìn)行通信,并刷新服務(wù)實(shí)例的緩存。為了達(dá)成目的,我們將要學(xué)習(xí)使用個(gè)不同的客戶(hù)端庫(kù),服務(wù)消費(fèi)者可以使用它們來(lái)和進(jìn)行交互。
本篇代碼存放于:github
一、服務(wù)發(fā)現(xiàn)架構(gòu)??服務(wù)發(fā)現(xiàn)架構(gòu)通常具有下面 4 個(gè)概念:
服務(wù)注冊(cè):服務(wù)如何使用服務(wù)發(fā)現(xiàn)代理進(jìn)行注冊(cè)?
服務(wù)地址的客戶(hù)端查找:服務(wù)客戶(hù)端查找服務(wù)信息的方法是什么?
信息共享:如何跨節(jié)點(diǎn)共享服務(wù)信息?
健康監(jiān)測(cè):服務(wù)如何將它的健康信息傳回給服務(wù)發(fā)現(xiàn)代理?
下圖展示了這 4 個(gè)概念的流程,以及在服務(wù)發(fā)現(xiàn)模式實(shí)現(xiàn)中通常發(fā)生的情況:
??通常服務(wù)實(shí)例都只向一個(gè)服務(wù)發(fā)現(xiàn)實(shí)例注冊(cè),服務(wù)發(fā)現(xiàn)實(shí)例之間再通過(guò)數(shù)據(jù)傳輸,讓每個(gè)服務(wù)實(shí)例注冊(cè)到所有的服務(wù)發(fā)現(xiàn)實(shí)例中。
??服務(wù)在向服務(wù)發(fā)現(xiàn)實(shí)例注冊(cè)后,這個(gè)服務(wù)就能被服務(wù)消費(fèi)者調(diào)用了。服務(wù)消費(fèi)者可以使用多種模型來(lái)"發(fā)現(xiàn)"服務(wù)。
每次調(diào)用服務(wù)時(shí),通過(guò)服務(wù)發(fā)現(xiàn)層來(lái)獲取目標(biāo)服務(wù)地址并進(jìn)行調(diào)用。這種用的比較少,弊端較多。首先是每次服務(wù)調(diào)用都通過(guò)服務(wù)發(fā)現(xiàn)層來(lái)完成,耗時(shí)會(huì)比直接調(diào)用高。最主要的是這種方法很脆弱,消費(fèi)端完全依賴(lài)于服務(wù)發(fā)現(xiàn)層來(lái)查找和調(diào)用服務(wù)。
更健壯的方法是使用所謂的客戶(hù)端負(fù)載均衡。
??如下圖所示:
??在這個(gè)模型中,當(dāng)服務(wù)消費(fèi)者需要調(diào)用一個(gè)服務(wù)時(shí):
??(1)聯(lián)系服務(wù)發(fā)現(xiàn)層,獲取所請(qǐng)求服務(wù)的所有服務(wù)實(shí)例,然后放到本地緩存中。
??(2)每次調(diào)用該服務(wù)時(shí),服務(wù)消費(fèi)者從緩存中取出一個(gè)服務(wù)實(shí)例的位置,通常這個(gè)"取出"使用簡(jiǎn)單的復(fù)制均衡算法,如“輪詢(xún)”,“隨機(jī)",以確保服務(wù)調(diào)用分布在所有實(shí)例之間。
??(3)客戶(hù)端將定期與服務(wù)發(fā)現(xiàn)層進(jìn)行通信,并刷新服務(wù)實(shí)例的緩存。
??(4)如果在調(diào)用服務(wù)的過(guò)程中,服務(wù)調(diào)用失敗,那么本地緩存將從服務(wù)發(fā)現(xiàn)層中刷新數(shù)據(jù),再次嘗試。
二、spring cloud 實(shí)戰(zhàn)??使用 spring cloud 和 Netflix Eureka 搭建服務(wù)發(fā)現(xiàn)實(shí)例。
1、構(gòu)建 Spring Eureka 服務(wù)??eurekasvr POM 主要配置如下:
org.springframework.cloud spring-cloud-starter-eureka-server
??applicaiton.yml 配置如下:
server: port: 8761 eureka: client: #不注冊(cè)自己 register-with-eureka: false #不在本地緩存注冊(cè)表信息 fetch-registry: false server: #接受請(qǐng)求前的等待實(shí)際,開(kāi)發(fā)模式下不要開(kāi)啟 #wait-time-in-ms-when-sync-empty: 5
??最后在啟動(dòng)類(lèi)上加入注釋@SpringBootApplication即可啟動(dòng)服務(wù)中心。服務(wù)中心管理頁(yè)面:http://localhost:8761
2、將服務(wù)注冊(cè)到服務(wù)中心??這里我們編寫(xiě)一個(gè)新服務(wù)注冊(cè)到服務(wù)中心,organizationservice:組織服務(wù)。并將上一篇的兩個(gè)服務(wù):confsvr:配置中心服務(wù),licensingservice:授權(quán)服務(wù)注冊(cè)到服務(wù)中心。
a、confvr 注冊(cè)??首先修改 POM 文件:
org.springframework.cloud spring-cloud-config-server org.springframework.cloud spring-cloud-starter-eureka
??然后修改配置文件 application.yml:
server: port: 8888 eureka: instance: #注冊(cè)服務(wù)的IP,而不是服務(wù)器名 prefer-ip-address: true client: #向eureka注冊(cè)服務(wù) register-with-eureka: true #拉取注冊(cè)表的本地副本 fetch-registry: true service-url: #Eureka服務(wù)的位置(如果有多個(gè)注冊(cè)中心,使用,分隔) defaultZone: http://localhost:8761/eureka/ spring: profiles: # 使用文件系統(tǒng)來(lái)存儲(chǔ)配置信息,需要設(shè)置為native active: native application: name: confsvr cloud: config: server: native: # 使用文件來(lái)存放配置文件,為每個(gè)應(yīng)用程序提供用逗號(hào)分隔的文件夾列表 searchLocations: file:///D:/configFolder/licensingservice,file:///D:/configFolder/organizationservice
??最后在啟動(dòng)類(lèi)加入注解@EnableDiscoveryClient,啟動(dòng)即可在 eureka 管理頁(yè)面發(fā)現(xiàn)。
b、licensingservice 注冊(cè)??首先修改 POM
org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-config-client
??然后修改配置文件 bootstrap.yml
spring: application: #指定名稱(chēng),以便spring cloud config客戶(hù)端知道查找哪個(gè)配置 name: licensingservice profiles: #指定環(huán)境 active: dev cloud: config: #設(shè)為true便會(huì)自動(dòng)獲取從配置中心獲取配置文件 enabled: true eureka: instance: prefer-ip-address: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8761/eureka/
??最后在啟動(dòng)類(lèi)加入注解@EnableDiscoveryClient,啟動(dòng)即可在 eureka 管理頁(yè)面發(fā)現(xiàn)本服務(wù)實(shí)例。
c、創(chuàng)建 organizationservice??首先在文件夾file:///D:/configFolder/organizationservice下創(chuàng)建兩個(gè)配置文件:organizationservice.yml,organizationservice-dev.yml,內(nèi)容分別為:
#organizationservice-dev.yml server: port: 10012
#organizationservice.yml spring: application: name: organizationservice
??主要 POM 配置如下:
org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-config-client
??然后修改配置文件,bootstrap.yml
spring: application: #指定名稱(chēng),以便spring cloud config客戶(hù)端知道查找哪個(gè)配置 name: organizationservice profiles: #指定環(huán)境 active: dev cloud: config: enabled: true eureka: instance: prefer-ip-address: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8761/eureka/
??最后在啟動(dòng)類(lèi)加入注解@EnableDiscoveryClient,啟動(dòng)。
3、使用服務(wù)發(fā)現(xiàn)來(lái)查找服務(wù)??現(xiàn)在已經(jīng)有兩個(gè)注冊(cè)服務(wù)了,現(xiàn)在來(lái)讓許可證服務(wù)調(diào)用組織服務(wù),獲取組織信息。首先在 organizationservice 服務(wù)中的 controller 包中加入一個(gè) controller 類(lèi),讓它能夠響應(yīng)請(qǐng)求:
//OrganizationController.java @RestController public class OrganizationController { @GetMapping(value = "/organization/{orgId}") public Object getOrganizationInfo(@PathVariable("orgId") String orgId) { Mapdata = new HashMap<>(2); data.put("id", orgId); data.put("name", orgId + "公司"); return data; } }
??接下來(lái)讓許可證服務(wù)通過(guò) Eureka 來(lái)找到組織服務(wù)的實(shí)際位置,然后調(diào)用該接口。為了達(dá)成目的,我們將要學(xué)習(xí)使用 3 個(gè)不同的 Spring/Netflix 客戶(hù)端庫(kù),服務(wù)消費(fèi)者可以使用它們來(lái)和 Ribbon 進(jìn)行交互。從最低級(jí)別到最高級(jí)別,這些庫(kù)包含了不同的與 Ribbon 進(jìn)行交互的抽象封裝層次:
Spring DiscoveryClient
啟用了 RestTemplate 的 Spring DiscoveryClient
Neflix Feign 客戶(hù)端
a、使用 Spring DiscoveryClient??該工具提供了對(duì) Ribbon 和 Ribbon 中緩存的注冊(cè)服務(wù)最低層次的訪(fǎng)問(wèn),可以查詢(xún)通過(guò) Eureka 注冊(cè)的所有服務(wù)以及這些服務(wù)對(duì)應(yīng)的 URL。
??首先在 licensingservice 的啟動(dòng)類(lèi)中加入@EnableDiscoveryClient注解來(lái)啟用 DiscoveryClient 和 Ribbon 庫(kù)。
??然后在 service 包下創(chuàng)建 OrganizationService.java
@Service public class OrganizationService { private static final String SERVICE_NAME = "organizationservice"; private DiscoveryClient discoveryClient; @Autowired public OrganizationService(DiscoveryClient discoveryClient) { this.discoveryClient = discoveryClient; } /** * 使用Spring DiscoveryClient查詢(xún) * * @param id * @return */ public Organization getOrganization(String id) { RestTemplate restTemplate = new RestTemplate(); Listinstances = discoveryClient.getInstances(SERVICE_NAME); if (instances.size() == 0) { throw new RuntimeException("無(wú)可用的服務(wù)"); } String serviceUri = String.format("%s/organization/%s", instances.get(0).getUri().toString(), id); ResponseEntity responseEntity = restTemplate.exchange(serviceUri, HttpMethod.GET , null, Organization.class, id); return responseEntity.getBody(); } }
??接著在 controller 包中新建 LicensingController.java
@RestController public class LicensingController { private OrganizationService organizationService; @Autowired public LicensingController(OrganizationService organizationService) { this.organizationService = organizationService; } @GetMapping("/licensing/{orgId}") public Licensing getLicensing(@PathVariable("orgId") String orgId) { Licensing licensing = new Licensing(); licensing.setValid(false); licensing.setOrganization(organizationService.getOrganization(orgId)); return licensing; } }
??啟動(dòng)所有項(xiàng)目,訪(fǎng)問(wèn)localhost:10011/licensing/12,可以看到返回如下結(jié)果:
{ "organization": { "id": "12", "name": "12公司" }, "valid": false }
??在實(shí)際開(kāi)發(fā)中,基本上是用不到這個(gè)的,除非是為了查詢(xún) Ribbon 以獲取某個(gè)服務(wù)的所有實(shí)例信息,才會(huì)直接使用。如果直接使用它存在以下兩個(gè)問(wèn)題:
沒(méi)有利用 Ribbon 的客戶(hù)端負(fù)載均衡
和業(yè)務(wù)無(wú)關(guān)的代碼寫(xiě)得太多
b、使用帶 Ribbon 功能的 Spring RestTemplate 調(diào)用服務(wù)??這種方法是較為常用的微服務(wù)通信機(jī)制之一。要啟動(dòng)該功能,需要使用 Spring Cloud 注解@LoadBanced 來(lái)定義 RestTemplate bean 的構(gòu)造方法。方便起見(jiàn)直接在啟動(dòng)類(lèi)中定義 bean:
#LicensingserviceApplication.java @SpringBootApplication @EnableDiscoveryClient //使用不帶Ribbon功能的Spring RestTemplate,其他情況下可刪除 public class LicensingserviceApplication { /** * 使用帶有Ribbon 功能的Spring RestTemplate,其他情況可刪除 */ @LoadBalanced @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(LicensingserviceApplication.class, args); } }
??接著 service 包下增加一個(gè)類(lèi):OrganizationByRibbonService.java
@Component public class OrganizationByRibbonService { private RestTemplate restTemplate; @Autowired public OrganizationByRibbonService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } public Organization getOrganizationWithRibbon(String id) { ResponseEntityresponseEntity = restTemplate.exchange("http://organizationservice/organization/{id}", HttpMethod.GET, null, Organization.class, id); return responseEntity.getBody(); } }
??最后就是在 LicensingController.js 中加一個(gè)訪(fǎng)問(wèn)路徑:
//不要忘記注入OrganizationByRibbonService服務(wù) @GetMapping("/licensingByRibbon/{orgId}") public Licensing getLicensingByRibbon(@PathVariable("orgId") String orgId) { Licensing licensing = new Licensing(); licensing.setValid(false); licensing.setOrganization(organizationService.getOrganization(orgId)); return licensing; } }
??訪(fǎng)問(wèn)localhost:10011/licensingByRibbon/113,即可看到結(jié)果。
c、使用 Netflix Feign 客戶(hù)端調(diào)用??Feign 客戶(hù)端是 Spring 啟用 Ribbon 的 RestTemplate 類(lèi)的替代方案。開(kāi)發(fā)人員只需定義一個(gè)接口,然后使用 Spring 注解來(lái)標(biāo)注接口,即可調(diào)用目標(biāo)服務(wù)。除了編寫(xiě)接口定義無(wú)需編寫(xiě)其他輔助代碼。
??首先啟動(dòng)類(lèi)上加一個(gè)@EnableFeignClients注解啟用 feign 客戶(hù)端。然后在 POM 中加入 Feign 的依賴(lài)
org.springframework.cloud spring-cloud-starter-feign
??然后在 client 包下新建 OrganizationFeignClient.java
@FeignClient("organizationservice")//使用FeignClient注解指定目標(biāo)服務(wù) public interface OrganizationFeignClient { /** * 獲取組織信息 * * @param orgId 組織id * @return Organization */ @RequestMapping(method = RequestMethod.GET, value = "/organization/{orgId}", consumes = "application/json") Organization getOrganization(@PathVariable("orgId") String orgId); }
??最后修改LicensingController.java,加入一個(gè)路由調(diào)用 Feign。
//注入OrganizationFeignClient,使用構(gòu)造注入 @GetMapping("/licensingByFeign/{orgId}") public Licensing getLicensingByFeign(@PathVariable("orgId") String orgId) { Licensing licensing = new Licensing(); licensing.setValid(false); licensing.setOrganization(organizationFeignClient.getOrganization(orgId)); return licensing; }
訪(fǎng)問(wèn)localhost:10011/licensingByFeign/11313,即可看到結(jié)果。
總結(jié)??這一節(jié)磨磨蹭蹭寫(xiě)了好幾天,雖然例子很簡(jiǎn)單,但是相信應(yīng)該是能夠看懂的。由于篇幅原因代碼沒(méi)有全部貼上,想要查看完整代碼,可以訪(fǎng)問(wèn)這個(gè)鏈接:點(diǎn)擊跳轉(zhuǎn)。
本篇原創(chuàng)發(fā)布于:http://tapme.top/blog/detail/2018-11-22-15-57
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77735.html
摘要:實(shí)現(xiàn)配置和注冊(cè)中心最近,阿里開(kāi)源的比較火,可以和和共用,對(duì)升級(jí)到非常的方便。只需要添加依賴(lài),使用配置注冊(cè)中心地址即可。配置不生效,沒(méi)有使用注解刷新配置分清注冊(cè)中心和配置中心是兩個(gè)概念,需要配置兩個(gè)地址學(xué)會(huì)看源碼,看維基。 Springcloud-nacos實(shí)現(xiàn)配置和注冊(cè)中心 最近,阿里開(kāi)源的nacos比較火,可以和springcloud和dubbo共用,對(duì)dubbo升級(jí)到springc...
摘要:集群系統(tǒng)中的單個(gè)計(jì)算機(jī)通常稱(chēng)為節(jié)點(diǎn),通常通過(guò)局域網(wǎng)連接,但也有其它的可能連接方式。這樣就高興了,可以專(zhuān)心寫(xiě)自己的,前端就專(zhuān)門(mén)交由小周負(fù)責(zé)了。于是,小周和就變成了協(xié)作開(kāi)發(fā)。都是為了項(xiàng)目正常運(yùn)行以及迭代。 一、前言 只有光頭才能變強(qiáng) 認(rèn)識(shí)我的朋友可能都知道我這陣子去實(shí)習(xí)啦,去的公司說(shuō)是用SpringCloud(但我覺(jué)得使用的力度并不大啊~~)... 所以,這篇主要來(lái)講講SpringClou...
摘要:集群系統(tǒng)中的單個(gè)計(jì)算機(jī)通常稱(chēng)為節(jié)點(diǎn),通常通過(guò)局域網(wǎng)連接,但也有其它的可能連接方式。這樣就高興了,可以專(zhuān)心寫(xiě)自己的,前端就專(zhuān)門(mén)交由小周負(fù)責(zé)了。于是,小周和就變成了協(xié)作開(kāi)發(fā)。都是為了項(xiàng)目正常運(yùn)行以及迭代。 一、前言 只有光頭才能變強(qiáng) 認(rèn)識(shí)我的朋友可能都知道我這陣子去實(shí)習(xí)啦,去的公司說(shuō)是用SpringCloud(但我覺(jué)得使用的力度并不大啊~~)... 所以,這篇主要來(lái)講講SpringClou...
閱讀 1413·2021-09-22 10:02
閱讀 1992·2021-09-08 09:35
閱讀 4097·2021-08-12 13:29
閱讀 2639·2019-08-30 15:55
閱讀 2289·2019-08-30 15:53
閱讀 2330·2019-08-29 17:13
閱讀 2786·2019-08-29 16:31
閱讀 2978·2019-08-29 12:24