1. 程式人生 > >SpringCloud---(4)Eureka服務發現元件

SpringCloud---(4)Eureka服務發現元件

 

Eureka簡介

Eureka是Netflix開發的服務發現框架,本身是一個基於REST的服務,主要用於定位執行在AWS域中的中間層服務,以達到負載均衡和中間層服務故障轉移的目的。SpringCloud將它整合在其子專案spring-cloud-netflix中,以實現Spring Cloud的服務發現功能。

Eureka與Spring Boot構建的微服務很容易整合起來。

Eureka包含了服務端和客戶端元件。

1.  服務端元件也被稱為服務註冊中心,用於提供服務的註冊與發現。Eureka支援高可用的配置,當叢集有分片出現故障時,Eureka就會轉入自動保護模式,它允許分片故障期間繼續提供服務的發現和註冊,當故障分片恢復正常時,叢集中其他分片會把他們的狀態再次同步回來。

2.  客戶端元件包含服務消費者和服務提供者。在應用程式執行中,Eureka客戶端向註冊中心自身提供的服務並週期性的傳送心跳來更新它的服務租約,同時也可以從服務端查詢當前註冊的服務資訊並把他們快取到本地並週期性的重新整理服務狀態。

Eureka原理

Region和Zone的關係

 

Application Service 就相當於本書中的服務提供者(使用者微服務),application client就相當於本書中的服務消費者(電影微服務)。

make remote call,可以簡單理解為呼叫RESTful的介面。

us-east-1c、us-east-1dd等是Zone,它們都屬於es-east-1這個region;

由圖可知,eureka包含兩個元件:Eureka Server和Eureka Client。

Eureka Server提供服務註冊服務,各個節點啟動後,會在Eureka Server中進行註冊,這樣Eureka Server中服務登錄檔中將會儲存所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀的看到。

Eureka Client是一個Java客戶端,用於簡化與Eureka Server的互動,客戶端同時也具備一個內建的、使用輪詢(round-robin)負載演算法的負載均衡器。

在應用啟動後,將會向Eureka Server傳送心跳(預設週期為30秒)。如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,Eureka Server將會從服務登錄檔中把這個服務節點移除(預設90秒)。

Eureka Server之間將會通過複製的方式完成資料的同步。

Eureka還提供了客戶端快取的機制,即使所有的Eureka Server都掛掉,客戶端依然可以利用快取中的資訊消費其他服務的API。

實現Eureka Server

將Eureka Server和Eureka Client放到同一個moduls中,這個大pom.xml作為配置管理其他Server和client。

大pom.xml

<?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.kevin.cloud</groupId>

   <artifactId>microservice-spring-cloud</artifactId>

   <version>0.0.1-SNAPSHOT</version>

   <packaging>pom</packaging>

   
   <modules>

      <module>microservice-consumer-movie</module>

      <module>microservice-provider-user</module>

      <module>microservice-discovery-eureka</module>

   </modules>


   <properties>

      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

      <java.version>1.8</java.version>

   </properties>


   <parent>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-parent</artifactId>

      <version>1.4.1.RELEASE</version>

   </parent>


   <dependencyManagement>

      <dependencies>

         <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-dependencies</artifactId>

            <version>Camden.SR1</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>


</project>

pom.xml

<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>


    <parent>

        <groupId>com.kevin.cloud</groupId>

        <artifactId>microservice-spring-cloud</artifactId>

        <version>0.0.1-SNAPSHOT</version>

        <relativePath/>

    </parent>


    <artifactId>microservice-discovery-eureka</artifactId>

    <packaging>jar</packaging>


    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <java.version>1.8</java.version>

    </properties>


    <dependencies>

        <!-- Eureka的依賴包 -->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-eureka-server</artifactId>

        </dependency>

        <!-- 安全模組 -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-security</artifactId>

        </dependency>

    </dependencies>


</project>

application.yml

security:

  basic:

    enabled: true

  user:

    name: kevin

    password: 123456

server:

  port: 8761  #指定服務埠

eureka:

  client:

    healthcheck:

      enabled: true

    register-with-eureka: false #是否將eureka自身作為應用註冊到eureka註冊中心

    fetch-registry: false  #為true時,可以啟動,但報異常caonot execute request on any know server

    service-url:

      defaultZone: http://kevin:[email protected]:8761/eureka

EurekaApplication.java

package com.kevin.cloud;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;



/**

 *

 * @title   EurekaServer註冊中心

 * @description

 * @author caonanqing

 * @createDate 2018/11/7

 * @version 1.0

 */

