服務(wù)發(fā)現(xiàn)
什么是服務(wù)發(fā)現(xiàn)
在微服務(wù)架構(gòu)中沫换,整個系統(tǒng)會按職責能力劃分為多個服務(wù),通過服務(wù)之間協(xié)作來實現(xiàn)業(yè)務(wù)目標娩贷。這樣在我們的代碼 中免不了要進行服務(wù)間的遠程調(diào)用喉磁,服務(wù)的消費方要調(diào)用服務(wù)的生產(chǎn)方,為了完成一次請求涕癣,消費方需要知道服務(wù) 生產(chǎn)方的網(wǎng)絡(luò)位置(IP地址和端口號)哗蜈。
我們的代碼可以通過讀取配置文件的方式讀取服務(wù)生產(chǎn)方網(wǎng)絡(luò)位置,如下:
我們通過Spring boot技術(shù)很容易實現(xiàn):
創(chuàng)建一個spring-boot父工程
創(chuàng)建Service B(服務(wù)生產(chǎn)者)
pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.xu.nacos</groupId>
<artifactId>nacos-discovery</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-restful-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
Service B是服務(wù)的生產(chǎn)方属划,暴露/service服務(wù)地址恬叹,實現(xiàn)代碼如下:
1、創(chuàng)建Controller
@RestController
public class RestProviderController {
//暴露一個Restful接口
@GetMapping("/service")
public String service(){
return "provider invoke";
}
}
創(chuàng)建application.yml同眯,內(nèi)容如下:
server:
port:56010
創(chuàng)建Service A(服務(wù)消費者)
pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.xu.nacos</groupId>
<artifactId>nacos-discovery</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-restful-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
創(chuàng)建controller
@RestController
public class RestConsumerController {
@Value("${provider.address}")
private String provider;
@GetMapping("service")
public String service(){
//遠程調(diào)用
RestTemplate restTemplate = new RestTemplate();
String forObject = restTemplate.getForObject("http://" + provider + "service", String.class);
return "消費成功"+forObject;
}
}
配置文件
server:
port: 56020
#配置服務(wù)提供方的ip和端口
provider:
address: 127.0.0.1:56010
以上消費方找到服務(wù)方并進行遠程調(diào)用就叫服務(wù)發(fā)現(xiàn)
那么該如何來發(fā)現(xiàn)這些服務(wù)呢绽昼?服務(wù)方實例的增加對服務(wù)的發(fā)現(xiàn)會產(chǎn)生哪些問題呢?
服務(wù)發(fā)現(xiàn)流程
上邊的例子看上去很完美须蜗,但是硅确,仔細考慮以下目溉,此方案對于微服務(wù)應(yīng)用而言行不通。首先菱农,微服務(wù)可能是部署在 云環(huán)境的缭付,服務(wù)實例的網(wǎng)絡(luò)位置或許是動態(tài)分配的。另外循未,每一個服務(wù)一般會有多個實例來做負載均衡陷猫,由于宕機 或升級,服務(wù)實例網(wǎng)絡(luò)地址會經(jīng)常動態(tài)改變的妖。再者绣檬,每一個服務(wù)也可能應(yīng)對臨時訪問壓力增加新的服務(wù)節(jié)點。正如 下圖所示:
基于以上的問題嫂粟,服務(wù)之間如何相互發(fā)現(xiàn)娇未?服務(wù)如何管理?這就是服務(wù)發(fā)現(xiàn)的問題了星虹。 服務(wù)發(fā)現(xiàn)就是服務(wù)消費方通過服務(wù)發(fā)現(xiàn)中心智能發(fā)現(xiàn)服務(wù)提供方零抬,從而進行遠程調(diào)用的過程。 如下圖:
上圖中服務(wù)實例本身并不記錄服務(wù)生產(chǎn)方的網(wǎng)絡(luò)地址宽涌,所有服務(wù)實例內(nèi)部都會包含服務(wù)發(fā)現(xiàn)客戶端平夜。
(1)在每個服務(wù)啟動時會向服務(wù)發(fā)現(xiàn)中心上報自己的網(wǎng)絡(luò)位置。這樣护糖,在服務(wù)發(fā)現(xiàn)中心內(nèi)部會形成一個服務(wù)注冊 表褥芒,服務(wù)注冊表是服務(wù)發(fā)現(xiàn)的核心部分,是包含所有服務(wù)實例的網(wǎng)絡(luò)地址的數(shù)據(jù)庫嫡良。
(2)服務(wù)發(fā)現(xiàn)客戶端會定期從服務(wù)發(fā)現(xiàn)中心同步服務(wù)注冊表 锰扶,并緩存在客戶端。
(3)當需要對某服務(wù)進行請求時寝受,服務(wù)實例通過該注冊表坷牛,定位目標服務(wù)網(wǎng)絡(luò)地址。若目標服務(wù)存在多個網(wǎng)絡(luò)地 址很澄,則使用負載均衡算法從多個服務(wù)實例中選擇出一個京闰,然后發(fā)出請求。
總結(jié):
在微服務(wù)環(huán)境中甩苛,由于服務(wù)運行實例的網(wǎng)絡(luò)地址是不斷動態(tài)變化的蹂楣,服務(wù)實例數(shù)量的動態(tài)變化 ,因此無法 使用固定的配置文件來記錄服務(wù)提供方的網(wǎng)絡(luò)地址讯蒲,必須使用動態(tài)的服務(wù)發(fā)現(xiàn)機制用于實現(xiàn)微服務(wù)間的相互感知痊土。 各服務(wù)實例會上報自己的網(wǎng)絡(luò)地址,這樣服務(wù)中心就形成了一個完整的服務(wù)注冊表墨林,各服務(wù)實例會通過服務(wù)發(fā)現(xiàn)中 心來獲取訪問目標服務(wù)的網(wǎng)絡(luò)地址赁酝,從而實現(xiàn)服務(wù)發(fā)現(xiàn)的機制犯祠。