使用Eureka提供服务注册与发现

使用Eureka提供服务注册与发现

前言

上文《使用Spring Boot快速构建服务提供和服务消费者》https://mp.weixin.qq.com/s/QGWzlqDxVVbPW24SUMkUew ,已完成服务提供者和服务消费者的搭建,服务间的调用采用的是指定服务提供方的网络地址(IP和端口等)进行访问。

User entity = restTemplate.getForObject("http://localhost:8000/user/v1/"+id, User.class);

这种方式有很多问题

  • 适用场景有局限:如果服务提供者的网络地址(IP和端口)发生了变化,会影响服务消费者。
  • 无法动态伸缩:在生产环境中,每个微服务一般都会部署多个实例,从而实现容灾和负载均衡。在微服务架构的系统中,还需要系统具备自动伸缩的能力,例如动态增减节点等。硬编码无法适应这种需求。

服务注册与发现

要想解决这些问题,服务消费者需要一个强大的服务发现机制,服务消费者使用这种机制获取服务提供者的网络信息。 不仅如此,即使服务提供者的信息发生变化,服务消费者也无须修改配置文件。服务发现组件正是用于提供这种能力。

在微服务架构中,服务发现组件是一个非常关键的组件。

3.服务发现架构图

服务提供者、服务消费者、服务发现组件这三者之间的关系大致如下

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

服务发现组件应具备以下功能:

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

注册中心主要功能:

  • 服务注册:服务提供方将自身路由信息发布到注册中心,供消费方获取用于与提供方建立连接并发起调用。包括:
    • 路由信息:注册服务节点IP、监听端口等路由信息。
    • 服务信息:序列化协议、路由规则、节点权重。
  • 服务发现:服务消费方通过访问注册中心获取服务提供方节点路由信息。常见方式:
    • 启动拉取:服务消费方启动后,从注册中心拉取提供方节点列表,建立连接,进行RPC调用。
    • 通知回调:接受注册中心变更通知,重新获取数据,更新节点列表。
    • 轮训拉取:服务消费方运行过程中定时拉取提供方节点列表,用来更新本地数据。
  • 健康检查:确保已注册节点健康度,能够及时准确剔除失效节点,保证服务发现正确性。
  • 变更通知:当服务提供方节点发生变更时,注册中心应该能够第一时间把变更事件或变更后的数据推送到服务订阅方。

注册中心本质是订阅+存储。存储系统主要关注点:

  • 数据可靠性:数据冗余存储,确保不会因为单节点故障导致数据丢失。
  • 数据一致性:各节点间数据同步,保证数据一致性.
  • 服务可用性:多节点对等的对外提供服务。

注册中心除了实现服务注册与发现,还可以用来实现服务治理相关功能:服务扩缩容、机器迁移、权重、灰度流量等。

Eureka 简介

Eureka Netflix 开源的服务发现组件,本身是一个基于 REST 的服务。它包含 Server 和 Client 两部分。 Spring Cloud 将它集成在在子项目 Spring Cloud Netflix 中,从而实现微服务的注册与发现。

4.Eureka集群高可用架构

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

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

使用 Eureka 提供服务注册与发现

版本说明:

  • JDK 1.8
  • Spring Boot 1.4.3.RELEASE
  • Spring Cloud Camden SR4

一、编写 Eureka Server

使用 Spring Boot 快速构建项目 micro-discovery-eureka 。

  1. 为项目添加 Eureka Server 依赖:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
  1. 在 Spring Boot 启动类上添加注解 @EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
  1. 在配置文件 application.yml 中配置属性
server:
  port: 8761
eureka:
  client:
    # 表示是否将自己注册到 Eureka Server ,默认为 true ,因为本身是 Eureka Server,故设为 false
    registerWithEureka: false
    # 表示是否从 Eureka Server 获取注册信息,默认为 true ,因为是单点故设为 false
    fetchRegistry: false
    # 设置与 Eureka Server 交互的地址,多个地址使用,逗号分隔
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  1. 启动 Eureka Server , 访问 http://localhost:8761/ 。

