使用 Eureka 做服務(wù)發(fā)現(xiàn)

Zookeeper 做注冊(cè)中心的缺陷

Peter Kelley(個(gè)性化教育初創(chuàng)公司 knewton 的一名軟件工程師)發(fā)表了一篇文章說(shuō)明為什么Zookeeper 用于服務(wù)發(fā)現(xiàn)是一個(gè)錯(cuò)誤的做法,他主要提出了三個(gè)缺點(diǎn):

  1. ZooKeeper 無(wú)法很好的處理網(wǎng)絡(luò)分區(qū)問(wèn)題,當(dāng)網(wǎng)絡(luò)分區(qū)中的客戶端節(jié)點(diǎn)無(wú)法到達(dá) Quorum 時(shí),會(huì)與 ZooKeeper 失去聯(lián)系,從而也就無(wú)法使用其服務(wù)發(fā)現(xiàn)機(jī)制。

  2. 服務(wù)發(fā)現(xiàn)系統(tǒng)應(yīng)該是一個(gè) AP 系統(tǒng),設(shè)計(jì)上針對(duì)可用性;而 ZooKeeper 是一個(gè) CP 系統(tǒng)。

  3. ZooKeeper 的設(shè)置和維護(hù)非常困難,實(shí)際操作的時(shí)候也容易出錯(cuò),比如在客戶端重建 Watcher,處理 Session 和異常的時(shí)候。

當(dāng)然, Peter Kelley 提出的這幾個(gè)問(wèn)題并不是不能克服的,并不能說(shuō)明基于 ZooKeeper 就不能做好一個(gè)服務(wù)發(fā)現(xiàn)系統(tǒng),但是我們可能有更簡(jiǎn)潔的方案來(lái)實(shí)現(xiàn)。

Eureka 介紹

什么是 Eureka

官方的介紹在這里Eureka Wiki。Eureka 是 Netflix 開(kāi)源的一個(gè) Restful 服務(wù),主要用于服務(wù)的注冊(cè)發(fā)現(xiàn)。Eureka 由兩個(gè)組件組成: Eureka 服務(wù)器和 Eureka 客戶端。 Eureka 服務(wù)器用作服務(wù)注冊(cè)服務(wù)器。 Eureka 客戶端是一個(gè) Java 客戶端,用來(lái)簡(jiǎn)化與服務(wù)器的交互、作為輪詢負(fù)載均衡器,并提供服務(wù)的故障切換。 Netflix 在其生產(chǎn)環(huán)境中使用的是另外的客戶端,它提供基于流量、資源利用率以及出錯(cuò)狀態(tài)的加權(quán)負(fù)載均衡。

  • 開(kāi)源: 大家可以對(duì)實(shí)現(xiàn)一探究竟,甚至修改源代碼。
  • 可靠: 經(jīng)過(guò) Netflix 多年的生產(chǎn)環(huán)境考驗(yàn),使用應(yīng)該比較靠譜處心。
  • 功能齊全: 不但提供了完整的注冊(cè)發(fā)現(xiàn)服務(wù),還有 Ribbon 等可以配合使用服務(wù)。
  • 基于 Java: 對(duì)于 Java 程序員來(lái)說(shuō),使用起來(lái),心里比較有底。
  • Spring Cloud 可以使用 Spring Cloud,與 Eureka 進(jìn)行了很好的集成,使用起來(lái)非常方便。

Eureka 架構(gòu):

Netflix 主要是在 AWS 中使用 Eureka 的,雖然同時(shí)也支持本地環(huán)境,但是了解 AWS 的一些基礎(chǔ)概念對(duì)于理解 Eureka 的設(shè)計(jì)非常有幫助。

區(qū)域與可用區(qū)

