spring cloud 服務治理 - Eureka

前言

在分佈式系統領域有個著名的CAP定理:css

C——數據一致性;html

A——服務可用性;java

P——服務對網絡分區故障的容錯性。git

這三個特性在任何分佈式系統中不能同時知足,最多同時知足兩個。github

Zookeeper是著名Hadoop的一個子項目,不少場景下Zookeeper也做爲Service發現服務解決方案。Zookeeper保證的是CP,即任什麼時候刻對Zookeeper的訪問請求能獲得一致的數據結果,同時系統對網絡分割具有容錯性,可是它不能保證每次服務請求的可用性。web

而Spring Cloud Netflix在設計Eureka時遵照的就是AP原則。由於對於服務消費者來講,能消費纔是最重要的——拿到可能不正確的服務實例信息後嘗試消費一下,也好過由於沒法獲取實例信息而不去消費。因此,對於服務發現而言,可用性比數據一致性更加劇要——AP賽過CP。spring

一、服務註冊與服務發現

服務治理是微服務架構中最爲核心和基礎的模塊,主要爲各個微服務實例提供自動化註冊與發現功能。apache

服務註冊:服務治理框架會構建一個註冊中心,每一個服務向註冊中心註冊登記本身提供的服務,將服務名、主機、端口號、版本號、通訊協議等告知註冊中心,註冊中心按服務名分類組織成一個服務清單。網絡

例如:架構

有三個提供訂單服務的實例分別運行在 192.168.0.100:808一、192.168.0.101:808二、192.168.0.102:8083;

還有四個提供用戶服務的實例分別運行在 192.168.1.100:809一、192.168.1.101:809二、192.168.1.102:809三、192.168.1.103:8094;

當這些服務所有啓動併成功註冊到註冊中心上後,註冊中心會維護一份相似下面的一個服務清單:

服務名 服務地址
訂單服務 192.168.0.100:808一、192.168.0.101:808二、192.168.0.102:8083
用戶服務 192.168.1.100:809一、192.168.1.101:809二、192.168.1.102:809三、192.168.1.103:8094

 

 

 

 

服務發現:在服務治理框架下,服務之間再也不經過具體實例地址來相互調用,而是經過向註冊中心諮詢並獲取服務清單,以實現(經過服務名)對具體服務的調用。

  例如:前臺用戶下單須要調用訂單服務,首先向註冊中心發起諮詢訂單服務的請求,註冊中心返回訂單服務位置清單,而後調用方經過負載策略選擇其中某一個位置進行服務調用便可。

二、單點註冊中心

 建立一個空項目,pom.xml以下(後面都基於這個pom):

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.springcloud.demo</groupId>
  <artifactId>springcloud-demo</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <modules>
    <module>eureka-server</module>
    <module>eureka-service-provider</module>
  </modules>

  <name>Maven</name>
  <!-- FIXME change it to the project's website -->
  <url>http://maven.apache.org/</url>
  <inceptionYear>2001</inceptionYear>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.8.RELEASE</version>
    <relativePath/>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <failIfNoTests>true</failIfNoTests>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
View Code

一、服務註冊中心

首先搭建一個註冊中心,命名爲eureka-server,引入eureka依賴包

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

在 Spring Boot 啓動入口文件上加註解 @EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run( EurekaServerApplication.class, args );
    }
}

而後配置application.yml:

server:
  port: 8081

eureka:
  instance:
    hostname: eurekaserver
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: eurka-server

其中: 

eureka.client.registerWithEureka = false     設置爲false表示不向註冊中心註冊本身,默認爲true
eureka.client.fetchRegistry = false               設置爲false表示不須要去檢索服務,默認爲true

啓動應用並訪問 http://localhost:8081/ ,以下圖所示:

能夠看到註冊中心尚未註冊任何服務,至此註冊中心已經搭建完畢。

二、服務提供者

搭建好註冊中心後,咱們再來建立一個服務提供者,而後將其註冊到註冊中心。新建一個項目eureka-service-provider,添加eureka依賴,在 Spring Boot 啓動入口文件上加註解 @EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class EurekaServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run( EurekaServiceApplication.class, args );
    }
}

配置application.yml:

server:
  port: 8082

eureka:
  instance:
    hostname: service-provider
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka/

spring:
  application:
    name: service-1

由於須要向註冊中心註冊,因此 eureka.client.registerWithEureka、eureka.client.fetchRegistry 不要配置爲 false

啓動eureka-service-provider,刷新註冊中心,能夠看到服務已經註冊成功了:

同時eureka-server控制檯會打印一行日誌:Registered instance SERVICE-1/xxxx:service-1:8082 with status UP (replication=false)

三、高可用註冊中心

