Spring Cloud服務治理之Eureka

什么是服務治理

主要是用來實現(xiàn)各個微服務實例的自動化注冊與發(fā)現(xiàn),解決隨著微服務的增加,靜態(tài)配置變得越來越難以維護的問題.

服務注冊

1. 維護注冊

維護一個類似下面的清單


image.png
2. 服務發(fā)現(xiàn)

向注冊中心發(fā)起咨詢服務請求,以獲取某個服務可用的位置清單 ,再以客戶端負載均衡的方式調用.

搭建服務注冊中心

  1. 添加POM依賴

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

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

        <!--<dependency>-->
            <!--<groupId>org.springframework.boot</groupId>-->
            <!--<artifactId>spring-boot-starter-actuator</artifactId>-->
        <!--</dependency>-->
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</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>
        </plugins>
    </build>
  1. 通過 @EnableEurekaServer 啟動一個服務注冊中心
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}
  1. 配置幾個配置,如,禁用客戶端注冊行為
eureka.instance.hostname=localhost

# 關閉保護機制
#eureka.server.enable-self-preservation=false
# false代表不向注冊中心注冊自己
eureka.client.register-with-eureka=false
#false代表不需要去檢索服務,因為自己就是維護服務
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

啟動看一下界面
image.png

注冊服務提供者

  1. 修改pom文件

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

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

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

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</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>
        </plugins>
    </build>
  1. 修改啟動類,添加@EnableDiscoveryClient,激活Eureka的實現(xiàn)
@EnableDiscoveryClient
@SpringBootApplication
public class HelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }

}
  1. 修改配置
#配置服務名稱
spring.application.name=hello-service
#指定服務注冊中心的位置
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

啟動結果


image.png

搭建高可用注冊中心

原理是搭建兩臺注冊中心,然后分別把自己作為客戶端服務向對方注冊,對方就把自己當成服務.

  1. 添加配置application-peer1.properties,內容如下:
spring.application.name=eureka-server
server.port=1111
eureka.instance.hostname=peer1

eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/

2.添加配置application-peer2.properties,內容如下:

spring.application.name=eureka-server
server.port=1112
eureka.instance.hostname=peer2

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
  1. 其他的配置不變,然后我們部署兩臺注冊中心,啟動命令如下
    java -jar eureka-server-ha-1.0.0.jar --spring.profiles.active=peer1
    java -jar eureka-server-ha-1.0.0.jar --spring.profiles.active=peer2
  2. 向高可用的注冊中心注冊服務
    修改上面的工程配置文件如下:
#eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
  • 查看結果

image.png

image.png

我們這時訪問一下剛剛的接口
http://localhost:8082/hello1?name=zzj
發(fā)現(xiàn)沒有問題.
這時再把peer2殺掉.再訪問,也是沒有問題的.同時在peer1的后臺中可以看到如下報錯:
image.png

peer1上也顯示peer2也為不可用服務
image.png

peer1在不停的嘗試連接peer2
至此,我們實現(xiàn)了注冊中心的高可用.
我們再啟動一下peer2,觀察peer1的報錯停止了.出現(xiàn)了以下的信息,

image.png

同時訪問peer2也能訪問了.
如果不想用主機名來定義注冊中心,也可以使用IP地址的形式.修改配置如下:
eureka.instance.prefer-ip-address=true
默認為false

服務的發(fā)現(xiàn)與消費

服務的發(fā)現(xiàn)是由eureka完成,消費是由Ribbon完成,Ribbon可以通過客戶端配置的ribbonServerList服務端列表去輪詢以達到負載均衡的效果
ribbonServerListDiscoveryEnabledNIWSServerList重寫
NIWSDiscoveryPing取代IPing

  1. 啟動之前的eureka-server以及hello-service服務,如下:
java -jar hello-service-eureka-1.3.7.RELEASE.jar --server.port=8083
java -jar hello-service-eureka-1.3.7.RELEASE.jar --server.port=8082
image.png
image.png
創(chuàng)建ribbon-customer工程
  1. 添加依賴
    <name>ribbon-consumer</name>
    <description>Demo project for Spring Boot</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

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

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

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-hystrix-amqp</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</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>
        </plugins>
    </build>

  1. 添加注解@EnableDiscoveryClient以獲得服務發(fā)現(xiàn)能力,@LoadBalanced開啟客戶端的負載均衡,代碼如下
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

}

3.創(chuàng)建Controller,實現(xiàn)/ribbon-consumer1接口
代碼如下:

    @Autowired
    RestTemplate restTemplate;

    @RequestMapping(value="/ribbon-consumer1",method = RequestMethod.GET)
    public String helloConsumer1() {
        return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
    }

地址用服務名


image.png
  1. 修改application.properties,啟動服務
