SpringCloud系列(2)---Netfilx-Eureka

上一篇筆記寫到的兩個問題,Netfilx-Eureka和Ribbo會給我們一一解決。如果有看過dubbo 應該知道zookeeper,Eureka的角色就是zookeeper。

Eureka和Zookeeper主要都是作爲微服務的註冊和發現。

Eureka和Zookeeper不一樣的是,Zookeeper是作爲一個單獨的應用程序,而Eureka是直接嵌套在SpringCloud當中的。所以 Eureka Server本身就是一個SpringBoot的項目。


一、服務註冊和發現概念


上面的圖是我網上找的。由於微服務的地址變革可能會影響很大,所以就引入了服務註冊中心的角色。所有服務提供者必須將IP地址或者主機名註冊到服務器註冊中心當中,我們使用註冊中心就是Eurika Server。服務的消費者在調用服務器之前,先要到服務註冊中心查詢服務提供者的網絡地址信息,然後進行調用,這個原理非常相似於我們的DNS。獲得服務提供者的網絡地址的操作,我們稱爲服務發現。服務註冊中心一般提供一下功能組件:

1、服務註冊表:記錄各個微服務的信息,例如名稱、網絡地址、端口號等。服務器註冊表提供查詢和管理的API,用於管理和查詢可用的微服務實例。

2、服務註冊和發現:剛剛已經說過了,微服務在啓動時,將自己的信息註冊到服務器註冊中心當中。在消費者可以通過服務註冊中心發現服務實例。

3、服務檢查:檢查微服務的健康情況,如果微服務實例在一段時間沒有心跳信息,就會從服務實例註冊表中移除該實例。


二、Eureka

Eureka是Netfilx開源的服務發現組件,本身是基於REST的服務。包含Server和Client兩個部分。SpingCloud 將其集成到SpringCloud Netflix子項目中。

Eureka有兩個概念分別 Region和Availability Zone。他們都是Amazon AWS的概率。其中,Region表示AWS中的地理位置,每個Region都有多個Availability Zone,各個Region之間完全隔離。

Spring Cloud 默認使用的Region是us-east-1,在非AWS環境下,可以將Availability Zone理解成機房,將Region理解爲誇機房的Eureka集羣。


三、Eureka Server 和 Client

Eureka Server 提供服務器的發現的能力,各個微服務啓動時,都會在Eureka Server中註冊自己的信息,Eureka Server 會將這些信息存儲到註冊表當中。

Eureka Client 這個就是一個JAVA客戶端,用於簡化於Eureka Server的交互。當然如果你的微服務是跨平臺的,各個服務存在不同的開發語言,那就只能通過REST的方式去與Eureka Server進行交互了。REST不是我們的重點,因爲我們作爲一個JAVA狗,Eureka Client足夠簡化我們的操作。

以下是筆者的從參考書中摘錄的重點概念:

1、微服務啓動後,會週期性向Eureka Server 發送心跳信息默認是30秒。如果Eureka在一定的時間內(默認90秒)無法獲得實例的心跳信息,Eureka Server 將會註冊該實例。

2、默認情況下,Eureka Server 同時也是Eureka Client。多個Eureka Server實例,互相之間通過複製的方式,來實現服務註冊表的同步。

3、Eureka Client 會緩存服務註冊表中的信息。這樣有非常多的好處,微服務無需每次都請求查詢Eureka Server,從而降低Eureka Server的服務壓力和網絡壓力;即使所有Eureka Server都掛了,Eureka Client還是可以根據自己的緩存註冊表自給自足。


四、動手編寫Eureka Server

筆者此事已經開了第三個IDE了,我的MacBook的內存開始吃不消了。建議這些還是在內存比較大的計算機上進行測試,而且同時去編譯和加載會導致非常耗時間。唉··· 一會還要再加多一個Eureka Server 做高可用,呵呵!搞事情!

在Maven上我們的依賴配置如下:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
然後在配置類當中打上@EnableEurekaServer 

@SpringBootApplication
@EnableEurekaServer
public class EurekaserveraApplication {

   public static void main(String[] args) {
      SpringApplication.run(EurekaserveraApplication.class, args);
   }
}
最後配置一下我們的application.properties

server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://lcoalhost:8761/eureka/

端口就不說了看看其他配置是什麼回事:

1、register-with-eureka 這個配置是否將自己的註冊到Eureka Server當中,默認true。由於當前應用就是Eureka Server 所以爲false

