什么是服務發現
在微服務架構中,整個系統會按職責能力划分為多個服務,通過服務之間協作來實現業務目標。這樣在我們的代碼
中免不了要進行服務間的遠程調用,服務的消費方要調用服務的生產方,為了完成一次請求,消費方需要知道服務
生產方的網絡位置(IP地址和端口號)。
我們的代碼可以通過讀取配置文件的方式讀取服務生產方網絡位置,如下:
看上去很完美,但是,仔細考慮以下,此方案對於微服務應用而言行不通。
首先,微服務可能是部署在雲環境的,服務實例的網絡位置或許是動態分配的。另外,每一個服務一般會有多個實
例來做負載均衡,由於宕機或升級,服務實例網絡地址會經常動態改變。再者,每一個服務也可能應對臨時訪問壓
力增加新的服務節點。正如下圖所示:
基於以上的問題,服務之間如何相互感知?服務如何管理?這就是服務發現的問題了。如下圖:
上圖中服務實例本身並不記錄服務生產方的網絡地址,所有服務實例內部都會包含服務發現客戶端。
(1)在每個服務啟動時會向服務發現中心上報自己的網絡位置。這樣,在服務發現中心內部會形成一個服務注冊表,服務注冊表是服務發現的核心部分,是包含所有服務實例的網絡地址的數據庫。
(2)服務發現客戶端會定期從服務發現中心同步服務注冊表 ,並緩存在客戶端。
(3)當需要對某服務進行請求時,服務實例通過該注冊表,定位目標服務網絡地址。若目標服務存在多個網絡地
址,則使用負載均衡算法從多個服務實例中選擇出一個,然后發出請求。
總結一下,在微服務環境中,由於服務運行實例的網絡地址是不斷動態變化的,服務實例數量的動態變化 ,因此無
法使用固定的配置文件來記錄服務提供方的網絡地址,必須使用動態的服務發現機制用於實現微服務間的相互感
知。各服務實例會上報自己的網絡地址,這樣服務中心就形成了一個完整的服務注冊表,各服務實例會通過服務發
現中心來獲取訪問目標服務的網絡地址,從而實現服務發現的機制。
主流服務發現與配置中心對比
目前市面上用的比較多的服務發現中心有:Nacos、Eureka、Consul和Zookeeper。
對比項目 | Nacos | Eureka | Consul | Zookeeper |
一致性協議 | 支持AP和CP模型 | AP模型 | CP模型 | CP模型 |
健康檢查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | Keep Alive |
負載均衡策略 | 權重/metadata/Selector | Ribbon | Fabio | - |
雪崩保護 | 有 | 有 | 無 | 無 |
自動注銷實例 | 支持 | 支持 | 不支持 | 支持 |
訪問協議 | HTTP/DNS | HTTP | HTTP/DNS | TCP |
監聽支持 | 支持 | 支持 | 支持 | 支持 |
多數據中心 | 支持 | 支持 | 支持 | 不支持 |
跨注冊中心同步 | 支持 | 不支持 | 支持 | 不支持 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 支持 |
k8s集成 | 支持 | 不支持 | 支持 | 不支持 |
從上面對比可以了解到,Nacos作為服務發現中心,具備更多的功能支持項,且從長遠來看Nacos在以后的版本會
支持SpringCLoud+Kubernetes的組合,填補 2 者的鴻溝,在兩套體系下可以采用同一套服務發現和配置管理的解
決方案,這將大大的簡化使用和維護的成本。另外,Nacos 計划實現 Service Mesh,也是未來微服務發展的趨勢
Nacos的服務發現
Nacos主要提供以下四大功能:
1. 服務發現與服務健康檢查
- Nacos使服務更容易注冊,並通過DNS或HTTP接口發現其他服務,Nacos還提供服務的實時健康檢查,以防止向不健康的主機或服務實例發送請求。
2. 動態配置管理
- 動態配置服務允許您在所有環境中以集中和動態的方式管理所有服務的配置。Nacos消除了在更新配置時重新部署應用程序,這使配置的更改更加高效和靈活。
3 . 動態DNS服務
- Nacos提供基於DNS 協議的服務發現能力,旨在支持異構語言的服務發現,支持將注冊在Nacos上的服務以域名的方式暴露端點,讓三方應用方便的查閱及發現。
4. 服務和元數據管理
- Nacos 能讓您從微服務平台建設的視角管理數據中心的所有服務及元數據,包括管理服務的描述、生命周期、服務的靜態依賴分析、服務的健康狀態、服務的流量管理、路由及安全策略。
這里1、3、4說明了服務發現的功能特性。
父項目
<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
生產者:
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
配置文件
server:
port: ${port:56010} #啟動端口
spring:
application:
name: quickstart-provider
cloud:
nacos:
discovery:
server-addr: xxxxx:8848
logging:
level:
root: info
org.springframework: info
web層
@RestController public class ProviderController { private static final Logger LOG = LoggerFactory.getLogger(ProviderController.class); @GetMapping("/service") public String service(){ LOG.info("provider invoke"); return "provider invoke"; } }
啟動類
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class NacosProviderApp { public static void main(String[] args) { SpringApplication.run(NacosProviderApp.class,args); } }
消費
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
Feign的調用
@FeignClient(value = "quickstart-provider") public interface ProviderClient { @GetMapping("/service") public String service(); }
配置類:
server: port: 56020 #啟動端口 命令行注入 spring: application: name: quickstart-consumer cloud: nacos: discovery: server-addr: xxxxxx:8848
web層
@RestController public class ConsumerController { //動態代理對象,內部遠程調用服務生產者 @Autowired ProviderClient providerClient; @GetMapping("/service") public String service(){ //遠程調用 String providerResult = providerClient.service(); return "consumer invoke" + "|" + providerResult; } }
然后開啟服務
查看注冊中心:
進行調用,發現由於fegin在,所以會有輪詢的效果