二、将微服务注册到 Eureka Server 上

使用 Spring Boot 快速构建项目 micro-provider-user 和 micro-consumer-movie 。

  1. 为项目添加 Eureka Client 依赖:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
  1. 在 Spring Boot 启动类上添加注解 @EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class MicroProviderUserApplication {
    public static void main(String[] args) {
        SpringApplication.run(MicroProviderUserApplication.class, args);
    }
}

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

}
  1. 在配置文件 application.yml 中配置属性
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    # 表示将自己的IP注册到 Eureka Server,如不配置或false,表示注册微服务所在操作系统的hostname到 Eureka Server。
    prefer-ip-address: true
  1. 启动服务,访问 Eureka Server http://localhost:8761/ ,检查服务是否已注册到注册中心。

三、基于 Eureka 实现服务发现

  1. 启动服务,服务提供者 micro-provider-user 和 Eureka Server 服务 micro-discovery-eureka 。

  2. 服务消费者 micro-consumer-movie ,基于 Eureka 提供服务发现。

@RestController
@RequestMapping("/movie/v1")
public class MovieController {
    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/user-instance")
    public List<ServiceInstance> showInfo(){
        return discoveryClient.getInstances("micro-provider-user");
    }
}
  1. 启动服务 micro-consumer-movie ,访问 http://localhost:8010/movie/v1/user-instance 。
[{
	"host": "192.168.233.1",
	"port": 8000,
	"metadata": {},
	"secure": false,
	"uri": "http://192.168.233.1:8000",
	"instanceInfo": {
		"instanceId": "localhost:micro-provider-user:8000",
		"app": "MICRO-PROVIDER-USER",
		"appGroupName": null,
		"ipAddr": "192.168.233.1",
		"sid": "na",
		"homePageUrl": "http://192.168.233.1:8000/",
		"statusPageUrl": "http://192.168.233.1:8000/info",
		"healthCheckUrl": "http://192.168.233.1:8000/health",
		"secureHealthCheckUrl": null,
		"vipAddress": "micro-provider-user",
		"secureVipAddress": "micro-provider-user",
		...
	},
	"serviceId": "MICRO-PROVIDER-USER"
}]

注:为方便服务间调用,还需要支持客户端负载均衡,在 Spring Cloud 中,当 Ribbon 和 Eureka 配合使用时,Ribbon 可自动从 Eureka Server 获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。

Eureka Server 的高可用

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

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

  1. 复制 micro-discovery-eureka 项目,修改 artifactId 为 micro-discovery-eureka-ha 。

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

127.0.0.1 peer1 peer2
  1. 添加配置文件 application-peer1.yml 和 application-peer2.yml
# application.yml
# 设置默认配置
spring:
  profiles:
    active: peer1

# application-peer1.yml
spring:
  application:
    name: micro-discovery-eureka-ha
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
  client:
    # 设置与 Eureka Server 交互的地址,将自己注册到 peer2 这个 Eureka 上面去
    serviceUrl:
      defaultZone: http://peer2:8762/eureka/

# application-peer2.yml
spring:
  application:
    name: micro-discovery-eureka-ha
  profiles:
    active: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2
  client:
    # 设置与 Eureka Server 交互的地址,将自己注册到 peer1 这个 Eureka 上面去
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/
  1. 启动 Eureka Server 集群,使用 mvn package 打包,通过命令行启动多个服务,访问 http://peer1:8761/ 或 http://peer2:8762/ 。
java -jar micro-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1

java -jar micro-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2
  1. 将应用注册到 Eureka Server 集群上

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

eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/

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

为 Eureka Server 添加用户认证

构建一个需要登录才能访问的 Eureka Server 。

  1. 复制 micro-discovery-eureka 项目,修改 artifactId 为 micro-discovery-eureka-authenticating 。

  2. 添加 Spring-boot-starter-security 的依赖,为 Eureka Server 提供用户认证的能力。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  1. 修改配置文件 application.yml ,添加配置:
