1. 程式人生 > 實用技巧 >SpringCloud之Eureka註冊中心

SpringCloud之Eureka註冊中心

Eureka為什麼出現?

微服務user-service對外提供服務,需要對外暴露自己的地址。而consumer(呼叫者)需要記錄服務提供者的地址。將來地址出現變更,還需要及時更新。這在服務較少的時候並不覺得有什麼,但是在現在日益複雜的網際網路環境,一個專案肯定會拆分出十幾,甚至數十個微服務。此時如果還人為管理地址,不僅開發困難,將來測試、釋出上線都會非常麻煩,這與DevOps的思想是背道而馳的。

Eureka做什麼?

Eureka負責管理、記錄服務提供者的資訊。服務呼叫者無需自己尋找服務,而是把自己的需求告訴Eureka,然後Eureka會把符合你需求的服務告訴你。

同時,服務提供方與Eureka之間通過“心跳”

機制進行監控,當某個服務提供方出現問題,Eureka自然會把它從服務列表中剔除。

這就實現了服務的自動註冊、發現、狀態監控。

Eureka實現原理圖

  • Eureka:就是服務註冊中心(可以是一個叢集),對外暴露自己的地址

  • 提供者:啟動後向Eureka註冊自己資訊(地址,提供什麼服務)

  • 消費者:向Eureka訂閱服務,Eureka會將對應服務的所有提供者地址列表傳送給消費者,並且定期更新

  • 心跳(續約):提供者定期通過http方式向Eureka重新整理自己的狀態


案例(微服務基於SpringBoot):

1、msg-server微服務:

MsgController:

package
com.itcast.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @Classname MsgController * @Description TODO * @Date 2020/12/18 10:24 * @Created by Administrator
*/ @Controller public class MsgController { @RequestMapping("hello") @ResponseBody public String hello(){ return "hello spring-cloud~"; } }

application.yml:

server:
  port: 8888
spring:
  application:
    name: msg-server
eureka:
  client:
    service-url:
      defaultZone:  http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka

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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.itcast</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>msg-server</artifactId>


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

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

啟動類:

package com.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @Classname MsgApplication
 * @Description TODO
 * @Date 2020/12/18 10:09
 * @Created by Administrator
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ServerApplication {

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

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

2、msg-consumer微服務:

MsgController:

package com.itcast.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @Classname MsgController
 * @Description TODO
 * @Date 2020/12/18 10:21
 * @Created by Administrator
 */
@Controller
public class MsgController {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    DiscoveryClient discoveryClient;

    @RequestMapping("hello")
    @ResponseBodypublic String hello(){
        List<ServiceInstance> instances = discoveryClient.getInstances("msg-server");
        ServiceInstance serviceInstance = instances.get(0);
        String url="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/hello";
        String forObject = restTemplate.getForObject(url, String.class);
        return forObject;
    }
}

application.yml

server:
  port: 8080
spring:
  application:
    name: msg-consumer
eureka:
  client:
    service-url:
      defaultZone:  http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka

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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.itcast</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>msg-consumer</artifactId>

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

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


</project>

啟動類:

package com.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @Classname Application
 * @Description TODO
 * @Date 2020/12/18 10:19
 * @Created by Administrator
 */
//@EnableDiscoveryClient
//@SpringBootApplication
//@EnableHystrix
    @SpringCloudApplication
public class ConsumerApplication {

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

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

3、Eureka註冊中心

啟動類:

package com.itcast;
//import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @Classname EurekaApplication
 * @Description TODO
 * @Date 2020/12/18 11:29
 * @Created by Administrator
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class);
    }
}

application.yml

server:
  port: 10086
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10087/eureka
#    fetch-registry: false
#    register-with-eureka: false

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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.itcast</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

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


</project>

Eureka架構中的三個核心角色

  • 服務註冊中心

    Eureka的服務端應用,提供服務註冊和發現功能

  • 服務提供者

    提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現,只要對外提供的是Rest風格服務即可。

  • 服務消費者

    消費應用從註冊中心獲取服務列表,從而得知每個服務方的資訊,知道去哪裡呼叫服務方。

高可用的Eureka Server

  Eureka Server即服務的註冊中心,在剛才的案例中,我們只有一個EurekaServer,事實上EurekaServer也可以是一個叢集,形成高可用的Eureka中心。

服務同步:

  多個Eureka Server之間也會互相註冊為服務,當服務提供者註冊到Eureka Server叢集中的某個節點時,該節點會把服務的資訊同步給叢集中的每個節點,從而實現資料同步。因此,無論客戶端訪問到Eureka Server叢集中的任意一個節點,都可以獲取到完整的服務列表資訊。

  所謂的高可用註冊中心,其實就是把EurekaServer自己也作為一個服務進行註冊,這樣多個EurekaServer之間就能互相發現對方,從而形成叢集。

多個Eureka之間的配置

Eureka1:

Eureka2:

服務續約(心跳)配置

eureka:
  instance:
    lease-expiration-duration-in-seconds: 90
    lease-renewal-interval-in-seconds: 30
  • lease-renewal-interval-in-seconds:服務續約(renew)的間隔,預設為30秒

  • lease-expiration-duration-in-seconds:服務失效時間,預設值90秒

  也就是說,預設情況下每個30秒服務會向註冊中心傳送一次心跳,證明自己還活著。如果超過90秒沒有傳送心跳,EurekaServer就會認為該服務宕機,會從服務列表中移除,這兩個值在生產環境不要修改,預設即可。

獲取服務列表

  當服務消費者啟動是,會檢測eureka.client.fetch-registry=true引數的值,如果為true,則會從Eureka Server服務的列表只讀備份,然後快取在本地。並且每隔30秒會重新獲取並更新資料。我們可以通過下面的引數來修改:

eureka:
  client:
    registry-fetch-interval-seconds: 5

失效剔除

  有些時候,我們的服務提供方並不一定會正常下線,可能因為記憶體溢位、網路故障等原因導致服務無法正常工作。Eureka Server需要將這樣的服務剔除出服務列表。因此它會開啟一個定時任務,每隔60秒對所有失效的服務(超過90秒未響應)進行剔除。

  可以通過eureka.server.eviction-interval-timer-in-ms引數對其進行修改,單位是毫秒,生成環境不要修改。

自我保護

我們關停一個服務,就會在Eureka面板看到一條警告:

  這是觸發了Eureka的自我保護機制。當一個服務未按時進行心跳續約時,Eureka會統計最近15分鐘心跳失敗的服務例項的比例是否超過了85%。在生產環境下,因為網路延遲等原因,心跳失敗例項的比例很有可能超標,但是此時就把服務剔除列表並不妥當,因為服務可能沒有宕機。Eureka就會把當前例項的註冊資訊保護起來,不予剔除。生產環境下這很有效,保證了大多數服務依然可用。

  但是這給我們的開發帶來了麻煩, 因此開發階段我們都會關閉自我保護模式:

eureka:
  server:
    enable-self-preservation: false # 關閉自我保護模式(預設為開啟)
    eviction-interval-timer-in-ms: 1000 # 掃描失效服務的間隔時間(預設為60*1000ms)