2、fetch-registry 表示是否從Eureka Server 中獲得註冊信息,默認爲true。目前是單點Eureka Server 所以不需要和其他Eureka Server 節點做同步,所以爲false

3、service-url.default-zone 設置與Eureka Server交互的地址,查詢服務和註冊服務都依賴這個地址。如果多個地址即多個Eureka Server節點需要用“,”分隔。默認是http://localhost:8761/eureka

配置完成,跑起!

需要注意的是,筆者之前是使用最新的SpringCloud版本1.5.4.RELEASE 但是實際當我打開頁面的過程當中發現無法打開上面的UI界面,只是有一個XML。筆者在查找了很多網上的資料後,也無法解決。但是在stackoverflow中我找到了一個帖子,說將其降級到1.5.2.RELEASE就正常出現頁面了。至於1.5.4爲什麼不可以顯示,可能後續我會有所補充。但是1.5.4其他的功能還是正常可以使用的。

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.4.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>
改成:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.2.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

五、Eureka Server 高可用

Eureka Server作爲一個服務註冊中心當然是不允許出現單點異常的,所以Eureka Server 做高可用是一個必須的操作。上面已經介紹過Eureka Server高可用的理論了,現在就操作一下。環境上筆者就不搞兩臺設備來做了,筆者會在hosts文件當中添加兩條記錄,表示當前的兩臺計算機的主機名:

127.0.0.1       eurekaservera eurekaserverb


然後在同一個項目當中配置兩個profile,然後通過不同的profile分別代表eureka-servera、eureka-serverb的配置,然後分別啓動。不清楚profile的可以看看我之前的SpringBoot的筆記SpringBoot系列(5)---SpringBoot-Web和SpringBoot基礎 搜索profile即可。


application-servera.properties文件配置如下:

server.port=8761
eureka.instance.hostname=eurekaservera
eureka.client.service-url.defaultZone=http://eurekaserverb:8762/eureka/
端口號8761 實例名稱的主機名稱爲 eurekaservera。 register-with-eureka 和 fetch-registry 默認爲true 所以直接不用配置  default-zone設置爲其他的eureka server 這裏設置是eureka-serverb 由於是同一臺計算機 所以我用了不同的端口號。


application-serverb.properties文件配置如下:

server.port=8762
eureka.instance.hostname=eurekaserverb
eureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/

就算端口號成8762 然後實例主機名稱改成 eureka-serverb 然後設置default-zone爲剛剛設置的eureka-servera


然後application.properties 修改profile.active 分別啓動

spring.application.name=tony-mall-discovery-eureka-ha
spring.profiles.active=servera

可以見到UI界面上出現如下的信息:



高可用已經配置生效了!


六、Eureka Cilent 

說了這麼久Eureka Server 連高可用都配置了,總得要用起來吧···  Eureka Client 真的非常簡單。你機會除了簡單的配置,你就感覺不到它的存在了。

我們分別在 用戶服務系統 和 商品服務系統 添加相應的Eureka Client 配置 主要爲了將自身信息隨SpringBoot項目開啓 註冊到 Eureka Server當中。

用戶服務系統的application.properties 文件如下:

server.port=8801
server.context-path=/user

spring.datasource.url=jdbc:mysql://localhost:3306/shop_mall?charset=utf8mb4
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=tonyyan

spring.application.name=tony-mall-provider-user
eureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/,http://eurekaserverb:8762/eureka/
eureka.instance.prefer-ip-address=true
service-url.defaultZone 我們將兩個Eureka Server 都註冊了。當然你可以註冊一個,然後通過指定的Eureka Server 自動獲得其他Eureka Server,同樣也可以實現高可用。但是最好也是配上,如果正好你指定的那臺Eureka Server 掛了,就呵呵了。

prefer-ip-address 爲true 這裏是代表註冊自身的ip地址 而不是主機名稱。


商品服務系統的application.properties 文件如下,跟用戶差不多:

server.port=8802
server.context-path=/product

spring.datasource.url=jdbc:mysql://localhost:3306/shop_mall?charset=utf8mb4
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=tonyyan

spring.application.name=tony-mall-provider-product
eureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/,http://eurekaserverb:8762/eureka/
eureka.instance.prefer-ip-address=true

最後在兩個項目的配置類當中分別打上@EnableDiscoveryClient的 annotation