spring.application.name=ribbon-consumer
server.port=9000

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/

image.png

訪問 http://localhost:9000/ribbon-consumer1 會發(fā)現(xiàn)兩個服務提供者的后臺會交替顯示訪問日志:
image.png

image.png

Eureka基礎架構

image.png
  • 服務注冊中心

    • 失效剔除
    • 自我保護
      Eureka Server在運行期間, 會統(tǒng)計心跳失敗的比例在15分鐘之內是否低于85%(在單機調試的時候很容易滿足)

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

對此可以修改eureka.server.enable-self-preservation=false默認為true
true的意思是Eureka會將當前的實例信息保護起來,讓這些實例不過期.

客戶端對于此問題必須要有容錯機制,比如:請求重試,斷路器等機制

  • 服務提供者

    • 服務注冊,啟動時注冊,Eureka保存在一個雙層結構的Map中
    • 服務同步
      只要向其中一臺Eureka注冊,另一臺就會自動同步到另外一臺

peer1的發(fā)現(xiàn)方式

2017-12-03 17:47:13.807 INFO 7336 --- [nio-1111-exec-5] c.n.e.registry.AbstractInstanceRegistry : Registered instance RIBBON-CONSUMER/loca
lhost:ribbon-consumer:9000 with status UP (replication=false)

peer2的發(fā)現(xiàn)日志

2017-12-03 17:47:14.913 INFO 19480 --- [nio-1112-exec-5] c.n.e.registry.AbstractInstanceRegistry : Registered instance RIBBON-CONSUMER/loc
alhost:ribbon-consumer:9000 with status UP (replication=true)
一個 replication=false 另一個 replication=true . 說明peer2是通過peer1同步過來的

  • 服務續(xù)約(renew)
#定義服務續(xù)約任務的調用間隔時間
eureka.instance.lease-renewal-interval-in-seconds=30
#定義服務失效的時間
eureka.instance.lease-expiration-duration-in-seconds=90
  • 服務消費者

    有Ribbon 和 Feign
    很多時候,客戶端即使服務提供者也是服務消費者
    • 獲取服務
      確保 eureka.client.fetch-registrytrue
      修改緩存清單的更新時間eureka.client.registry-fetch-interval-seconds=30
    • 服務調用
      Ribbon會默認采取輪詢的方式進行調用
      對訪問實例的選擇,Eureka有 RegionZone 的概念
      1. 一個Region包含多個Zone
      2. 在服務調用的時候,優(yōu)先訪問同一個Zone中的服務提供方
    • 服務下線

源碼分析

@EnableDiscoveryClient

image.png

EurekaDiscoveryClient
EndpointUtils.getServiceUrlsFromConfig-->eureka.client.service-url.defaultZone=
eureka.client.region= 指定region
eureka.client.availability-zones=指定zone
通過對Zone的定義,配合實際部署的物理結構,可以設計出對區(qū)域性故障的容錯集群

服務注冊

服務獲取

服務續(xù)約

服務注冊中心

InstanceRegistry.register

配置詳解

  • Eureka服務端的配置可查看 EurekaServerConfigBean
  • Eureka客戶端的配置

服務注冊類配置

參數(shù)名 說明 默認值
registryFetchIntervalSeconds Indicates how often(in seconds) to fetch the registry information from the eureka server 30
instanceInfoReplicationIntervalSeconds Indicates how often(in seconds) to replicate instance changes to be replicated to the eureka server 30
initialInstanceInfoReplicationIntervalSeconds Indicates how long initially (in seconds) to replicate instance info to the eureka server 40
eurekaServiceUrlPollIntervalSeconds Indicates how often(in seconds) to poll for changes to eureka server information.Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it. 300
eurekaServerReadTimeoutSeconds Indicates how long to wait (in seconds) before a read from eureka server needs to timeout. 8
eurekaServerConnectTimeoutSeconds Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout 5
eurekaServerTotalConnections Gets the total number of connections that is allowed from eureka client to all eureka servers. 200
eurekaServerTotalConnectionsPerHost Gets the total number of connections that is allowed from eureka client to a eureka server host. 50
eurekaConnectionIdleTimeoutSeconds Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed 30
heartbeatExecutorThreadPoolSize The thread pool size for the heartbeatExecutor to initialise with 2
heartbeatExecutorExponentialBackOffBound Heartbeat executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred.心跳超時延遲時間的最大乘數(shù)值 10
cacheRefreshExecutorThreadPoolSize The thread pool size for the cacheRefreshExecutor to initialise with 2
cacheRefreshExecutorExponentialBackOffBound Cache refresh executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred緩存刷新重試 延遲時間的最大乘數(shù)值 10
useDnsForFetchingServiceUrls Indicates whether the eureka client should use the DNS mechanism to fetch a list of eureka servers to talk to false
registerWithEureka Indicates whether or not this instance should register its information with eureka server for discovery by others. true
preferSameZoneEureka Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason true
filterOnlyUpInstances Indicates whether to get the applications after filtering the applications for instances with only InstanceStatus UP states true
fetchRegistry Indicates whether this client should fetch eureka registry information from eureka server. true