@SpringBootApplication  //設為springboot

@EnableEurekaServer     //實現服務發現,註冊

public class EurekaApplication {


    public static void main(String[] args) {

        SpringApplication.run(EurekaApplication.class, args);

        System.out.println("EurekaServer啟動...");

    }


}

實現Eureka Client(提供者)

pom.xml

<?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>


   <artifactId>microservice-provider-user</artifactId>

   <packaging>jar</packaging>


   <name>microservice-provider-user</name>

   <description>Demo project for Spring Boot</description>


   <parent>

      <groupId>com.kevin.cloud</groupId>

      <artifactId>microservice-spring-cloud</artifactId>

      <version>0.0.1-SNAPSHOT</version>

      <relativePath/>

   </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-data-jpa</artifactId>

      </dependency>

      <dependency>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-web</artifactId>

      </dependency>

      <dependency>

         <groupId>com.h2database</groupId>

         <artifactId>h2</artifactId>

         <scope>runtime</scope>

      </dependency>


      <dependency>

         <groupId>org.springframework.cloud</groupId>

         <artifactId>spring-cloud-starter-eureka</artifactId>

      </dependency>


      <dependency>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-actuator</artifactId>

      </dependency>

   </dependencies>


</project>

application.yml

server:

  port: 7900

spring:

  jpa:

    generate-ddl: false

    show-sql: true

    hibernate:

      ddl-auto: none

  datasource:

    platform: h2

    schema: classpath:schema.sql

    data: classpath:data.sql

  application:

    name: microservice-provider-user

logging:

  level:

    root: INFO

    org.hibernate: INFO

    org.hibernate.type.descriptor.sql.BasicBinder: TRACE

    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE

    com.cloud: DEBUG

eureka:

  client:

    #註冊中心地址

    service-url:

      defaultZone: http://kevin:[email protected]:8761/eureka/

  #instance:

    #prefer-ip-address: true

    #instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}

schema.sql

drop table if exists user;

create table user(

  id int not null auto_increment,

  username varchar(40),

  name varchar(20),

  age int(3),

  balance decimal (10,2),

  primary key(id)

);

data.sql

insert into user(id,username,name,age,balance) values(1,'user1','張三',20,100.00)

insert into user(id,username,name,age,balance) values(2,'user2','李四',20,100.00)

insert into user(id,username,name,age,balance) values(3,'user3','王五',20,100.00)

insert into user(id,username,name,age,balance) values(4,'user4','馬六',20,100.00)

MicroserviceSimpleProviderUserApplication .java

package com.keivn.cloud;


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;


/**

 *

 * @title   服務提供者

 * @description

 * @author caonanqing

 * @createDate 2018/11/7

 * @version 1.0

 */

@SpringBootApplication

@EnableEurekaClient

public class MicroserviceSimpleProviderUserApplication {

   public static void main(String[] args) {

      SpringApplication.run(MicroserviceSimpleProviderUserApplication.class, args);

      System.out.println("服務提供者啟動...");

   }

}

UserController.java

package com.keivn.cloud.controller;

import com.keivn.cloud.entity.User;

import com.keivn.cloud.repository.UserRepository;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RestController;

import com.netflix.appinfo.InstanceInfo;

import com.netflix.discovery.EurekaClient;


/**

 *

 * @title

 * @description

 *  作用:

 *  1:測試服務例項的相關內容

 *  2:為後來的服務做提供

 * @author caonanqing

 * @createDate 2018/11/6

 * @version 1.0

 */

@RestController

public class UserController {

    @Autowired

    private UserRepository userRepository;

    @Autowired

    private EurekaClient eurekaClient;

    @Autowired

    private DiscoveryClient discoveryClient;

    @GetMapping("/simple/{id}")

    public User findById(@PathVariable Long id ){

        return this.userRepository.findOne(id);

    }

    @GetMapping("/eureka-instance")

    public String serviceUrl() {

        InstanceInfo instanceInfo = this.eurekaClient.getNextServerFromEureka("MICROSERVICE-PROVIDER-USER", false);

        return instanceInfo.getHomePageUrl();

    }

    @GetMapping("/instance-info")

    public ServiceInstance showInfo(){

        ServiceInstance localServiceInstance = this.discoveryClient.getLocalServiceInstance();

        return localServiceInstance;

    }

}

User.java

package com.keivn.cloud.entity;

import javax.persistence.*;

import java.io.Serializable;