@SpringBootApplication
@EnableDiscoveryClient
public class ProductsystemApplication {
@SpringBootApplication
@EnableDiscoveryClient
public class UsersystemApplication {


將兩個微服務啓動,並查看Eureka Server 上的實例信息:


如果你配置了HA,你會發現兩臺註冊中心都會出現同樣的實例列表。OK!現在都配置好了,可以調用測試~

@GetMapping("/getProduct/{productId}/userId/{userId}")
public Map<String, Object> getProduct(@PathVariable int productId, @PathVariable int userId) {
    Map<String, Object> map = new HashMap<>();
    String url = "http://tony-mall-provider-user/user/getUserById/" + userId;
    User user = this.restTemplate.getForEntity(url, User.class).getBody();
    Product product = this.productRepository.getByProductId(productId);
    map.put("user",user);
    map.put("product",product);
    return map;
}
可以發現調用其實都一樣,只不過URL 從IP地址改成了實例名稱了。其實這裏就是一個虛擬主機名稱。最後測試通過~ 我這裏就不貼出返回的JSON了。


六、Eureka Cilent 元數據和實例信息

Eureka Client 還可以獲得其他實例的信息:

@GetMapping("/showProvider")
public List<ServiceInstance> showInfo(){
    return this.discoveryClient.getInstances("tony-mall-provider-user");
}

返回如下的JSON:

[
  {
    "host": "192.168.28.100",
    "port": 8801,
    "uri": "http://192.168.28.100:8801",
    "serviceId": "TONY-MALL-PROVIDER-USER",
    "metadata": {},
    "secure": false,
    "instanceInfo": {
      "instanceId": "192.168.28.100:tony-mall-provider-user:8801",
      "app": "TONY-MALL-PROVIDER-USER",
      "appGroupName": null,
      "ipAddr": "192.168.28.100",
      "sid": "na",
      "homePageUrl": "http://192.168.28.100:8801/",
      "statusPageUrl": "http://192.168.28.100:8801/info",
      "healthCheckUrl": "http://192.168.28.100:8801/health",
      "secureHealthCheckUrl": null,
      "vipAddress": "tony-mall-provider-user",
      "secureVipAddress": "tony-mall-provider-user",
      "countryId": 1,
      "dataCenterInfo": {
        "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
        "name": "MyOwn"
      },
      "hostName": "192.168.28.100",
      "status": "UP",
      "leaseInfo": {
        "renewalIntervalInSecs": 30,
        "durationInSecs": 90,
        "registrationTimestamp": 1500002506247,
        "lastRenewalTimestamp": 1500002506247,
        "evictionTimestamp": 0,
        "serviceUpTimestamp": 1500002506248
      },
      "isCoordinatingDiscoveryServer": false,
      "metadata": {},
      "lastUpdatedTimestamp": 1500002506248,
      "lastDirtyTimestamp": 1500002506142,
      "actionType": "ADDED",
      "asgName": null,
      "overriddenStatus": "UNKNOWN"
    }
  }
]

除了一些服務信息之外,還看到了這個屬性metadata 這個是元數據,又服務提供者提供。以下我們嘗試在用戶服務系統的application.properties中添加元數據:

eureka.instance.metadata-map.developer=TONY
eureka.instance.metadata-map.provider_city=GZ
重新調用我們寫的showProvider接口,發現metadata已經添加相應的元數據信息:

