SpringCloud2.x(二)微服务注册与发现——Eureka

如果直接在服务消费者项目指定服务提供者地址的话,会带来很多问题。比如

  • 服务提供者的网络地址(IP和端口)发生了变化,服务消费者无法自动感知,需要手动修改并重新部署。
  • 无法动态增减每个微服务的集群节点。
  • 服务之间调用混乱,难于管理。

服务发现组件提供了解决以上问题的能力。

一、服务发现简介

  • 服务提供者、服务消费者、服务发现组件这三者的关系大致如下:
  • 各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
  • 服务消费者可从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口。
  • 各个微服务与服务发现组件使用一定机制(例如心跳)通信。服务发现组件如长时间无法与某微服务实例通信,就会注销该实例。
  • 微服务网络地址发生变更(例如实例增减或者IP端口发生变化等)时,会重新注册到服务发现组件。使用这种方式,服务消费者就无需人工修改提供者的网络地址了。

综上,服务发现组件应该具备以下功能:

  • 服务注册表:是服务发现组件的核心,它用来记录各个微服务的信息,例如微服务的名称、IP、端口等。服务注册表提供查询API和管理API,查询API用于查询可用的微服务实例,管理API用于服务的注册和注销。
  • 服务注册与服务发现:服务注册是指微服务在启动时,将自己的信息注册到服务发现组件上的过程。服务发现是指查询可用微服务列表及其网络地址的机制。
  • 服务检查:服务发现组件使用一定机制定时检测已注册的服务,如发现某实例长时间无法访问,就会从服务注册表中移除该实例。 

服务发现组件的其它叫法:服务注册、服务发现或注册中心。Spring Cloud提供了多种服务发现组件的支持,例如Eureka、Consul和Zookeeper等。 

二、Eureka简介

Eureka是Netflix开源的服务发现组件,本身是一个基于REST的服务。它包含Server和Client两部分。

PS:Eureka 2.x已宣布闭源,不过可能是临时的。

三、Eureka原理

Eureka架构图
  • Application Service:相当于服务提供者
  • Application Client:相当于服务消费者
  • Make Remote Call:可理解成调用RESTful API的行为 

Eureka包含两个组件:Eureka Server和Eureka Client,它们的作用如下:

  • Eureka Server提供服务发现的能力,各个微服务启动时,会向Eureka Server注册自己的信息(例如IP、端口、微服务名称等)。Eureka Server会存储这些信息。
  • Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。
  • 微服务启动后,会周期性(默认30秒)地向Eureka Server发送心跳以续约自己的“租期”。
  • 如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例。
  • 默认情况下,Eureka Server同时也是Eureka Client。多个Eureka Server实例,互相之间通过复制的方式,来实现服务注册表中数据的同步。
  • Eureka Client会缓存服务注册表中的信息。这种方式有一定的优势——首先,微服务无需每次请求都查询Eureka Server,从而降低了Eureka Server的压力;其次,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存的信息找到服务提供者并完成调用。

Eureka通过心跳检查、客户端缓存等机制,提供了系统的灵活性、可伸缩性和可用性。

四、Eureka的使用

1、编写Eureka Server

1)新建maven项目microservice-eureka,pom.xml文件引入spring boot、spring cloud和eureka-server的相关依赖。

<?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>cn.zhh</groupId>
    <artifactId>microservice-eureka</artifactId>
    <version>1.0</version>
    
    <!-- Spring Boot依赖  -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <!-- Spring Cloud管理依赖  -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
    	<!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题  -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

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

</project>

2)在application.yml加上以下配置。

## 服务端口
server:
  port: 8080
 
eureka:
  instance:
    hostname: localhost
  client:
    ## 因为该应用为注册中心,所以设置为false,代表不向注册中心注册自己
    registerWithEureka: false
    ## 因为该应用为注册中心,职责就是维护服务实例信息,并不需要去检索服务,所以设置为false。 
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3)启动类加上EnableEurekaServer注解。

@SpringBootApplication
@EnableEurekaServer
public class MicroserviceEurekaApplication {

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

}

4)启动项目,浏览器访问http://localhost:8080/,看到以下页面说明Eureka服务端运行成功。

2、将微服务注册到Eureka Server

1)新建maven项目microservice-provider,pom.xml文件引入spring boot、spring cloud和eureka-server的相关依赖。

<?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>cn.zhh</groupId>
    <artifactId>microservice-provider</artifactId>
    <version>1.0</version>
    
    <!-- Spring Boot依赖  -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <!-- Spring Cloud管理依赖  -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
    	<!-- spring-boot-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<!-- spring-boot-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
		<!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题  -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

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

