Spring Cloud(三):服务发现之Eureka注册中心(2)-集群、配置、监控
分布式微服务在生产环境必须搭建集群来保证高可用,集群至少需要搭建两台服务器。
Eureka 的集群搭建配置非常简单,每一台 Eureka 只需在配置中指定另外多个 Eureka 的地址就可实现集群的搭建。官方文档:12. Service Discovery: Eureka Server。
Eureka 集群搭建
Eureka 可以运行多个实例,并让实例彼些注册,可使 Eureka 更具伸缩性和可用性。实现上,这是 Eureka 默认就支持的,只需在另外的 Eureka 添加一个有效的 serviceurl 。
集群说明
一个 Eureka Server 应用,部署到两台服务器上,一台为 master,另一个为 slave,通过运行不同的环境参数来启动集群实例。
- 将 master 注册到 Slave 上。
- 将 slave 注册到 master 上。
如果是三台服务器,分别将每一台注册到另外两台上,依次类推。
搭建配置
新增 2 个属性配置文件,一个为 master 环境配置,一个为 slave 环境配置;默认启动 master,slave 通过设置运行环境参数启动。
示例的 Demo 集成 Spring Security,增加了 Eureka Server 的 Web 控制台登录安全认证。
主配置文件:application.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17master =
eureka-server =
#因自己就是注册中心,所以关闭向注册中心注册自己
#eureka.client.register-with-eureka=false
#因注册中心的职责是维护实例,并不需要去检索服务,所以关闭
#eureka.client.fetch-registry=false
#设置 eureka server 同步失败的等待时间 默认 5分,在此期间,不向客户端提供服务注册信息
0 =
#设置 eureka server 同步失败的重试次数 默认为 5 次
5 =
# 扫描失效服务的间隔时间(单位毫秒,默认是60*1000)即60秒
5000 =
#认证账号密码
admin =
123456 =master 配置文件:application-master.properties
1
2
3
4
58761 =
eureka.master.com =
#注册中心地址
#eureka.client.service-url.defaultZone=http://eureka.slave.com:8762/eureka/
http://admin:123456@eureka.slave.com:8762/eureka/ =slave 配置文件:application-slave.properties
1
2
3
4
58762 =
eureka.slave.com =
#注册中心地址
#eureka.client.service-url.defaultZone=http://eureka.master.com:8761/eureka/
http://admin:123456@eureka.master.com:8761/eureka/ =关闭 Spring Security 的 csrf 防护
Spring Security 默认开启了 CSRF(跨站请求伪造) 防护,其它实例在请求注册时会失败并报错,需要禁用。
1
2
3
4
5
6
7
8
9
10
11
12/**
* @name: SpringSecurityConfig
* @desc: SpringSecurity配置类
**/
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().ignoringAntMatchers("/eureka/**");
}
}hosts 域名映射
1
2
3#eureka server master/slave
eureka.master.com
eureka.slave.com设置 Eureka 实例的主机名: eureka.instance.hostname ,也可使用环境变量在运行时设置主机名,如下:
1
2eureka.master.com =
${HOST_NAME} =某些情况下,会优先使用 IP 地址来通知服务,而不是主机名。如在阿里云服务器,应用部署在内网,使用的内网IP地址来注册和通知。
设置 eureka.instance.preferIpAddress 为 true,当应用向 Eureka 注册时,链接优先使用其 IP 地址,而不是主机名,如果无法确定主机名,则将 IP 地址通知给 Eureka;在 Eureka Server 的 Web 控制台的实例注册列表中,实例的链接地址改为了 IP 地址。IDEA 添加运行 slave 环境
菜单:Run → Edit Configurations → 左侧导航点击【+】,选择 Spring Boot → Configuration:选择入口文件,在 Active profile 输入:slave → 【Apply】→ 【OK】;
或者在 Configuration → Environment → Program arguments 输入:–spring.profiles.active=slave 来指定 slave 环境。或者将 Eureka Server 注册中心打成 jar 包,通过 java 命令指定运行环境,如下:
1
2java -jar eureka-server.jar --spring.profiles.active=master
java -jar eureka-server.jar --spring.profiles.active=slavemaster 和 slave 分别启动成功后,打开浏览器分别登录这两个服务的 Web 控制台。
在 DS Replicas 可以看到集群其它服务实例的主机名。
在 Instances currently registered with Eureka 可以看到 Eureka Server 集群其它实例主状态信息(包含多个实例ID:主机名:端口)
在 General Info 可以看到 registered-replicas 和 available-replicas 有 slave 实例的 url 地址。
注意事项
集群部署 Eureka Server ,多个注册中心实例, spring.application.name 值必须一致,所以最好放在主配置文件里。
集群部署时,eureka.client.register-with-eureka 和 eureka.client.fetch-registry 如果显式配置必须为 true(默认值),可不显式配置使用默认值。
这两项在 Eureka Server 注册中心部署 单实例 时,显式配置为 false,因只做服务发现和维护实例,不需要向自己注册为客户端实例,也不需要作为客户端来获取注册表(检索服务)。
集群部署时,主机名不能使用 localhost,即注册中心地址(service-url)不能使用 localhost,否则集群不能互相发现。
集群部署时,在本地调试,编辑 hosts 设置不同主机名(hostname)映射到本地 IP。
如果上以注意事项配置不对,要搭建集群的实例就不能关联,集群就不可用,注册的实例地址 URL 会显示在 General Info 的 unavailable-replicas 项目里。
客户端配置
客户端通过配置 eureka.client.service-url.defaultZone 来指定注册中心地址,当注册中心有多个节点时,该配置的值可为多个节点的地址,多个地址用英文逗号隔开。
1 | http://admin:123456@eureka.master.com:8761/eureka,http://admin:123456@eureka.slave.com:8762/eureka = |
Web 控制台
- master Web 控制台
- slave Web 控制台
Demo 源码
源码:SpringCloud-Example/eureka-cluster/
Eureka 更多配置
自我保护机制
Eureka 提供了 自我保护 模式,模认开启,防止节点之间因网络故障不能正常通信(心跳),但服务是正常运行的情况下,不再删除注册表中的数据。当网络故障恢复后,节点之间通信正常,节点自动退出保护模式。
Eureka 注册中心服务器有个续约期的概念,客户端通过定期发送心跳来告诉服务器我还活着。
续约期有两个参数:Renews threshold 和 Renews (last min)
Renews threshold | 描述 |
---|---|
Renews threshold | Eureka Server 期望每分钟收到客户端续约的总数(心跳阀值) |
Renews (last min) | Eureka Server 最近一分钟收到客户端续约的总数(心跳数) |
如果出现 Renews (last min) < Renews threshold,则表示有客户端服务断开了,但不会立即从注册表中删除该客户端服务的信息,而是进入保护模式。
如果在 Web 控制台看到如下所示内容,表示进入了保护模式:
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.server.enable-self-preservation=false#自我保护系数(默认0.85),自我保护模式必须开启
eureka.server.renewal-percent-threshold=0.49则会报如下信息:
THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
页面状态和健康指标
Eureka 实例的状态页和健康指标采集依赖于 Spring Boot Actuator ,采集自默认端点 /info
和 /health
端点,也是 Actuator 默认使用的端点。
应用如果使用非默认上下文路径或 servlet 路径(如自定义了 server.servlet.context-path=/custom)。 Eureka 实例的状态页面路径和健康检测路径也要根着修改,示例如下。这些链接显示在客户端的元数据中,并在某些场景中用于决定是否向应用发送请求。
application.properties
1 | /app = |
Eureka 健康检查
默认情况下,Eureka 通过客户端发送的心跳来确定客户端是否正常(up),客户端并不是根据 Spring Boot Actuator 传播应用程序的当前运行状态。
在客户端成功注册后,Eureka Server(注册中心)会一直认为客户端应用是正常运行的(设置客户端状态为 up),可通过开启客户端健康检查来修改客户端的运行状态(默认开启),从而将客户端应用的状态传播到其它 Eureka 应用(注:这块的处理机制还有疑问,待细究)。其他应用不会将流量(请求)发送到除 up 之外的其他状态的应用。
application.properties
1 | true = |
自定义实例 ID
Eureka 实例注册的ID等于其主机名(即每个主机只有一个服务)。
Spring Cloud Eureka 提供了合理的默认值,由以下环境变量组合而成:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}}
示例:myhost:myappname:8080
1
2
38080 =
myappname =
myhost =还可以通过设置 eureka.instance.instanceId 唯一标识符来覆盖默认值
示例:sakila-service1:52a65013349b6e9d2d17b6b1812fa188
1
${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}} =
配置项说明
- spring.cloud.client.hostname:取自元数据,来自操作系统,可在配置文件显式指定,在注册中心的注册列表里作为实例ID的组成部分在页面显示,用于区分不同的实例。
- spring.application.instance_id:实例ID,默认值是 null。
- vcap.application.instance_id:默认是空,在Cloud Foundry中,会自动填充。
- random.value:使用随机值。
- 注意主机名:hostname
- spring.cloud.client.hostname:配置 Eureka 实例 ID,默认来自Spring Cloud元数据,取自操作系统;可显式配置。在 Eureka Web 控制台的注册列表中显示 Eureka 实例 ID 用。
- eureka.instance.hostname:配置 Eureka 实例主机名,默认来自 Eureka 元数据,取自操作系统;可显式配置。在 Eureka Web 控制台的注册列表中Eureka 实例的跳转链接用。
如果开启了优使用 IP地址(eureka.instance.preferIpAddress=true),则实例的跳转链接为主机的IP地址。 - eureka.instance.virtual-host-name:给 Eureka 实例指定一个虚拟主机名,通常其他实例使用虚拟主机名查找此实例(可将此虚拟主机名视为类似于完全限定的域名,供其它服务查找此实例)。见本篇的【使用 EurekaClient】章节。
该虚拟主机名默认被设置为环境变量 spring.application.name 的值。当集群部署 Eureka Server 注册中心时时,多个节点的应用名必须是相同的,所以就有必要通过这个虚拟主机名来识别每一个节点实例。
Eureka 实例名
eureka.instance.appname 属性可以配置注册到 Eureka 的实例的名称(appName属性),如果该配置项不存在,则实例名称等于服务应用名称(spring.application.name)。
Eureka 实例名显示在 Web 页面实例注册列表的 Application 栏,个人理解是用于对应用分组,不同实例名的服务在 Web 页面的注册列表分别显示。而多个实例名相同的服务则显示在同一行。
自定义实例跳转链接
在 Eureka Server 的 Web 控制台,注册列表显示的实例ID 的跳转链接默认是 eureka.instance.hostname:server.port/actuator/info;
或设置了IP地址优先,跳转链接是 ipAddre:server.port/actuator/info
可以自定义这个跳转地址:eureka.instance.status-page-url=http://eureka.server.xxxx.com
心跳周期和心跳超时
Eureka 实例注册注册中心,通过 serviceUrl 定期向注册中心服务器发送心跳以报告实例仍处活动状态(up,正常运行),默认间隔是 30 秒。
在实例、服务器和客户端在其本地缓中具有相同的元数据之前,客户端是无法发现服务的(这个过程可能需要 3次 心跳)。
可以通过设置 eureka.instance.lease-renewal-interval-in-seconds 来更改心跳周期。将值设置小于 30 秒会加快客户端与其他服务的连接。
1 | //客户端发送心跳频率为每10秒一次 |
leaseExpirationDurationInSeconds 的值至少要大于 leaseRenewalIntervalInSeconds 指定的值。
leaseExpirationDurationInSeconds 值若设置的太长,可能存在实例不在活动状态,仍将流量路由到该实例;若设置的太小,出现网络临时故障时(快速恢复),该实例可能会失去通信。
若要修改缓存清单的更新时间,可以通过以下参数修改,默认是 30秒:
1 | 30 = |
注意:修改心跳频率和心跳超时可在开发环境使用,以加快实例状态更新;在生产环境中,最好还是使用默认值。
更多关注实例、服务、客户端的配置信息可参考源码中的配置类:
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean,
org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean,
org.springframework.cloud.netflix.eureka.EurekaClientConfigBean。
EurekaClient 的使用
应用如果是 Eureka Client 应用,可以使用原生的 com.netflix.discovery.EurekaClient 从 Eureka Server 查找获取其它 Eureka 实例(注意不是 Spring Cloud DiscoveryClient) 。
1 |
|
virtualHostName 取的是环境变量 eureka.instance.virtual-host-name 的值。
DiscoveryClient 的使用
可以不使用原始的 Netflix EurekaClient ,Spring Cloud 重新封装了 DiscoveryClient 用于发现获取服务实例。Spring Cloud 支持 Feig 和 RestTemplate 通过 Eureka 服务的ID(VIPs-vipAddress) 代替 物理URL 进行 HTTP 通信。
给 Ribbon 配置一个固定的物理服务器列表,使用 <client>.ribbon.listOfServer
设置多个物理服务器地址或多个主机名,通过逗号分隔,<client>
是客户端ID。【这块的理解和使用待研究Ribbon时深究】
还可以使用 org.springframework.cloud.client.discovery.DiscoveryClient ,他提供了一个简单的 API(不是 Netflix) 来发现客户端,示例如下:
1 |
|
Eureka 排除 Jersey
EurekaClient 默认使用 Jersey 来进行 HTTP 通信,可以排除 Jersey 依赖;自动切换使用 Spring Cloud 默认自动配置 Spring RestTemplate 进行客户端通信。
1 | <dependency> |
EurekaClient 元数据
Eureka 实例和客户端有标准的元数据,包括主机名、IP地址、端口号、状态页和运行健康检查信息 ;这些信息随客户端注册发布到服务注册表中,其它客户端使用这些元数据联系服务。
也可以自定义元数据到注册信息中,这些自定义的元素据同样能被其它客户端访问到:
1 | 自定义元数据,key 是自定义的键 |
通常,自定义的元数据不会影响客户端的功能,可以用来做一些扩展信息。 Spring Cloud 为默认的元数据指定了特定含义的。
EurekaClient 区域连接
如果客户端是多区域分布式布署,则可能希望这些客户端优先使用同一区域的服务,其次再连接其它区域的服务。
首先要确保提供服务的实例部署到各个区域,可以使用 metadataMap
属性来标识当前实例所在区域。
例如 service1 分别部署到 zone1 和 zone2 两个区域,则需要配置如下:
Service 1 in Zone 1
1 | zone1 = |
Service 1 in Zone 2
1 | zone2 = |
Eureka Rest API
Eureka 提供了多个 REST 接口来获取实例注册信息,可以获取某个服务的实例信息。
获取注册列表中所有服务的实例信息
地址:
http://hostname:port/eureka/apps
获取某个服务的实例信息,Get 请求,浏览器输出的是 XML 格式
地址:
http://hostname:port/eureka/apps/appname
以上接口也可以使用接口调试工具请求,如 Postman,指定请求和返回数据类型
指定请求 Headers 属性:
Content-Type:application/json
Accept:application/json若开启了安全授权,设置 Authorization 头
TYPE 设置为 Basic Auth
输入账号密码
服务上下线监控
通常需要对服务的上下线进行监控,可能整合邮件或其他通信方式通知到用户,Eureka 提供了事件监听的方式来扩展该功能:
Eureka 支持的事件
- EurekaInstanceRegisteredEvent 实例注册事件
- EurekaInstanceCanceledEvent 实例下线事件
- EurekaInstanceRenewedEvent 服务续约事件
- EurekaRegistryAvailableEvent 注册中心启动事件
- EurekaServerStartedEvent Eureka Server 启动事件
在集群部署情况下,每个节点都会触发事件,这时需要对下发通知进行控制,否则每个接点都发送通知。
Eureka 事件监听示例
1 |
|
相关参考
Spring Cloud(三):服务发现之Eureka注册中心(2)-集群、配置、监控
http://blog.gxitsky.com/2019/02/22/SpringCloud-03-service-discover-eureka-2/