Eureka 学习笔记
目录
- 服务发现
- Eureka 概述
- 使用
- Eureka 集群
- 服务发现(Discovery)
- Eureka 自我保护
- 其他
- Eureka Server伙伴感知配置文件1234567891011121314151617181920spring:profiles: peer1eureka:instance:hostname: peer1client:serviceUrl:defaultZone: http://peer2/eureka/---spring:profiles: peer2eureka:instance:hostname: peer2client:serviceUrl:defaultZone: http://peer1/eureka/
- 附录
在了解 Eureka 常用操作之前,先查看一点微服务中关于服务发现的知识,这样能够帮助使用者更好的理解 Eureka 的工作模式
¶服务发现
❓微服务框架中,服务通常需要相互调用,为什么需要服务发现机制?
根据发出请求方不同,将服务发现划分为两种模式:客户端服务发现模式和服务端服务发现模式两种
¶客户端服务发现
✨RPC 远程调用框架核心设计思想在于注册中心,使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念),目前常用的注册中心架构如下图:
❓什么是服务注册中心?
服务发现依赖于服务注册表,系统中每个服务实例启动时,会将自己的网络位置信息发送到服务注册表,服务注册表利用心跳机制即时更新。实例关闭或者服务注册表检测到实例心跳超时情况下,实例信息就会从服务注册表移出
¶服务器端服务发现
🆚服务器端服务与客户端服务发现的异同
¶总结
¶Eureka 概述
Eureka 最初在 Netflix 主要用于 AWS 云上的服务发现,以实现服务器的负载均衡和容错。Eureka 也适用于基于 Docker 等虚拟化计数的微服务架构环境中,Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理。
¶Eureka 的服务注册与发现
之前阐述过,进行服务注册与发现时,存在一个注册中心,当服务器启动的时候,各个服务提供者会把将当前服务器的信息(比如服务地址通讯地址等以别名方式)注册到注册中心上。服务消费者使用该别名的方式去注册中心上获取到实际的服务通讯地址,获取到通讯地址后,就可以进行 RPC 调用
Eureka Server 没有基于 quorum
机制实现,而是采用 p2p
的去中心化结构,这样相比于zookeeper
,集群不需要保证至少 $((n+1)/2)$台 Server 存活才能正常工作,增强了可用性;但是这种结构注定了 Eureka 不可能有 zookeeper 那样的一致性保证,因为 Client 缓存更新不及时或 Server 间同步失败等原因,都会导致 Client 访问不到新注册的服务或者访问到过期的服务
Quorum 机制,是一种分布式系统中常用的,用来保证数据冗余和最终一致性的投票算法,其主要数学思想来源于鹊巢原理,由于不是本文重点,所以不在这里进行阐述
当 Eureka Server 节点间某次信息同步失败时,同步失败的操作会在客户端下次心跳发起时再次同步;如果 Eureka Server 和 Eureka Client 间有网络分区存在,Eureka Server 会进入自我保护模式,不再把过期服务从服务注册表移除(这种情况下客户端有可能获取已经停止的服务,配合使用Hystrix
通过熔断机制来容错和降级,弥补基于客户端服务发现的时效性缺点)
¶Eureka 组件
🆚Eureka 包含两个组件:Eureka Server 和 Eureka Client,下面主要介绍两者的区别
¶使用
Eureka 可以和 Spring Cloud 无缝集成,本小节开始阐述 Eureka 常用操作。
¶服务端(Eureka Server)
1 | <!-- eureka-server --> |
1 | # Eureka在Spring boot 项目中的配置文件 |
默认的应用名(Service ID)和端口号分别对应配置信息中的${spring.application.name}
和${server.port}
参数
1 |
|
随后就可以启动服务,访问http://localhost:6868
就可以查看Eureka
服务页面,由于只有服务端没有客户端所以看不到任何注册的服务,接下来介绍如何增加客户端
¶客户端
1 | <!--eureka client--> |
1 | eureka: |
1 |
|
使用@EnableEurekaClient
注解后,当前应用会同时变成 Eureka 服务端(它会注册自身)和 Eureka 客户端(可以查询当前服务列表),与此相关的配置都在以eureka.instance.*
开头的参数下,下图是启动 Eureka 后,访问当前系统内已注册的服务(由于存在网络分区所以默认开启的自我保护模式)
画面中的那一段英文,表示的就是当前 Eureka 开启了自我保护模式,具体的自我保护机制在后面会有一小节内容进行介绍
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 集群的实现非常简单,就是通过将两个 Eureka 服务做到:互相注册,互相守望即可做到 Eureka 集群的高可用
⛵使用步骤
默认已经将eureka7002.com
和 eureka7001.com
映射到了本地host
文件,映射地址就是127.0.0.1
1 |
|
1 |
|
此时由于拥有了两个微服务注册中心,所以每一个客户端都需要更改注册中心的位置信息
1 | eureka: |
- 先要启动 EurekaServer,7001/7002 服务
- 再要启动服务提供者 provider,8001
- 再要启动消费者
在使用过程中,遇到如下问题:
¶服务发现(Discovery)
对于注册进 eureka 里面的微服务,可以通过服务发现来获得该服务的信息
1 |
|
1 |
|
¶Eureka 自我保护
自我保护模式通常在一组客户端和 Eureka Server 之间存在网络分区场景下使用,一旦进入保护模式,Eureka Server 将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。默认Eureka
开启了自我保护模式,进入首页的红字就是提示开启了保护模式
❓什么是自我保护模式
当 Eureka Server 节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式,在自我保护模式中,Eureka Server 会保护服务注册表中的信息,不再注销任何服务实例,自我保护默认是开启的,也可以通过使用eureka.server.enable-self-preservation = false
禁用自我保护模式关闭
1 | eureka: |
¶其他
接下来记录 Eureka 其他功能
¶Eureka Server 的身份验证
如果客户端的eureka.client.serviceUrl.defaultZone
参数值(即 Eureka Server 的地址)中包含HTTP Basic Authentication
信息,如http://user:password@localhost:8761/eureka
,那么客户端就会自动使用该用户名、密码信息与 Eureka 服务端进行验证。如果需要更复杂的验证逻辑,必须注册一个DiscoveryClientOptionalArgs
组件,并将ClientFilter
组件注入,在这里定义的逻辑会在每次客户端向服务端发起请求时执行。由于 Eureka 的限制,Eureka 不支持单节点身份验证
¶状态页和健康信息指示器
Eureka 应用的状态页和健康信息默认的 url 为:/info
和/health
,这与Spring Boot Actuator
中对应的 Endpoint 是重复的,因此必须进行修改,修改后的配置文件如下:
1 | eureka: |
¶使用 HTTPS
可以通过指定EurekaInstanceConfig
类中的eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]
属性来指定是否使用 HTTPS。当配置使用 HTTPS 时,Eureka Server 会返回以https
开头的服务地址。即使配置了使用 HTTPS,Eureka 的主页依然是以普通 HTTP 方式访问的,需要手动添加一些配置来将这些页面也通过 HTTPS 保护起来
1 | eureka: |
🎶eureka.hostname
是 Eureka 原生属性,只有新版本的 Eureka 才支持该属性,也可以使用 Spring EL 表达式代替${eureka.instance.hostName}
¶健康检查
默认情况下,Eureka 通过客户端发来的心跳包来判断客户端是否在线。如果不显式指定,客户端在心跳包中不会包含当前应用的健康数据。这意味着只要客户端启动时完成了服务注册,那么该客户端在主动注销之前在 Eureka 中的状态会永远是UP
状态。我们可以通过配置修改这一默认行为,即在客户端发送心跳包时会带上自己的健康信息。这样做的后果是只有当该服务的状态是UP
时才能被访问,其它的任何状态都会导致该服务不能被调用
1 | eureka: |
如果想对健康检查有更细粒度的控制,可以自己实现com.netflix.appinfo.HealthCheckHandler
接口,做到自定义健康检查机制
¶Eureka 元数据说明
了解 Eureka 的元数据,就可以添加一些自定义的数据以适应特定的业务场景。像主机名、IP 地址、端口号、状态页 url 和健康检查 url 都是 Eureka 定义的标准元数据。这些元数据会被保存在 Eureka Server 的注册信息中,客户端会读取这些数据来向需要调用的服务直接发起连接。可以使用以eureka.instance.metadataMap
开头的参数来添加自定义的元数据,所有客户端都会读取到该信息。通过这种方式你能给客户端自定义一些行为
¶使用 Spring 的 DiscoveryClient 对象
没有必要直接使用 Netflix 原生的EurekaClient
对象,在此基础上做一些封装使用起来会更方便。Spring Cloud 支持Feign
和Spring RestTmpelate
,它们都可以使用服务的逻辑名而不是 URL 地址来查询服务。也可以使用 Spring 提供的DiscoveryClient
对象访问远程服务,从而代码就不会与 Eureka 紧耦合
1 |
|
¶伙伴感知
Eureka Server 可以通过运行多个实例并相互指定为伙伴的方式来达到更高的高可用性。实际上这就是默认设置,只需要指定伙伴的地址就可以了,这也就是之前说的 Eureka 集群方式
¶Eureka Server伙伴感知配置文件 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2/eureka/
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1/eureka/
1 |
|
在上面这个例子中,通过使用不同profile
配置的方式可以在本地运行两个 Eureka Server。可以通过修改/etc/host
文件,使用上述配置在本地测试伙伴感特性。可以同时启动多个 Eureka Server, 并通过伙伴配置使之围成一圈(相邻两个 Server 互为伙伴),这些 Server 中的注册信息都是同步的。如果伙伴在物理上是分开的,那么系统原则上可以承受脑裂类型的故障
¶Eureka 的高可用
Eureka 把所有注册信息都放在内存中,所有注册过的客户端都会向 Eureka 发送心跳包来保持连接。客户端会有一份本地注册信息的缓存,这样就不需要每次远程调用时都向 Eureka 查询注册信息。默认情况下,Eureka 服务端自身也是个客户端,所以需要指定一个 Eureka Server 的 URL 作为"伙伴"(peer)。如果没有提供这个地址,Eureka Server 也能正常启动工作,但是在日志中会有大量关于找不到 peer 的错误信息
¶为什么注册一个服务这么慢?
服务的注册涉及到心跳连接,默认为每 30 秒一次。只有当 Eureka 服务端和客户端本地缓存中的服务元数据相同时这个服务才能被其它客户端发现,这需要 3 个心跳周期。可以通过参数eureka.instance.leaseRenewalIntervalInSeconds
调整这个时间间隔来加快这个过程。在生产环境中最好使用默认值,因为 Eureka 内部的某些计算依赖于该时间间隔
¶Standalone 模式
只要 Eureka Server 进程不会挂掉,这种集 Server 和 Client 于一身的模式能让 Standalone 部署的 Eureka Server 非常容易进行灾难恢复。在 Standalone 模式中,可以通过下面的配置来关闭查找伙伴的行为
1 | server: |
🎶serviceUrl
中的地址的主机名要与本地主机名相同
¶使用 IP 地址
有些时候可能更倾向于直接使用 IP 地址定义服务而不是使用主机名。把eureka.instance.preferIpAddress
参数设为true
时,客户端在注册时就会使用自己的 ip 地址而不是主机名