首先,我們先熟悉兩個(gè)概念:

  • 區(qū)域(Region): AWS 云服務(wù)在全球不同的地方都有數(shù)據(jù)中心,比如北美、南美、歐洲和亞洲等。與此對(duì)應(yīng),根據(jù)地理位置我們把某個(gè)地區(qū)的基礎(chǔ)設(shè)施服務(wù)集合稱為一個(gè)區(qū)域。通過(guò) AWS 的區(qū)域,一方面可以使得 AWS 云服務(wù)在地理位置上更加靠近我們的用戶,另一方面使得用戶可以選擇不同的區(qū)域存儲(chǔ)他們的數(shù)據(jù)以滿足法規(guī)遵循方面的要求。美東(北佛吉尼亞)、美西(俄勒岡)、美西(北加利佛尼亞)、歐洲(愛(ài)爾蘭)、亞太(新加坡)、亞太(東京)等。每個(gè)區(qū)域都有自己對(duì)應(yīng)的編碼,如:
區(qū)域 編碼
亞太(東京) ap-northeast-1
亞太(新加坡) ap-southeast-1
亞太(悉尼) ap-southeast-2
歐洲(愛(ài)爾蘭) eu-west-1
南美(圣保羅) sa-east-1
美東(北佛杰尼亞) us-east-1
美西(北加利佛尼亞) us-west-1
美西(俄勒岡) us-west-2
  • 可用區(qū)(Zone): AWS 的每個(gè)區(qū)域一般由多個(gè)可用區(qū)(AZ)組成,而一個(gè)可用區(qū)一般是由多個(gè)數(shù)據(jù)中心組成。AWS引入可用區(qū)設(shè)計(jì)主要是為了提升用戶應(yīng)用程序的高可用性。因?yàn)榭捎脜^(qū)與可用區(qū)之間在設(shè)計(jì)上是相互獨(dú)立的,也就是說(shuō)它們會(huì)有獨(dú)立的供電、獨(dú)立的網(wǎng)絡(luò)等,這樣假如一個(gè)可用區(qū)出現(xiàn)問(wèn)題時(shí)也不會(huì)影響另外的可用區(qū)。在一個(gè)區(qū)域內(nèi),可用區(qū)與可用區(qū)之間是通過(guò)高速網(wǎng)絡(luò)連接,從而保證有很低的延時(shí)。

每次當(dāng)用戶需要使用 EC2 相關(guān)資源的時(shí)候,他需要首先選擇目標(biāo)區(qū)域,如美東(北佛杰尼亞)us-east-1。然后在創(chuàng)建 EC2 產(chǎn)例的時(shí)候,用戶可以選擇實(shí)例所在的可用區(qū),比如可以是 us-east-1a 或 us-east-1b 等??捎脜^(qū)的編碼就是區(qū)域后面添加不同的英文字母。

Eureka 架構(gòu)說(shuō)明

下圖是 Eureka Wiki 中提供的架構(gòu)圖:

Eureka 架構(gòu)圖

從上面的架構(gòu)圖可以看出,主要有三種角色:

  • Eureka Server
    *** 通過(guò) Register, Get,Renew 等 接口提供注冊(cè)和發(fā)現(xiàn)

  • Application Service (Service Provider):
    *** 服務(wù)提供方
    *** 把自身服務(wù)實(shí)例注冊(cè)到 Eureka Server

  • Application Client (Service Consumer):
    *** 服務(wù)調(diào)用方
    *** 通過(guò) Eureka Server 獲取服務(wù)實(shí)例,并調(diào)用 Application Service

他們主要進(jìn)行的活動(dòng)如下:

  1. 每個(gè) Region 有一個(gè) Eureka Cluster, Region 中的每個(gè) Zone 都至少有一個(gè) Eureka Server。
  2. Service 作為一個(gè) Eureka Client,通過(guò) register 注冊(cè)到 Eureka Server,并且通過(guò)發(fā)送心跳的方式更新租約(renew leases)。如果 Eureka Client 到期沒(méi)有更新租約,那么過(guò)一段時(shí)間后,Eureka Server 就會(huì)移除該 Service 實(shí)例。
  3. 當(dāng)一個(gè) Eureka Server 的數(shù)據(jù)改變以后,會(huì)把自己的數(shù)據(jù)同步到其他 Eureka Server。
  4. Application Client 也作為一個(gè) Eureka Client 通過(guò) Get 接口從 Eureka Server 中獲取 Service 實(shí)例信息,然后直接調(diào)用 Service 實(shí)例。
  5. Application Client 調(diào)用 Service 實(shí)例時(shí),可以跨可用區(qū)調(diào)用。