security:
  basic:
    # 开启基于 HTTP basic 的认证
    enabled: true
  user:
    # 配置登录账号与密码
    name: user
    password: password123

这样就为 Eureka Server 添加了基于 HTTP basic 认证。如果不设置这段内容,账号默认是 user ,密码是一个随机值,该值会在启动时打印出来。

  1. 启动 Eureka Server ,访问 http://localhost:8761/ ,输入账号密码即可访问。

  2. 配置 Eureka Client 访问 Eureka Server ,以 micro-provider-user 项目为例,修改 eureka.client.serviceUrl.defaultZone ,修改为 http://user:password@EUREKA_HOST:EUREKA_PORT/eureka/的形式

eureka:
  client:
    serviceUrl:
      defaultZone: http://user:password123@localhost:8761/eureka/

Eureka Server 的 REST 端点

Eureka Server 提供了一些 REST 端点。非 JVM 的微服务可使用这些 REST 端点操作 Eureka 从而实现服务注册与发现。事实上,Eureka Client 就是一个使用 Java 编写的、操作这些 REST 端点的类库。

Eureka 提供的 REST 端点,可以使用 XML 或者 JSON 与这些端点通信,默认是 XML 。

5.Eureka的REST端点一览表

appID 是应用程序的名称, instanceID 是与实例相关联的唯一 ID 。在 AWS 环境中, instanceID 表示微服务实例的实例 ID ,在非 AWS 环境则表示实例的主机名。

示例:查看所有实例: http://localhost:8761/eureka/apps

Eureka 的自我保护模式

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

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

综上 ,自我保护模式是一种应对网络异常的安全保护措。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式可以让 Eureka 集群更加的健壮、稳定。

在 Spring Cloud 中,可以使用 eureka.server.enable-self-preservation = false 禁用自我保护模式。

Eureka 的健康检查

Eureka Server 与 Eureka Client 之间使用心跳机制来确定 Eureka Client 的状态,默认情况下,服务器端与客户端的心跳保持正常,应用程序就会始终保持“UP”状态。

Spring Boot Actuator 提供了/health 端点,该端点可展示应用程序的健康信息。那么如何才能将该端点中的健康状态传播到 Eureka Server 呢?

要实现这一点,只需启用 Eureka 的健康检查。这样,应用程序就会将自己的健康状态传播到 Eureka Server 。

开启方法,只需为微服务配置以下内容,就可以开启健康检查。

eureka:
  client:
    healthcheck:
      enabled: true

为 Spring Boot 项目整合 Actuator

Spring Boot Actuator 提供了很多监控端点。可使用 http://{ip}:{port}/{endpoint}的形式访问这些端点,从而了解应用程序的运行状况。

Actuator 提供的端点,如下图所示:

2.Spring Boot Actuator常用端点及描述

整合 Actuator

为项目添加依赖:

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

测试:/health 端点

  • 访问:http://localhost:8000/health
  • 可展示当前应用的健康状况 其中, UP 表示运行正常,除 UP 外,还有 DOWN、OUT_OF_SERVICE、UNKNOWN 等状态。
  • /health 的本质,通过检查 Spring Boot 应用程序的资源,来判断应用是否正常。

测试:/info 端点

  • 访问:http://localhost:8000/info
  • /info 端点可使用 info.* 属性来自定义 /info 端点公开的数据,例如:
info:
  app:
    name: @project.artifactId@
    encoding: @project.build.sourceEncoding@
    java:
      source: @java.version@
      target: @java.version@
  • 这样,重启后,再次访问 http://localhost:8000/info ,结果如下:
{
	"app": {
		"name": "micro-simple-consumer-movie",
		"encoding": "UTF-8",
		"java": {
			"source": "1.8.0_40",
			"target": "1.8.0_40"
		}
	}
}

Spring Boot Actuator 端点详解:https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/?%20t=O.%2040102908698306905#production-ready-endpoints

代码仓库

https://gitee.com/chentian114/spring-cloud-practice

公众号

知行chen

参考

《Spring Cloud 与Docker 微服务架构实战》 周立

https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值