     。。。省略。。。
      "isCoordinatingDiscoveryServer": false,
      "metadata": {
        "provider_city": "GZ",
        "developer": "TONY"
      },
      "lastUpdatedTimestamp": 1500003756538,
      。。。省略。。。


七、Eureka Server 的自我保護模式

以下摘錄於《SpringCloud和Docker微服務架構實戰》

默認情況下,如果Eureka Sever在一定時間內沒有接收到某個微服務實例的心跳信息,Eureka Server 會直接註銷該實例。但是當網絡分區發生故障時,微服務與Eureka Server之間無法通信,直接註銷微服務實例就會非常危險。服務本身而言是健康的,不應該直接註銷微服務。

Eureka Server 通過 自我保護模式 來解決這個問題。當Eureka Server 節點在短時間內丟失多個客戶端時,那麼這個節點就會進入自我保護模式。一旦進入該模式,Eureka Server 就會保護服務註冊表的信息,不會再刪除註冊表信息(不會註銷實例信息)。當網絡故障恢復後,該Eureka Server 節點會自動退出自我保護模式。

自我保護模式是一種應對網絡異常的安全保護措施。


在Spring Cloud中,可以使用以下啓用或禁用安全保護措施

eureka.server.enable-self-preservation=false

默認爲true



八、多網卡環境選擇IP

對於多個網卡的服務器,指定IP的需求非常常見。例如某臺服務器有多張網卡,但是隻有eth1可以被其他服務器訪問;如果Eureka Client將其他網卡的IP註冊到Eureka Server上,其他服務消費者將無法方位服務提供實例的服務。

各個微服務註冊到Eureka Server 上的IP可以有以下操作進行指定:

忽略指定網卡:

eureka.instance.prefer-ip-address=true
spring.cloud.inetutils.ignored-interfaces=docker0

使用正則表達式指定使用的網絡地址:

spring.cloud.inetutils.preferred-networks=192.168

我還是最喜歡這個方式,直接指定IP地址,簡單粗暴:

eureka.instance.ip-address=127.0.0.1

只使用站點的本地地址

spring.cloud.inetutils.use-only-site-local-interfaces=true



九、服務健康檢查

SpringBoot Actuator 提供了很多監控REST端點。方位這些斷點就可以獲得相應的服務運行狀況。

以下是SpringBoot Actuator 提供的端點 摘錄於SpringBoot官方文檔

ID Description Sensitive Default

actuator

Provides a hypermedia-based “discovery page” for the other endpoints. Requires Spring HATEOAS to be on the classpath.

true

auditevents

Exposes audit events information for the current application.

true

autoconfig

Displays an auto-configuration report showing all auto-configuration candidates and the reason why they ‘were’ or ‘were not’ applied. 

(顯示自動配置信息)

true

beans

Displays a complete list of all the Spring beans in your application. (顯示所有Bean信息)

true

configprops

Displays a collated list of all @ConfigurationProperties. (顯示所有@ConfigurationProperties的配置屬性列表)

true

dump

Performs a thread dump. (顯示線程活動快照)

true

env

Exposes properties from Spring’s ConfigurableEnvironment. (顯示應用的環境變量)

true

flyway

Shows any Flyway database migrations that have been applied.

true

health

Shows application health information (when the application is secure, a simple ‘status’ when accessed over an unauthenticated connection or full message details when authenticated).(顯示應用程序的健康指標,這些值由HealthIndicator的實現類提供)

false

info

Displays arbitrary application info.(顯示應用程序的新,可以用info.*屬性自定義info端點公開的數據)

false

loggers

Shows and modifies the configuration of loggers in the application. (顯示和修改Logger配置)

true

liquibase

Shows any Liquibase database migrations that have been applied.

true

metrics

Shows ‘metrics’ information for the current application.(顯示應用程序的度量標準信息)

true

mappings

Displays a collated list of all @RequestMapping paths.(顯示所有URL路徑)

true

shutdown

Allows the application to be gracefully shutdown (not enabled by default). (關閉應用 默認不啓用,如果啓用需要配置endpoints.shutdown.enabled=true)

true

trace

Displays trace information (by default the last 100 HTTP requests).(顯示跟蹤信息,默認情況下爲最近100個HTTP請求)

true


之後的筆記也會有相關Actuator的介紹,先整合到SpringCloud當中:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然後就沒有然後了,非常簡單~ 添加個依賴就將actuator整合到Spring當中。當我們啓用了Eureka之後 health接口會出現如下信息:

http://localhost:8802/product/health

{
  "description": "Remote status from Eureka server",
  "status": "DOWN"
}

註銷所有Eureka配置之後重新訪問http://localhost:8802/product/health獲得如下JSON

{"status":"UP"}


info接口會出現如下信息:

http://localhost:8802/product/info

{}

info默認沒有返回任何數據,需要我們配置info屬性來定義info公開的端點數據。

info.app.name=@project.artifactId@
info.app.encoding=@project.build.sourceEncoding@
info.app.java=@java.version@

再次調用接口:http://localhost:8802/product/info

{
  "app": {
    "name": "productsystem",
    "java": "1.8.0_121",
    "encoding": "UTF-8"
  }
}


事實上Eureka 已經集成了對實例的健康檢查


Status 還有其他取值:DOWN、OUT_OF_SERVICE 、UNKNOWN、UP

當Eureka Server 和 Eureka Client 之間使用心跳機制來確定Eureka Client 的狀態。默認情況下,如果Server 和Client 的心跳保持正常,應用程序就會始終保持UP狀態。

如果微服務器的數據源發現了問題,根本無法工作。我們希望Eureka Server 可以獲得 Client 的SpringBoot Actuator 提供的health端點,可以在Client客戶端當中的application.properties配置如下參數:

eureka.client.healthcheck.enable=true

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章