Eureka Demo

實(shí)際工作中,我們很少會(huì)直接使用 Eureka,因?yàn)?Spring Cloud 已經(jīng)把 Eureka 與 Spring Boot 進(jìn)行了集成,使用起來(lái)更為簡(jiǎn)單,所以我們使用 Spring Cloud 作為示例。

這里是官方提供的一個(gè)示例:spring-cloud-eureka-example

啟動(dòng) Eureka Server

Eureka Server 非常簡(jiǎn)單,只需要三個(gè)步驟:

  1. 在 pom.xml 中添加依賴:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
  1. 實(shí)現(xiàn) Application,添加 annotation。 @EnableEurekaServer、@EnableDiscoveryClient 執(zhí)行 main 方法啟動(dòng) Eureka Server。
@SpringBootApplication
@EnableEurekaServer
@EnableDiscoveryClient
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}
  1. 運(yùn)行 Application 即可啟動(dòng) Server,啟動(dòng) Server 后打開(kāi) http://localhost:8761/,可以看到信息頁(yè)面。

注冊(cè)服務(wù)

把一個(gè)服務(wù)注冊(cè)在 server 中需要以下幾個(gè)步驟:

  1. 添加 eureka 依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
  1. 添加 @EnableEurekaClient 注解
@EnableEurekaClient
public class Application
  1. 在 application.yml 或者 application.properties 中添加配置
eureka:
  instance:
    leaseRenewalIntervalInSeconds: 1
    leaseExpirationDurationInSeconds: 2
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/
    healthcheck:
      enabled: true
    lease:
      duration: 5
 
spring:
  application:
    name: customer-service

配置中有兩項(xiàng)需要額外注意:

  • eureka.client.serviceUrl.defaultZone:指定 Eureka 服務(wù)端的地址,當(dāng)客戶端沒(méi)有專門進(jìn)行配置時(shí),就會(huì)使用這個(gè)默認(rèn)地址。

  • spring.application.name:服務(wù)注冊(cè)所使用的名稱,同時(shí)其他服務(wù)查找該服務(wù)時(shí)也使用該名稱。我們啟動(dòng)該服務(wù)后,可以在管理頁(yè)面中查看到該服務(wù)已經(jīng)在注冊(cè)中心中注冊(cè)成功了。

服務(wù)發(fā)現(xiàn)與負(fù)載均衡(Ribbon + RestTemplate)

直接使用 Eureka Client 還是比較麻煩的,幸運(yùn)的是,RestTemplate 整合了 Eureka Client,Ribbon 為我們提供了多樣的負(fù)載均衡的功能,為我們提供了很多便利,我們所需要做的就是在 Spring 中注冊(cè)一個(gè) RestTemplate,并且添加 @LoadBalanced 注解

@Configuration
public class Config {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

接下來(lái),可以直接使用 RestTemplate 調(diào)用服務(wù)。服務(wù)的 URL 中包含了服務(wù)名稱,例如:http://customer-service/customer,其中, customer-service 是服務(wù)名,而 customer 是該服務(wù)下的一個(gè)接口。

@Autowired
private RestTemplate restTemplate; 
 
public MessageWrapper<Customer> getCustomer(int id) { 
    Customer customer = restTemplate.exchange( "http://customer-service/customer/{id}", HttpMethod.GET, null, new ParameterizedTypeReference<Customer>() { }, id).getBody(); 
    return new MessageWrapper<>(customer, "server called using eureka with rest template"); 
}

Eureka Api

如果使用的是非 Java 的語(yǔ)言客戶端,可以通過(guò) API 的方式進(jìn)行集成。相關(guān)文檔請(qǐng)查看 https://github.com/Netflix/eureka/wiki/Eureka-REST-operations

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容