import java.math.BigDecimal;

/**

 *

 * @title

 * @description

 * @author caonanqing

 * @createDate 2018/11/6

 * @version 1.0

 */

@Entity

public class User implements Serializable {


    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    private Long id;

    @Column

    private String username;

    @Column

    private String name;

    @Column

    private Short age;

    @Column

    private BigDecimal balance;

    public User() {

    }

    public User(String username, String name, Short age, BigDecimal balance) {

        this.username = username;

        this.name = name;

        this.age = age;

        this.balance = balance;

    }

    public Long getId() {

        return id;

    }

    public void setId(Long id) {

        this.id = id;

    }

    public String getUsername() {

        return username;

    }

    public void setUsername(String username) {

        this.username = username;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public Short getAge() {

        return age;

    }

    public void setAge(Short age) {

        this.age = age;

    }

    public BigDecimal getBalance() {

        return balance;

    }

    public void setBalance(BigDecimal balance) {

        this.balance = balance;

    }

}

UserRepository.java

package com.keivn.cloud.repository;


import com.keivn.cloud.entity.User;

import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;


/**

 *

 * @title

 * @description

 * @author caonanqing

 * @createDate 2018/11/6

 * @version 1.0

 */

@Repository

public interface UserRepository extends JpaRepository<User, Long> {

}

Eureka Client(消費者)

pom.xml

<?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>

   <artifactId>microservice-consumer-movie</artifactId>

   <packaging>jar</packaging>

   <parent>

      <groupId>com.kevin.cloud</groupId>

      <artifactId>microservice-spring-cloud</artifactId>

      <version>0.0.1-SNAPSHOT</version>

      <relativePath/>

   </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.cloud</groupId>

         <artifactId>spring-cloud-starter-eureka</artifactId>

      </dependency>

      <dependency>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-actuator</artifactId>

      </dependency>

   </dependencies>

</project>

application.yml

server:

  port: 7901

user:

  userServicePath: http://localhost:7900/simple/

spring:

  application:

    name: microservice-consumer-movie

eureka:

  client:

    healthcheck:

      enabled: true

    service-url:

      defaultZone: http://kevin:[email protected]:8761/eureka

  instance:

    prefer-ip-address: true

EurekaClientApplication.java

package com.keivn.cloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.context.annotation.Bean;

import org.springframework.web.client.RestTemplate;


/**

 *

 * @title   服務消費者

 * @description

 * @author caonanqing

 * @createDate 2018/11/7

 * @version 1.0

 */

@SpringBootApplication

@EnableEurekaClient    //註冊到Eureka

public class MicroserviceSimpleConsumerUserApplication {


   @Bean

   public RestTemplate restTemplate(){

      return new RestTemplate();

   }

   public static void main(String[] args) {

      SpringApplication.run(MicroserviceSimpleConsumerUserApplication.class, args);

      System.out.println("服務消費者啟動...");

   }

}

MovieController.java

package com.keivn.cloud.controller;


import com.keivn.cloud.entity.User;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;


/**

 *

 * @title

 * @description

 * @author caonanqing

 * @createDate 2018/11/7

 * @version 1.0

 */

@RestController

public class MovieController {


    @Autowired

    private RestTemplate restTemplate;


    @Value("${user.userServicePath}")

    private String userServicePath;


    @GetMapping(value = "/movie/{id}")

    public User finById(@PathVariable long id ){

        return this.restTemplate.getForObject(this.userServicePath + id, User.class);

    }

}

User.java

package com.keivn.cloud.entity;


import java.io.Serializable;

import java.math.BigDecimal;


/**

 *

 * @title

 * @description

 * @author caonanqing

 * @createDate 2018/11/7

 * @version 1.0

 */

public class User implements Serializable {

    private Long id;

    private String username;

    private String name;

    private Short age;

    private BigDecimal balance;

    public User() {

    }

    public User(Long id, String username, String name, Short age, BigDecimal balance) {

        this.id = id;

        this.username = username;

        this.name = name;

        this.age = age;

        this.balance = balance;

    }

    public Long getId() {

        return id;

    }

    public void setId(Long id) {

        this.id = id;

    }

    public String getUsername() {

        return username;

    }

    public void setUsername(String username) {

        this.username = username;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public Short getAge() {

        return age;

    }

    public void setAge(Short age) {

        this.age = age;

    }

    public BigDecimal getBalance() {

        return balance;

    }

    public void setBalance(BigDecimal balance) {

        this.balance = balance;

    }

}