在遠程調用的時候,我們寫的url是寫死的。
String url = "<http://127.0.0.1:9090/product/>"+ orderInfo.getProductId();
當換個機器,或者新增個機器,導致ip變換,從而使得 url 發生了變化,接著就需要去通知所有的相關業務也跟著去改變,這就導致后期非常麻煩。
解決思路:
使用注冊中心
什么是注冊中心
注冊中心是分布式系統/微服務架構中的核心基礎設施,它扮演著服務治理的"電話簿"角色,他能維護一個服務列表,哪個機器上線了,哪個機器宕機了,這些信息都會自動更新到服務列表上,客戶端拿到這個列表,直接進行服務調用即可。這個就是注冊中心。 注冊中心主要有三個角色:
- **服務提供者(Server):**一次業務中,被其他微服務調用的服務,也就是提供接口給其他微服務。
- **服務消費者(Client):**一次業務中,調用其他微服務的服務,也就是調用其他微服務提供的接口。
- **服務注冊中心(Register):**用于保存Server的注冊信息,當Server節點發生變更時,Register會同步變更。服務和注冊中心使用一定的通信機制,如果注冊中心與某服務長時間無法通信,就會注銷該實例。
注:服務提供者和服務消費者是相對的。
他們之間的關系及工作內容,可以通過兩個概念來描述:
- **服務注冊:**服務提供者在啟動時,向Register注冊自身服務,并向Register定期發送心跳匯報存活狀態。
- **服務發現:**服務消費者從注冊中心查詢服務提供者的地址,并通過該地址調用服務提供者的接口,服務發現的一個重要作用就是提供給消費者一個可用的服務列表。
CAP理論:分布式系統的基石
CAP 理論是分布式系統設計的核心定理,由計算機科學家 Eric Brewer 于 2000 年提出,揭示了分布式系統必然面臨的三元悖論。其核心內容可概括為:
任何分布式系統最多只能同時滿足以下三項中的兩項:
Consistency(一致性)
Availability(可用性)
Partition tolerance(分區容錯性)
注:一致性分為強一致性(主庫和從庫,不論何時,對外提供的服務都是一致的)和弱一致性(隨著時間的推移,最終達到了一致性),這里指的是強一致性。
比如說我有一個數據庫集群,客戶端向數據庫集群發送了一個數據修改的請求,數據庫集群需要向客戶端進行響應,響應的時機分為以下兩種:
- 主庫接收到請求,并處理成功,此時數據庫還未完全同步到從庫,隨著時間的推移,主庫和從庫的數據,最終會達到一個一致性。
- 主庫接收到請求,并且所有數據庫同步成功時,才返回響應。
CAP三要素:
要素 | 含義 | 典型場景 |
---|---|---|
C:一致性(Consistency) | 所有節點在同一時刻看到的數據完全相同(強一致性) | 銀行轉賬系統:A 轉 B 100元后,所有節點必須立即看到更新 |
A:可用性(Availability) | 每個請求都能獲得非錯誤響應(系統始終可操作) | 電商網站:雙十一高峰期間必須保證用戶能正常下單 |
P:分區容錯性(Partition Tolerance) | 網絡分區發生時系統仍能繼續運行(容忍網絡故障) | 跨數據中心部署:當機房之間網絡中斷時,系統仍能提供服務 |
CAP理論告訴我們:一個分布式系統不可能同時滿足數據一致性,服務可用性和分區容錯性這是三個基本需求,最多只能同時滿足其中的兩個。
在分布式系統中,系統間的網絡不能100%保證健康,服務又必須對外保證服務,因此PartitionTolerance不可避免,那就只能在C和A中選擇一個,也就是CP或者AP架構。
正常情況:
異常情況:
CP架構:為了保證分布式系統對外的數據一致性,于是選擇不返回任何數據。
AP架構:為了保證分布式系統的可用性,節點2返回V0版本的數據(即使這個數據不正確)
更多參考:一文看懂|分布式系統之CAP理論-騰訊云開發者社區-騰訊云
常見的注冊中心有:
- Zookeeper(CP)
- nacos(CP或AP,默認是AP)
- eureka(AP)
Eureka介紹
Eureka是Netflix OSS套件中關于服務注冊和發現的解決?案. Spring Cloud對Eureka進?了集成, 并
作為優先推薦?案進?宣傳, 雖然?前Eureka 2.0已經停?維護, 新的微服務架構設計中, 也不再建議使
?, 但是?前依然有?量公司的微服務系統使?Eureka作為注冊中?。
官方文檔:https://github.com/Netflix/eureka/wiki
Eureka主要分為兩個部分:
- Eureka Server:作為注冊中心Server端,向微服務應用程序提供服務注冊,發現健康檢查等能力。
- Eureka Client:服務提供者,服務啟動時,會向Eureka Server 注冊自己的信息(IP,端口,服務信息等),Eureka Server會存儲這些信息。
搭建注冊中心
1.創建項目
2.pom加入Eureka的環境
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
項目構建插件
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
3.配置文件,增加Eureka相關的配置
server:port: 10010
spring:application:name: eureka-server
eureka:instance:hostname: localhostclient:fetch-registry: false # 表示是否從Eureka Server獲取注冊信息,默認為true.因為這是一個單點的Eureka Server,不需要同步其他的Eureka Server節點的數據,這里設置為falseregister-with-eureka: false # 表示是否將自己注冊到Eureka Server,默認為true.由于當前應用就是Eureka Server,故而設置為false.service-url:# 設置Eureka Server的地址,查詢服務和注冊服務都需要依賴這個地址defaultZone: <http://$>{eureka.instance.hostname}:${server.port}/eureka/
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
4.啟動類,開啟Eureka的功能
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class,args);}
}
5.啟動測試
啟動服務,訪問注冊中心:http://127.0.0.1:10010/
可以看到能正常訪問注冊中心了。
服務注冊
我們的需求是訂單查詢訂單信息的時候,根據訂單里的產品ID,獲取產品的詳細信息,也就是需要order-service遠程調用product-service,也就是說product-service是服務提供者,就需要把product-sevrice服務注冊到注冊中心里去。
1.加入Eureka的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
2.完善配置信息
#服務名稱
spring:application:name: product-service#eureka地址
eureka:client:service-url:defaultZone: <http://127.0.0.1:10010/eureka/>
#日志
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
3.啟動測試
可以看到product-service已經成功注冊到eureka-service上了。
服務發現
order-service是服務消費者,在遠程調用時候,會從eureka-server拉取product-service的服務信息,實現服務發現。
1.加入Eureka依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
2.完善配置信息
spring:application:name: order-serviceeureka:client:service-url:defaultZone: <http://127.0.0.1:10010/eureka/>
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
3.修改遠程調用的代碼
public OrderInfo selectOrderById(Integer orderId){OrderInfo orderInfo = orderMapper.selectOrderById(orderId);//String url = "<http://127.0.0.1:9090/product/>" + orderInfo.getProductId();//從Eureka中獲取服務列表List<ServiceInstance> instances = discoveryClient.getInstances("product-service");//http://127.0.0.1:9090//instances.get(0):服務可能有多個,這里只獲取第一個String uri = instances.get(0).getUri().toString();String url = uri + "/product/" + orderInfo.getProductId();log.info("遠程調用url:{}",url);ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
4.啟動測試
可以看到order-service已經注冊到eureka上了。
訪問接口:http://127.0.0.1:8080/order/1
也可以看到,遠程調用成功了。
Eureka 和Zookeeper區別(不發)
Eureka和Zookeeper都是?于服務注冊和發現的?具,區別如下:
- Eureka是Netflix開源的項?, ?Zookeeper是Apache開源的項?.
- Eureka 基于AP原則, 保證?可?, Zookeeper基于CP原則, 保證數據?致性.
- Eureka 每個節點 都是均等的, Zookeeper的節點區分Leader 和Follower 或 Observer, 也正因為這 個原因, 如果Zookeeper的Leader發?故障時, 需要重新選舉, 選舉過程集群會有短暫時間的不可?.