上面只是一個單點註冊中心,微服務場景下應用經過註冊中心來訪問真實服務,若是註冊中心掛了會形成服務沒法調用,因此註冊中心也得要保持高可用,Eureka 不可能沒有想到這一點,其實在Eureka裏,全部結點既是服務提供方,又是服務消費方,註冊中心也不例外。

你們還記得在單節點配置裏講到的這兩個配置嗎:

eureka.client.registerWithEureka = false

eureka.client.fetchRegistry = false

實際上 Eureka 高可用方案就是將本身做爲服務向其餘服務註冊中心註冊本身,這樣就能夠造成一組相互註冊的服務註冊中心,在這組服務註冊中心內部相互同步註冊清單,造成一個高可用集羣

註冊中心集羣

建立如下三個Eureka Server:peer一、peer二、peer3

peer1的配置以下(peer二、peer3配置相似):

server:
  port: 8081

eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2:8082/eureka/,http://peer3:8083/eureka/

spring:
  application:
    name: eurka-server

分別啓動peer一、peer二、peer3,訪問peer1:8081

單點故障

這時候若是peer2忽然掛了,訪問peer1和peer3仍然能夠看到peer2,這是由於Eureka默認開啓了自我保護機制(peer2掛了沒有剔除),能夠經過設置 eureka.server.enable-self-preservation=false 來禁用保護

peer1的配置文件裏新增eureka.server.enable-self-preservation=false設置,而後模擬peer3掛了,peer1註冊中心以下:

大概兩分鐘左右,從peer1註冊中心能夠看到 registered-replicas 有3個,unavailable-replicas 裏有 peer3,available-replicas 裏只有 peer1 和 peer2 可用,

而從 peer2 裏看 peer3 仍然可用(過比較長的時間,peer2 仍然會將 peer3 從 available-replicas 裏剔除)

將serverce-1註冊到註冊中心peer1,而後在peer1 和 peer2裏均可以看到service-1。

故障恢復

peer3 通過運維處理恢復了,從新啓動peer3自動加入了peer1和peer2集羣,可用看到service-1也自動註冊到peer3上了:

四、配置

服務註冊相關配置:eureka.instance 爲前綴對應的Class

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean 

服務實例相關配置:eureka.client 爲前綴對應的Class

org.springframework.cloud.netflix.eureka.EurekaClientConfigBean

服務配置屬性以eureka.server爲前綴對應的Class

org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean

client常見配置

# 啓用Eureka客戶端
eureka.client.enabled=true
# 從Eureka服務端獲取註冊信息的間隔時間(單位:秒)
eureka.client.registry-fetch-interval-seconds=30
# 是否從Eureka服務端獲取註冊信息
eureka.client.fetch-registry=true
# 是否要將自身的實例信息註冊到Eureka服務端
eureka.client.register-with-eureka=true
# 初始化實例信息的變化到Eureka服務端的間隔時間(單位:秒)
eureka.client.instance-info-replication-interval-seconds=40
# 從Eureka客戶端到Eureka服務端的鏈接總數
eureka.client.eureka-server-total-connections=200
# 獲取實例時是否過濾,僅保留UP狀態的實例
eureka.client.filter-only-up-instances=true

server常見配置

#設爲false,關閉自我保護
eureka.server.enable-self-preservation=false
#表示是否將本身註冊到Eureka Server,默認爲true
eureka.client.register-with-eureka=false
#表示是否從Eureka Server獲取註冊信息,默認爲true
eureka.client.fetch-registry=false
# 掃描失效服務的間隔時間(單位毫秒,默認是60*1000)即60秒
eureka.server.eviction-interval-timer-in-ms=5000
#設置 eureka server同步失敗的等待時間 默認 5分
#在這期間,它不向客戶端提供服務註冊信息
eureka.server.wait-time-in-ms-when-sync-empty=5
#設置 eureka server同步失敗的重試次數 默認爲 5 次
eureka.server.number-of-replication-retries=5
#自我保護係數(默認0.85)
eureka.server.renewal-percent-threshold=0.85

instance常見配置

#是否優先使用IP地址做爲主機名的標識,若是不配置就是機器的主機名
eureka.instance.prefer-ip-address=false
#Eureka客戶端向服務的發送心跳的時間間隔(單位:秒)
eureka.instance.lease-renewal-interval-in-seconds=30
#Eureka服務的收到最後一次心跳以後等待的時間上限(單位:秒),
#超過這個時間以後會將該服務實例從註冊中心清單裏剔除
eureka.instance.lease-expiration-duration-in-seconds=90

附錄

  本文Demo地址

  Spring Cloud Netflix官方文檔

  Spring Cloud 中文社區

  spring-cloud-book

服務治理 

SpringCloudLesson

更多配置參考

相關文章
相關標籤/搜索