關于Eureka的學習,主要學習如何搭建Eureka,將order-service和product-service都注冊到Eureka。?
1.為什么使用Eureka?
我在實現一個查詢訂單功能時,希望可以根據訂單中productId去獲取對應商品的詳細信息,但是產品服務和訂單服務是分布式的,所以如果要實現根據訂單中的productId去獲取商品的詳細信息,就需要在訂單服務中遠程調用產品服務,如下圖
但是這樣有一個問題,就是遠程調用產品服務時,這里的ip和端口號是寫死的,如果ip地址發生變化,我們就需要修改對應的代碼,而Eureka就是用解決這個問題的。
2.注冊中心?
Eureka是作為一個注冊中心來解決這個問題的,當產品服務發生變更重新啟動時,會先先向Eureka打報告,然后Eureka去記錄服務和對應IP的關系,此時訂單服務如果想遠程調用產品服務,此時產品服務會先去Eureka獲取產品服務的IP,然后再根據從Eureka中獲取的IP去遠程調用產品服務。
2.1 什么是注冊中心?
在Spring Cloud Eureka中,注冊中心是服務發現的核心組件,負責管理微服務的注冊和發現。?
2.2 注冊中心的三種角色?
注冊中心主要有3中角色,分別是服務提供者(Server),服務消費者(Client)和服務注冊中心(Registry)。
服務提供者(Server):一次業務中,被其他微服務調用的服務,也就是給其他微服務提供接口的微服務,如上面提到的產品服務就是服務提供者
服務消費者(Client):一次業務中,調用其他微服務的微服務,也就是調用其他微服務提供的接口的微服務,如上面提到的訂單服務就是服務消費者
服務注冊中心(Registry)?:用于保存Server的注冊信息,當Server節點發生更改時,Registry會同步變更。服務與注冊中心使用一定機制通信,如果注冊中心與某服務長時間無法通信,就會注銷該實例。
三者之間的關系和工作內容,可以用兩個概念來解釋。
服務注冊:服務提供者在啟動時,向注冊中心注冊自身服務,并向注冊中心定期發送心跳匯報存活狀態。
服務發現:?服務消費者1從注冊中心查詢服務提供者的IP地址,并通過該IP地址遠程調用服務提供者的接口。服務發現的一個重要作用就是提供給服務者一個可用的服務列表。
如下圖
2.3 CAP理論
談到注冊中心,就避不開CAP理論,CAP理論是分布式系統設計中最基礎,也是最為關鍵的理論。
?一致性:CAP理論中的一致性,這里指的是強一致性,強一致性的意思是所有節點的對外提供的數據都是一致的。
可用性:保證每個請求都能有響應,響應的數據有可能是舊的數據。
分區容錯性: 當出現網絡分區后后,系統任然能夠對外提供服務。
網絡分區是指在分布式系統中,由于網絡故障,導致分布式系統中部分節點無法進行通信,形成多個獨立的子網絡(即分區)
CAP理論告訴我們:一個分布式系統不可能同時滿足數據一致性,服務可用性和分區容錯性這三個基本需求,最多只能同時滿足其中兩個。
在分布式系統中,由于網絡狀態是不可預測的,我們即使出現網絡分區的情況,我們的系統任然能夠對外提供服務,所以我們一定保證分區容錯性。
正常情況下
網絡出現異常:
而一致性和可用性只能滿足一個。
如果想要保證各個節點數據的強一致性,由于數據的同步更新是有一定時間延遲的,那么此時該節點的服務一定是有一段時間是停止對外提供服務的。?
如果想要保證可用性,由于數據的同步更新是有一定時間延遲的,那么此時一定有一段時間一些節點的數據是來不及更新的,如果此時請求發送到給數據還沒有同步更新的節點,那么得到的響應就是一個舊的數據。?
所以,我們只能實現AP架構或者CP架構
?AP架構:為了保證分布式系統對外的數據一致性,于是選擇不返回任何數據
AP架構:為了保證分布式系統的可用性,即使該節點數據還沒有關系,依舊會返回一個響應,這個響應中的數據是一個舊的數據。
y3.搭建Eureka Server?
Eureka Server可以是一個單獨的工程,也可以是一個子工程,下面的搭建Eureka Server是以子工程的方式搭建的。
第一步,創建一個子工程
第二步,在eureka-server工程中的pom文件引入eureka-server的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
第三步,在在eureka-server工程中的pom文件引入項目構建插件
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
第四步,完善啟動類,注意在在啟動類加上@EnableEurekaServer注解
第五步,在配置文件中添加一下配置信息?
# Eureka相關配置
# 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/
第六步,啟動服務
啟動服務后,如果能通過127.0.0.1:10010訪問,說明Eureka搭建成功了,如下圖
4.服務注冊?
將product-service服務注冊到eureka server中
第一步,在product-service的pom文件中引入下面的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
第二步,完善product-service的配置文件
?添加服務名稱和eureka地址
#Eureka Client
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/
第三部,啟動product-service服務,啟動之后,刷新注冊中心界面,會發現注冊中心中注冊了product-service服務
5.服務發現?
接下來我們修改orders-service,在遠程調用時,從eureka-server拉去product-service的服務信息,實現服務發現。
第一步,在orders-service工程的pom文件中引入下面的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
第二步,完善orders-service的配置文件,添加服務名稱和eureka地址?
添加的eureka地址的配置文件,添加服務名稱根據自己工程的名字自己去添加即可。?
#Eureka Client
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/
第三步,實現訂單服務遠程調用產品服務,代碼如下
修改原來的service層代碼?
如果要從Eureka中獲取注冊的服務列表,要用到一個spring中提供的DiscoveryClient,通過getInstances方法來獲取服務列表,getInstances是通過服務的Id來Eureka中獲取對應的服務列表,這里的id其實就是服務的名稱。
由于是一個服務列表,我們要從服務列表中獲取對應的服務,由于我在Eureka中注冊的product-service服務只有一個,所以從服務列表中取第一個服務就行了。
@Slf4j
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;public OrderInfo selectByOrderId(Integer id){OrderInfo orderInfo = orderMapper.selectByOrderId(id);/*String url = "http://127.0.0.1:9090/product/"+orderInfo.getProductId();*///根據應用名從eureka中獲取對應的服務列表List<ServiceInstance> instances = discoveryClient.getInstances("product-service");String uri = instances.get(0).getUri().toString();log.info("遠程調用的uri:{}",uri);String url = uri+"/product/"+orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}}
第四步,運行訂單服務,啟動orders-service服務,此時刷新Eureka頁面,發現Eureka中也成功注冊orders-service服務
遠程調用product-service也成功了
注意:校驗時,eureka-server,product-service和order-service都要啟動?