javascript
Spring Cloud 入门 之 Eureka 篇(一)
一、前言
Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的開發(fā)便利性巧妙地簡化了分布式系統(tǒng)基礎(chǔ)設(shè)施的開發(fā),如服務(wù)發(fā)現(xiàn)注冊、配置中心、消息總線、負(fù)載均衡、斷路器、數(shù)據(jù)監(jiān)控等,都可以用 Spring Boot 的開發(fā)風(fēng)格做到一鍵啟動(dòng)和部署。
本篇介紹 Spring Cloud 入門系列中的 Eureka,實(shí)現(xiàn)快速入門。
二、簡單介紹
Eureka 是 Netflix 的子模塊,它是一個(gè)基于 REST 的服務(wù),用于定位服務(wù),以實(shí)現(xiàn)云端中間層服務(wù)發(fā)現(xiàn)和故障轉(zhuǎn)移。
服務(wù)注冊和發(fā)現(xiàn)對于微服務(wù)架構(gòu)而言,是非常重要的。有了服務(wù)發(fā)現(xiàn)和注冊,只需要使用服務(wù)的標(biāo)識(shí)符就可以訪問到服務(wù),而不需要修改服務(wù)調(diào)用的配置文件。該功能類似于 Dubbo 的注冊中心,比如 Zookeeper。
Eureka 采用了 CS 的設(shè)計(jì)架構(gòu)。Eureka Server 作為服務(wù)注冊功能的服務(wù)端,它是服務(wù)注冊中心。而系統(tǒng)中其他微服務(wù)則使用 Eureka 的客戶端連接到 Eureka Server 并維持心跳連接。
其運(yùn)行原理如下圖:
由圖可知,Eureka 的運(yùn)行原理和 Dubbo 大同小異, Eureka 包含兩個(gè)組件: Eureka Server 和 Eureka Client。
Eureka Server 提供服務(wù)的注冊服務(wù)。各個(gè)服務(wù)節(jié)點(diǎn)啟動(dòng)后會(huì)在 Eureka Server 中注冊服務(wù),Eureka Server 中的服務(wù)注冊表會(huì)存儲(chǔ)所有可用的服務(wù)節(jié)點(diǎn)信息。
Eureka Client 是一個(gè) Java 客戶端,用于簡化 Eureka Server 的交互,客戶端同時(shí)也具備一個(gè)內(nèi)置的、使用輪詢負(fù)載算法的負(fù)載均衡器。在應(yīng)用啟動(dòng)后,向 Eureka Server 發(fā)送心跳(默認(rèn)周期 30 秒)。如果 Eureka Server 在多個(gè)心跳周期內(nèi)沒有接收到某個(gè)節(jié)點(diǎn)的心跳,Eureka Server 會(huì)從服務(wù)注冊表中將該服務(wù)節(jié)點(diǎn)信息移除。
三、搭建注冊中心
創(chuàng)建 Spring Boot 項(xiàng)目,名為 eureka-server,進(jìn)行如下操作:
#?3.1 添加依賴
? <dependencyManagement><dependencies><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-starter-parent</artifactId><version>2.1.3.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement><dependencies><!-- eureka 服務(wù)端 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency> </dependencies>?Spring Boot 與 SpringCloud 有版本兼容關(guān)系,如果引用版本不對應(yīng),項(xiàng)目啟動(dòng)會(huì)報(bào)錯(cuò)。具體信息查看?Spring 官網(wǎng)。
#?3.2 application.yml 配置參數(shù)
server:port: 9000spring:application:name: EUREKAeureka:instance:hostname: localhost # eureka 實(shí)例名稱client:register-with-eureka: false # 不向注冊中心注冊自己fetch-registry: false # 是否檢索服務(wù)service-url:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 注冊中心訪問地址#?3.3 開啟注冊中心功能
在啟動(dòng)類上添加?@EnableEurekaServer?注解:
@EnableEurekaServer @SpringBootApplication public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);} }至此,準(zhǔn)備工作完成,啟動(dòng)項(xiàng)目完成后,瀏覽器訪問?http://localhost:9000?,查看 Eureka 服務(wù)監(jiān)控界面,如下圖:
通過該網(wǎng)址可以查看注冊中心注冊服務(wù)的相關(guān)信息。當(dāng)前還沒有服務(wù)注冊,因此沒有服務(wù)信息。
補(bǔ)充:http://localhost:9000?是 Eureka 監(jiān)管界面訪問地址,而?http://localhost:9000/eureka/?Eureka 注冊服務(wù)的地址。
四、實(shí)戰(zhàn)演練
了解 Eureka 的環(huán)境搭建后,我們需要進(jìn)行實(shí)戰(zhàn)直觀的感受 Eureka 的真正作用,這樣才能清楚掌握和學(xué)習(xí) Eureka 。
下面我們要?jiǎng)?chuàng)建 2 個(gè)微服務(wù),一個(gè)是商品服務(wù),另一個(gè)訂單服務(wù)。
測試場景:用戶下訂單時(shí),訂單系統(tǒng)需要調(diào)用商品系統(tǒng)獲取商品信息檢查商品是否存在,從而進(jìn)行其他操作。
| common-api | - | 公用的 api,如:實(shí)體類 |
| eureka-server | 9000 | 注冊中心(Eureka 服務(wù)端) |
| goods-server | 8081 | 商品服務(wù)(Eureka 客戶端) |
| order-server | 8100 | 訂單服務(wù)(Eureka 客戶端) |
#?4.1 商品服務(wù)(goods-server)
由于文章內(nèi)容針對 Eureka 的入門和使用,因此只張貼重要代碼。具體代碼請瀏覽下文提供的源碼地址。
? ? 2.配置參數(shù):
server:port: 8081spring:application:name: GOODSeureka:instance:instance-id: goods-api-8081prefer-ip-address: true # 訪問路徑可以顯示 IPclient:service-url:defaultZone: http://localhost:9000/eureka/ # 注冊中心訪問地址注意:http://localhost:9000/eureka/?就是第三節(jié)中配置的注冊中心的地址。
? ? 3. 服務(wù)接口:
public interface GoodsService {Goods findGoodsById(String goodsId); } @Service public class GoodsServiceImpl implements GoodsService{// 模擬數(shù)據(jù)庫private static Map<String, Goods> data;static {data = new HashMap<>();data.put("1", new Goods("1", "手機(jī)", "國產(chǎn)手機(jī)", 8081));data.put("2", new Goods("2", "電腦", "臺(tái)式電腦", 8081));}@Overridepublic Goods findGoodsById(String goodsId) {return data.get(goodsId);}} @RestController @RequestMapping("/goods") public class GoodsController {@Autowiredprivate GoodsService goodsService;@RequestMapping("/goodsInfo/{goodsId}")public Result goodsInfo(@PathVariable String goodsId) {Goods goods = this.goodsService.findGoodsById(goodsId);return Result.success(goods);} }? ? 4.開啟服務(wù)注冊功能:
? ? 在啟動(dòng)類上添加?@EnableEurekaClient?注解:
@EnableEurekaClient @SpringBootApplication public class GoodsServerApplication {public static void main(String[] args) {SpringApplication.run(GoodsServerApplication.class, args);} }? ? 啟動(dòng)項(xiàng)目完成后,瀏覽器訪問?http://localhost:9000?查看 Eureka 服務(wù)監(jiān)控界面 ,如下圖:
從圖可知,商品服務(wù)已經(jīng)注冊到 Eureka 服務(wù)中了。
補(bǔ)充:在上圖中,我們還看到一串紅色的字體,那是因?yàn)?Eureka 啟動(dòng)了自我保護(hù)的機(jī)制。當(dāng) EurekaServer 在短時(shí)間內(nèi)丟失過多客戶端時(shí)(可能發(fā)生了網(wǎng)絡(luò)故障),EurekaServer 將進(jìn)入自我保護(hù)模式。進(jìn)入該模式后,EurekaServer 會(huì)保護(hù)服務(wù)注冊表中的信息不被刪除。當(dāng)網(wǎng)絡(luò)故障恢復(fù)后,EurekaServer 會(huì)自動(dòng)退出自我保護(hù)模式。
#?4.2 訂單服務(wù)(order-server)
? ? 2.配置參數(shù):
server:port: 8100spring:application:name: ORDEReureka:instance:instance-id: order-api-8100prefer-ip-address: true # 訪問路徑可以顯示 IPclient:service-url:defaultZone: http://localhost:9000/eureka/ # 注冊中心訪問地址? ? 3.服務(wù)接口:
@Configuration public class RestConfiguration {@Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } } public interface OrderService {void placeOrder(Order order) throws Exception; } @Service public class OrderServiceImpl implements OrderService{@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient client;@Overridepublic void placeOrder(Order order) throws Exception{// 獲取商品服務(wù)地址列表List<ServiceInstance> list = this.client.getInstances("GOODS");String uri = "";for (ServiceInstance instance : list) {if (instance.getUri() != null && !"".equals(instance.getUri())) {uri = instance.getUri().toString();break;}}Result result = restTemplate.getForObject(new URI(uri + "/goods/goodsInfo/" + order.getGoodsId()), Result.class);if (result != null && result.getCode() == 200) {System.out.println("=====下訂單====");System.out.println(result.getData());}}}注意:此處只是為了體現(xiàn)服務(wù)發(fā)現(xiàn)的效果,實(shí)際開發(fā)中不使用 DiscoveryClient 查詢服務(wù)進(jìn)行調(diào)用!至于如何進(jìn)行服務(wù)發(fā)現(xiàn)和調(diào)用請讀者等待和瀏覽后續(xù)發(fā)布的 Ribbon 文章。
? ? 4.客戶端:
@RestController @RequestMapping("/order") public class OrderController {@Autowiredprivate OrderService orderService;@RequestMapping("/place")public Result placeOrder(Order order) throws Exception {this.orderService.placeOrder(order);return Result.success();} }?
? ? 5.開啟服務(wù)發(fā)現(xiàn)功能:
? ? 在啟動(dòng)類上添加?@EnableEurekaClient?注解:
@EnableEurekaClient @SpringBootApplication public class OrderServerApplication {public static void main(String[] args) {SpringApplication.run(OrderServerApplication.class, args);} }啟動(dòng)項(xiàng)目后,使用 PostMan 模擬用戶下單,運(yùn)行結(jié)果如下:
至此,Eureka 的服務(wù)注冊和發(fā)現(xiàn)演示完畢。
本系列的后續(xù)文章會(huì)基于該案例進(jìn)行介紹和實(shí)戰(zhàn)演練。
五、Eureka 集群
Eureka 作為注冊中心,保存了系統(tǒng)服務(wù)的相關(guān)信息,如果注冊中心掛掉,那么系統(tǒng)就癱瘓了。因此,對 Eureka 做集群實(shí)現(xiàn)高可用是必不可少的。
本次測試使用一臺(tái)機(jī)器部署 Eureka 集群,通過名字和端口區(qū)分不同的 eureka 服務(wù)。
| eureka01 | 9001 |
| eureka02 | 9002 |
? ? 2. application.yml 文件需要進(jìn)行如下修改:
server:port: 9001eureka:instance:hostname: eureka01 # eureka 實(shí)例名稱client:register-with-eureka: false # 不向注冊中心注冊自己fetch-registry: false # 表示自己就是注冊中心service-url:defaultZone: http://eureka01:9001/eureka/,http://eureka02:9002/eureka/? ? 兩個(gè) eureka 服務(wù)實(shí)例的配置文件修改方式類似,將名稱和端口進(jìn)行修改即可。
? ? 3. ?服務(wù)注冊的項(xiàng)目中,將 eureka.client.service-url.defaultZone 改成集群的 url 即可。
? ? 啟動(dòng)效果如下圖:
六、Eureka 與 Zookeeper 的區(qū)別
兩者都可以充當(dāng)注冊中心的角色,且可以集群實(shí)現(xiàn)高可用,相當(dāng)于小型的分布式存儲(chǔ)系統(tǒng)。
#?6.1 CAP 理論
CAP 分別為 consistency(強(qiáng)一致性)、availability(可用性) 和 partition tolerance(分區(qū)容錯(cuò)性)。
理論核心:一個(gè)分布式系統(tǒng)不可能同時(shí)很好的滿足一致性、可用性和分區(qū)容錯(cuò)性這三個(gè)需求。因此,根據(jù) CAP 原理將 NoSQL 數(shù)據(jù)庫分成滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三大類:
CA:單點(diǎn)集群,滿足一致性,可用性的系統(tǒng),通常在可擴(kuò)展性上不高 CP: 滿足一致性,分區(qū)容錯(cuò)性的系統(tǒng),通常性能不是特別高 AP: 滿足可用性,分區(qū)容錯(cuò)性的系統(tǒng),通過對一致性要求較低簡單的說:CAP 理論描述在分布式存儲(chǔ)系統(tǒng)中,最多只能滿足兩個(gè)需求。
#?6.2 Zookeeper 保證 CP
當(dāng)向注冊中心查詢服務(wù)列表時(shí),我們可以容忍注冊中心返回的是幾分鐘前的注冊信息,但不能接受服務(wù)直接掛掉不可用了。因此,服務(wù)注冊中心對可用性的要求高于一致性。
但是,zookeeper 會(huì)出現(xiàn)一種情況,當(dāng) master 節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與其他節(jié)點(diǎn)失去聯(lián)系時(shí),剩余節(jié)點(diǎn)會(huì)重新進(jìn)行 leader 選舉。問題在于,選舉 leader 的時(shí)間較長,30 ~ 120 秒,且選舉期間整個(gè) zookeeper 集群是不可用的,這期間會(huì)導(dǎo)致注冊服務(wù)癱瘓。在云部署的環(huán)境下,因網(wǎng)絡(luò)問題導(dǎo)致 zookeeper 集群失去 master 節(jié)點(diǎn)的概率較大,雖然服務(wù)能最終恢復(fù),但是漫長的選舉時(shí)間導(dǎo)致注冊服務(wù)長期不可用是不能容忍的。
#?6.3 Eureka 保證 AP
Eureka 在設(shè)計(jì)上優(yōu)先保證了可用性。EurekaServer 各個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉不會(huì)影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊和發(fā)現(xiàn)服務(wù)。
而 Eureka 客戶端在向某個(gè) EurekaServer 注冊或發(fā)現(xiàn)連接失敗時(shí),會(huì)自動(dòng)切換到其他 EurekaServer 節(jié)點(diǎn),只要有一臺(tái) EurekaServer 正常運(yùn)行,就能保證注冊服務(wù)可用,只不過查詢到的信息可能不是最新的。
除此之外,EurekaServer 還有一種自我保護(hù)機(jī)制,如果在 15 分鐘內(nèi)超過 85% 的節(jié)點(diǎn)都沒有正常的心跳,那么 EurekaServer 將認(rèn)為客戶端與注冊中心出現(xiàn)網(wǎng)絡(luò)故障,此時(shí)會(huì)出現(xiàn)一下幾種情況:
EurekaServer 不再從注冊列表中移除因?yàn)殚L時(shí)間沒有收到心跳而應(yīng)該過期的服務(wù)EurekaServer 仍然能夠接收新服務(wù)的注冊和查詢請求,但不會(huì)被同步到其他節(jié)點(diǎn)上當(dāng)網(wǎng)絡(luò)穩(wěn)定時(shí),當(dāng)前 EurekaServer 節(jié)點(diǎn)新的注冊信息會(huì)同步到其他節(jié)點(diǎn)中因此,Eureka 可以很好的應(yīng)對因網(wǎng)絡(luò)故障導(dǎo)致部分節(jié)點(diǎn)失去聯(lián)系的情況,而不會(huì)向 Zookeeper 那樣是整個(gè)注冊服務(wù)癱瘓。
七、案例源碼
Eureka demo 源碼
八、參考資料
Springcloud 中文網(wǎng)
ZooKeeper、Eureka對比
總結(jié)
以上是生活随笔為你收集整理的Spring Cloud 入门 之 Eureka 篇(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jeewx-api.jar入门教程
- 下一篇: 再水一发相同序列