Spring-Cloud-Eureka-学习笔记
Eureka
Eureka简介
是Netflix开源的服务发现组件,本事是基于REST的服务. 包括Server和Client两部分.在Spring Cloud子项目Spring Cloud Netflix中.
Eureka能做什么?
微服务的注册与发现
Eureka什么时候使用?有哪些应用场景?在Spring Cloud中是一个什么位置的存在?
Eureka Server 和 Eureka Client
- Eureka Server : 提供服务发现的能力,各服务启动时,会向Eureka Server注册自己的信息(IP,端口,服务信息等),Eureka Server会存储这些信息.
- Eureka Client : 服务提供者,简化与Eureka Server的交互.
- 微服务启动后,会周期性(默认30秒)的向Eureka Server发送心跳以续约自己的”租期”.
- 如果Eureka Server在一定时间内没有收到某个微服务实例(Eureka Client)的心跳,Eureka Server将会注销该实例(默认90秒).
注 : - 默认请求下,Eureka Server同时也是Eureka Client.多个Eureka Server实例,互相之间通过复制的方式,来实现服务注册表中的数据.(实现集群,高可用)
- Eureka Client会缓存注册表中的信息.这种方式有一定的优势
首先,微服务无需每次请求都查询Eureka Server,从而降低了Eureka Server的压力;
其次,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用.
这样,Eureka通过心跳检测,客户端缓存等机制,提高了系统的灵活性,可伸缩性和可用性.
Eureka Server示例
创建Maven项目,pom.xml 配置如下
1 | <?xml version="1.0" encoding="UTF-8"?> |
如果使用IntelliJ IDEA
启动类中加入@EnableEurekaServer
@EnableEurekaServer : 表示这是一个Eureka Server
application.yml
注 : 默认生成的项目配置文件是 application.properties,这里我是使用application.yml1
2
3
4
5
6
7
8
9
10
11
12
13# 服务注册中心 (单节点)
server:
port: 1111
eureka:
instance:
hostname: localhost
client:
fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
service-url:
# 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址.默认是http://localhost:8761/eureka/;多个地址可使用','风格.
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
eureka的配置信息就是这个org.springframework.cloud.netflix.eureka.EurekaClientConfigBean类,具体可以看源码
启动Eureka Server工程,打开浏览器输入地址即可看到eureka的信息
Eureka Client示例
重复之前的步骤1
2
3<artifactId>spring-cloud-eureka-server</artifactId>
改成
<artifactId>spring-cloud-eureka-client</artifactId>
启动类中加入@EnableDiscoveryClient
之前启动类的@EnableEurekaServer换成@EnableDiscoveryClient
@EnableDiscoveryClient : 声明这是一个Eureka Client
application.yml
Eureka Client的application.yml如下1
2
3
4
5
6
7
8
9
10
11
12
server:
port: 2222
spring:
application:
name: service
eureka:
client:
service-url:
defaultZone: http://localhost:1111/eureka # 指定服务注册中心
启动Eureka Client工程
再访问Eureka Server http://localhost:1111 就可以看到,注册的服务了.
这样一个简单的微服务就被注册到Eureka Server.
Eureka Server的高可用(集群)
以上的Eureka Server只是简单Demo,真正生产环境是需要高可用的,通常会部署一个高可用的Eureka Server集群.
Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署,Eureka Server实例会彼此增量地同步信息,从而保证所有节点数据一致.
事实上,节点之间互相注册是Eureka Server默认行为.
之前的Eureka Server配置如下,1
2
3
4
5eureka:
client:
# 下面两个配置默认值是true,也就是,节点之间互相注册是Eureka Server默认行为.所以集群的时候,不设置即可
# fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
# register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
Eureka Server集群示例
- 复制之前Eureka Server项目,修改pom.xml中artifactId,这个你自己填写
- 修改hosts,加入 127.0.0.1 server-1 server-2
- 增加 application-server-1.yml application-server-2.yml
application-server-1.yml配置如下1
2
3
4
5
6
7
8
9
10
11
12
13# 服务注册中心 (多节点,集群)
server:
port: 1111
eureka:
instance:
hostname: server-1
client:
service-url:
defaultZone: http://server-2:1112/eureka/
# 需要修改host 127.0.0.1 server-1
# java -jar --spring.profiles.active=server-1
application-server-2.yml配置如下1
2
3
4
5
6
7
8
9
10
11
12# 服务注册中心 (多节点,集群)
server:
port: 1112
eureka:
instance:
hostname: server-2
client:
service-url:
defaultZone: http://server-1:1111/eureka/
# 需要修改host 127.0.0.1 server-2
# java -jar --spring.profiles.active=server-2
- 然后打包项目,使用java命令启动
java -jar aidijing-eureka-server-0.0.1-SNAPSHOT.jar –spring.profiles.active=server-1
java -jar aidijing-eureka-server-0.0.1-SNAPSHOT.jar –spring.profiles.active=server-2
然后再访问,即可看到如下图
Eureka Client注册到Eureka Server集群上
在之前Eureka Client的配置文件中修改application.yml配置即可
1 | eureka: |
启动的时候,端口号自行指定两个不同的就行了
Eureka Server安全
为Eureka Server加入用户认证,默认Eureka Server是匿名的.
spring-boot-starter-security依赖
在之前的Eureka Server项目中加入spring-boot-starter-security,当然也可以复制一个新的项目进行添加.1
2
3
4
5<!-- 为Eureka Server添加用户认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
application.yml 中添加spring相关配置
1 | security: |
这样再启动Eureka Server,访问时则需要进行认证才可以进入
Eureka Client注册到需要认证的Eureka Server
很简单只需要修改之前的配置,对defaultZone进行修改
格式是 : http://user:password@EurekaHost:EurekaPort/eureka/1
2
3
4
5
6eureka:
client:
service-url:
# defaultZone: http://localhost:1111/eureka/ # 指定服务注册中心
# 格式是 : http://user:password@EurekaHost:EurekaPort/eureka/
defaultZone: http://root:root@localhost:1111/eureka/ # 指定服务注册中心
Eureka元数据
Eureka的元数据有两种
- 标准元数据
指的是主机名,IP地址,端口号,状态页和健康检查等信息,这些信息都会被发布在注册表中,用于服务之间的调用 - 自定义元数据
可以使用eureka.instance.metadata-map进行配置,这些元数据可以在远程客户端中访问,但不会改变客户端行为.
自定义元数据,就是可以在标准元数据上添加一些其他信息自定义元数据示例
在原来Eureka Client上进行测试
application.yml新增如下配置1
2
3
4
5
6eureka:
# ... ...
instance:
metadata-map:
# 自定义元数据,key/value自行定义
order-id: 自定义元数据
打印元数据
在Eureka Client项目控制器中新增一个方法,打印元数据信息
1 |
|
然后访问这个控制器,得到如下信息.
Eureka 的自我保护模式
进入自我保护模式最直观的体现是,Eureka Server首页输出的警告,如下图
默认情况下,如果Eureka Server在一定时间内没有收到某个微服务实例的心跳,Eureka Server就会注销这个实例(默认是90秒).
但是当网路分区发生故障时,微服务与Eureka Server之间无法正常通信,以上行为就可能非常危险,因为微服务本身是健康的,此时本不应该注销这个服务的.
Eureka 通过自我保护模式来解决这个问题,当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式.
一旦进入这个模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不注销任何微服务).当网络故障恢复后,这个Eureka Server
节点会自动退出自我保护模式.
当然也可以关闭自我模式1
2
3eureka:
server:
enable-self-preservation: false # 禁用自我保护模式
多网卡下的IP选择
对于多网卡的服务器,各个微服务注册到Eureka Server上的IP要如何指定呢?
指定IP在某些场景下很有用.例如某台服务器有eth0,eth1,eth2三张网卡,但是只有eth1可以被其他的服务器访问;
如果Eureka Client将eth0或者eth2注册到Eureka Server上,其他微服务就无法通过这个IP调用该微服务的接口.
Spring Cloud提供了按需选择IP的能力,从而避免以上的问题.
忽然指定名称的网卡
1 | spring: |
使用正则表达式忽略
1 | spring: |
只使用站点本地地址
1 | spring: |
手动指定IP地址
1 | spring: |
Eureka 的健康检查
Eureka Server与Eureka Client之间使用心跳机制来确定Eureka Client的状态,默认情况下,服务端与客户端
保持正常,应用程序就会始终保持’UP’状态.以上机制并不能完全反应应用程序的状态.
如果,微服务与Eureka Server之间的心跳正常,Eureka Server认为该服务’UP’;然而,该微服务的数据源发生了
问题(例如因为网络抖动,连不上数据源),那么其实这个微服务是无法正常工作的.
Spring Boot Actuator提供了/heath端点,改端点可展示应用程序的健康信息.
那么如何才能将该端点中的健康状态传播到Eureka Server呢?
要实现这一点,只需启动Eureka的健康检查.这样应用程序就会将自己的健康状态传播到Eureka Server.开启的方法非常简单,只需
为微服务配置一下内容,就可以开启健康检查.
1 | # actuator 权限 |
未完成
服务注册发现实现了,但是这样依然有问题,比如负载均衡.各位服务之间会部署多个实例,那么服务消费者要如何将请求分摊
到多个服务器实例上呢?
.