</project>

2)在application.yml加上以下配置。主要是应用名(用于标记服务)、要注册到的Eureke注册中心地址。

server:
  port: 8081
spring:
  application:
    name: provider-pay
 
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8080/eureka/

3)编写一个支付API的控制器。

@RestController
public class PayController {

	@GetMapping("/pay")
	public String pay() {
		return "支付功能调用成功!";
	}
}

4)在项目启动类加上EnableDiscoveryClient注解。

@SpringBootApplication
@EnableDiscoveryClient // 相当于服务发现组件的门面,也可以使用@EnableEurekaClient
public class MicroserviceProviderApplication {

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

}

5)启动应用,可以看到服务已经注册到Eureka Server上了。

五、Eureka Server的高可用

Eureka Client会定时连接Eureka Server,获取服务注册表中的信息并缓存在本地。微服务在消费远程API时总是使用本地缓存中的数据。因此一般来说,即使Eureka Server发生宕机,也不会影响到服务之间的调用。但如果Eureka Server宕机时,某些微服务也出现了不可用的情况,Eureka Client中的缓存若不被更新,就可能会影响到微服务的调用,甚至影响到整个应用系统的高可用性。因此,通常会部署一个高可用的Eureka Server集群。

Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署,Eureka Server实例会彼此增量地同步信息,从而确保所有节点数据一致。事实上,节点之间相互注册时Eureka Server的默认行为。

下面来构造一个双节点Eureka Server集群(3个节点、4个节点...也是类似的,只要将自己的节点都注册到别的节点上就可以了)。

1)配置系统的hosts,Windows系统的hosts文件路径是C:\Windows\System32\drivers\etc\hosts,Linux及Mac OS等系统的文件路径是/etc/hosts。

127.0.0.1 ha1 ha2

2)复制项目microservice-eureka两份,将artifactId分别修改为microservice-eureka-ha1和microservice-eureka-ha2。

3)分别将application.yml修改如下,让两个节点的Eureka Server相互注册。

 

## 服务端口
server:
  port: 9081
 
eureka:
  instance:
    hostname: ha1
  client:
    ## 因为该应用为注册中心,所以设置为false,代表不向注册中心注册自己
    registerWithEureka: false
    ## 因为该应用为注册中心,职责就是维护服务实例信息,并不需要去检索服务,所以设置为false。 
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://ha2:9082/eureka/
## 服务端口
server:
  port: 9082
 
eureka:
  instance:
    hostname: ha2
  client:
    ## 因为该应用为注册中心,所以设置为false,代表不向注册中心注册自己
    registerWithEureka: false
    ## 因为该应用为注册中心,职责就是维护服务实例信息,并不需要去检索服务,所以设置为false。 
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://ha1:9081/eureka/

4)启动两个项目,分别访问http://localhost:9081/http://localhost:9082/,都可以看到registered-replicas拥有对方节点。

 

5)将应用注册到Eureka Server集群上。

以microservice-provider项目为例, 只需修改eureka.client.serviceUrl.defaultZone,配置多个Eureka Server地址,就可以将其注册到Eureka Server集群了。

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9081/eureka/,http://localhost:9082/eureka/

其实,微服务即使只配置Eureka Server集群中的某个节点,也能正常注册到Eureka Server集群,因为多个Eureka Server之间的数据会相互同步。不过,避免某些极端场景,还是建议在客户端配置多个Eureka Server节点。

六、Eureka的自我保护模式

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。

Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka就会保护服务注册表中的信息,不会删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动推出自我保护模式。

可以将eureka.server.enable-self-preservation设置为false禁用自我保护模式(默认为true),一般在开发环境中使用。

七、多网卡环境下的IP选择

Spring Cloud提供了按需选择IP的能力。

1、忽略指定名称的网卡

spring:
  cloud:
    inetutils:
      ignored-interfaces:
      - docker0
      - vetch.*

这样就可以忽略docker0网卡以及所有以vetch开头的网卡。

2、使用正则表达式,指定使用的网络地址

spring:
  cloud:
    inetutils:
      preferred-networks:
      - 192.168
      - 10.0

3、只使用站点本地地址

spring:
  cloud:
    inetutils:
      use-only-site-local-interfaces: true

这样就可以强制使用站点本地地址。

4、手动指定IP地址

eureka:
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

八、Eureka的健康检查

在Eureka Server首页,可以看到以下信息

在Status一栏有个UP,表示应用程序状态正常。应用状态还有其它取值,例如DOWN、OUT_OF_SERVICE、UNKNOWN等。只有标记为“UP”的微服务会被请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值