EurekaClientConfigBean
服務注冊中心加入安全校驗

參數(shù)名 說明 默認值
registryFetchIntervalSeconds Indicates how often(in seconds) to fetch the registry information from the eureka server 30
instanceInfoReplicationIntervalSeconds Indicates how often(in seconds) to replicate instance changes to be replicated to the eureka server 30
initialInstanceInfoReplicationIntervalSeconds Indicates how long initially (in seconds) to replicate instance info to the eureka server 40
eurekaServiceUrlPollIntervalSeconds Indicates how often(in seconds) to poll for changes to eureka server information.Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it. 300
eurekaServerReadTimeoutSeconds Indicates how long to wait (in seconds) before a read from eureka server needs to timeout. 8
eurekaServerConnectTimeoutSeconds Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout 5
eurekaServerTotalConnections Gets the total number of connections that is allowed from eureka client to all eureka servers. 200
eurekaServerTotalConnectionsPerHost Gets the total number of connections that is allowed from eureka client to a eureka server host. 50
eurekaConnectionIdleTimeoutSeconds Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed 30
heartbeatExecutorThreadPoolSize The thread pool size for the heartbeatExecutor to initialise with 2
heartbeatExecutorExponentialBackOffBound Heartbeat executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred.心跳超時延遲時間的最大乘數(shù)值 10
cacheRefreshExecutorThreadPoolSize The thread pool size for the cacheRefreshExecutor to initialise with 2
cacheRefreshExecutorExponentialBackOffBound Cache refresh executor exponential back off related property. It is a maximum multiplier value for retry delay, in case where a sequence of timeouts occurred緩存刷新重試 延遲時間的最大乘數(shù)值 10
useDnsForFetchingServiceUrls Indicates whether the eureka client should use the DNS mechanism to fetch a list of eureka servers to talk to false
registerWithEureka Indicates whether or not this instance should register its information with eureka server for discovery by others. true
preferSameZoneEureka Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason true
filterOnlyUpInstances Indicates whether to get the applications after filtering the applications for instances with only InstanceStatus UP states true
fetchRegistry Indicates whether this client should fetch eureka registry information from eureka server. true

服務實例類配置

EurekaInstanceConfigBeaneureka.instance開頭

元數(shù)據(jù)

InstanceInfo 中的private volatile Map<String, String> metadata = new ConcurrentHashMap<String, String>()是自定義元數(shù)據(jù)信息,其他的標準化的元數(shù)據(jù)信息

  1. 配置自定義元數(shù)據(jù)
#自定義元數(shù)據(jù)配置
eureka.instance.metadata-map.zone=shanghai
  1. 配置標準化元數(shù)據(jù)
    eureka.instance.<EurekaInstanceConfigBean中的屬性> = <value>
實例名配置

隨機端口配置

eureka.instance.instance-id=${spring.application.name}:${random.int}

上面配置能夠實現(xiàn)在同一臺主機上,不指定端口就能啟動多個實例的效果

端點配置

確保/info和/health是有效的
1.當修改了management.context-path時需要修改端點

# 端點配置
management.context-path=/hello
eureka.instance.statusPageUrlPath=${management.context-path}/info
eureka.instance.healthCheckUrlPath=${management.context-path}/health
  1. 為了安全考慮
endpoints.info.path=appInfo
endpoints.health.path=healthInfo
eureka.instance.statusPageUrlPath=/${endpoints.info.path}
eureka.instance.healthCheckUrlPath=/${endpoints.health.path}
  1. HTTPS的端點配置
#HTTPS的端點配置
eureka.instance.status-page-url=https://${eureka.instance.hostname}/info
eureka.instance.health-check-url=https://${eureka.instance.hostname}/health
eureka.instance.home-page-url=https://${eureka.instance.hostname}
健康檢測

心跳方式的健康檢查不能說明服務是可用的,因為服務可能還依賴一些數(shù)據(jù)庫等,所以我們需要用/health端點來實現(xiàn)更全面的健康維護,步驟如下:

  1. 添加jar包至服務提供者
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  1. 在application.properties中添加配置
# 健康檢查
#eureka.client.healthcheck.enabled=true
  1. 保證/health端點路徑是有效的
    就是確保 eureka.instance.health-check-url 是有效訪問的,具體可參考上面的端點配置
其他配置
image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容