1. Eureka简介
Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件,Springcloud Netflix中的重要组件。
注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中, 服务会注册到这里,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。
-
Eureka Server 服务注册中心
提供服务注册和发现
-
Service Provider 服务提供方
将自身服务注册到Eureka,从而使服务消费方能够找到
-
Service Consumer 服务消费方
从Eureka获取注册服务列表,从而能够消费服务
2. 能干什么
服务注册中心是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。
注册中心一般包含如下几个功能:
-
服务发现:
服务注册/反注册:保存服务提供者和服务调用者的信息服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能服务路由(可选):具有筛选整合服务提供者的能力。
-
服务配置:
配置订阅:服务提供者和服务调用者订阅微服务相关的配置
配置下发:主动将配置推送给服务提供者和服务调用者
-
服务健康检测
检测服务提供者的健康情况
3. Quick Start
3.1 eureka-server
创建服务注册中心
3.1.1 引入依赖坐标
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
3.1.2 配置application.yml
server:port: 8080eureka:instance:hostname: localhostclient:# 是否将自己注册到Eureka服务中,本身就是所有无需注册registerWithEureka: false# 是否从Eureka中获取注册信息fetchRegistry: false# 客户端与Eureka服务端进行交互的地址serviceUrl:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.1.3 配置启动类
//激活Eureka Server端配置@EnableEurekaServer@SpringBootApplicationpublic class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}}
3.1.4 服务注册中心管理后台
浏览器输入:
localhost:8080
访问注册中心管理后台
3.2 eureka-client
创建provider服务,将服务注册到注册中心
3.2.1 引入依赖坐标
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
3.2.2 配置application.yml
server:port: 8082spring:application:name: providereureka:client:# eureka server的路径serviceUrl:defaultZone: http://localhost:8080/eureka/instance:#使用ip注册prefer-ip-address: true
3.2.3 配置启动类
package com.ldx.provider;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;//开启Eureka客户端发现功能//@EnableDiscoveryClient@SpringBootApplicationpublic class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}}
从Spring Cloud Edgware版本开始, @EnableDiscoveryClient 或 @EnableEurekaClient 可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。
重复上述操作,完成consumer服务的注册。
3.2.4 查看注册中心管理后台
如图 两个服务已成功注册到服务注册中心。
4. Eureka中的自我保护
微服务第一次注册成功之后,每30秒会发送一次心跳将服务的实例信息注册到注册中心。通知Eureka Server该实例仍然存在。如果超过90秒没有发送更新,则服务器将从注册信息中将此服务移除。
Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况 (在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。保护模式主要用于一组客户端和Eureka Server 之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务) 验证完自我保护机制开启后,并不会马上呈现到web上,而是默认需等待 5 分钟(可以通过eureka.server.wait-time-in-ms-when-sync-empty 配置),即 5 分钟后你会看到下面的提示信息:
可以通过设置 eureka.enableSelfPreservation=false 来关闭自我保护功能。
5. Eureka中的元数据
Eureka的元数据有两种:标准元数据和自定义元数据
标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注 册表中,用于服务之间的调用。
自定义元数据:可以使用eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。这些元数据可以在远程客户端中访问。
在程序中可以使用DiscoveryClient 获取指定微服务的所有元数据信息
在provider模块中添加metadata配置:
eureka:client:# eureka server的路径serviceUrl:defaultZone: http://localhost:8080/eureka/instance:#使用ip注册prefer-ip-address: true#添加元数据metadata-map:name: myproviderage: 18
在consumer中添加测试类
package com.ldx.consumer.test;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@SpringBootTest@RunWith(SpringRunner.class)public class RestTemplateTest {@Autowiredprivate DiscoveryClient discoveryClient;@Testpublic void test() {//根据微服务名称从注册中心获取相关的元数据信息List<ServiceInstance> instances = discoveryClient.getInstances("provider");for (ServiceInstance instance : instances) {System.out.println("secure:" + instance.isSecure());System.out.println("scheme:" + instance.getScheme());System.out.println("ubstabceId:" + instance.getInstanceId());System.out.println("serviceId:" + instance.getServiceId());System.out.println("host:" + instance.getHost());System.out.println("port:" + instance.getPort());System.out.println("uri:" + instance.getUri());System.out.println("metadata:" + instance.getMetadata());}}}
测试结果如下
secure:falsescheme:httpubstabceId:192.168.0.102:provider:8082serviceId:PROVIDERhost:192.168.0.102port:8082uri:http://192.168.0.102:8082metadata:{name=myprovider, management.port=8082, age=18}
6. Eureka的认证
我们启动了Eureka Server,然后在浏览器中输入http://localhost:8080/后,直接回车,就进入了spring cloud的服务治理页面,这么做在生产环境是极不安全的,下面,我们就给Eureka Server加上安全的用户认证。
6.1 配置Eureka Server
6.1.1 引入坐标依赖
在pom.xml中添加spring-boot-starter-seurity的依赖,该依赖为Eureka Server提供用户认证的能力。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
6.1.2 配置application.yml
修改 application.properties 增加以下配置
如何不进行配置,则默认用户名是 user ,默认密码是一个随机值,会在项目启动时打印出来。
spring:security:user:name: adminpassword: admin123
6.1.3 关闭认证
在Eureka Server中添加如下配置类即可关闭Csrf校验
@Configurationpublic class EurekaConfiguration {/*** 2.1版本的security默认加上了 csrf 拦截, 所以需要通过重写方法, 把csrf拦截禁用* 不写,客户端无法注册服务*/@EnableWebSecuritystatic class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable();super.configure(http);}}}
6.1.4 启动项目
启动项目,访问 http://localhost:8080/ 即可看见身份验证的对话框,输出设置的用户名和密码即可进入。
6.2 配置Eureka Client
Eureka Server开启认证后,客户端默认情况下是无法注册的,只有认证才可以,当然配置很简单,只需修改defaultZone即可:
http://${user.name}:${user.password}@${host}:${port}/eureka
defaultZone: http://admin:admin123@localhost:8080/eureka/
修改完成后启动项目,查看控制台
7. 服务的监控
我们除了可以在Eureka控制面板中监控微服务的状态外,我们还可以结合springboot-admin查看服务的具体参数,运行参数等
添加模块admin-server 主要用作监控的服务端,被监控的服务作为客户端
7.1 配置admin-server
7.1.1 引入坐标依赖
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.3.1</version></dependency><!--因为admin服务也属于微服务中的模块,所以将admin-server注册到Eureka中这样做还有个好处,admin-server能自动从注册中心中获取其他服务的信息--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
7.1.2 配置application.yml
server:port: 8083spring:application:name: admin-servereureka:client:# eureka server的路径serviceUrl:defaultZone: http://admin:admin123@localhost:8080/eureka/instance:#使用ip注册prefer-ip-address: true# 续约更新时间间隔,一般设置比续约到期时间少,该配置表示,每隔30秒就向服务端发送心跳。lease-renewal-interval-in-seconds: 30# 续约到期时间,可以单独给每个服务设置,如果在90秒(默认)内没有给服务发送心跳,则剔除该服务。lease-expiration-duration-in-seconds: 90# springboot-admin 相关配置management:endpoints:web:exposure:#开放所有页面节点 默认只开启了health、info两个节点include: \'*\'endpoint:health:#显示健康具体信息 默认不会显示详细信息show-details: always# 利用info端点,将版本等信息加入到springboot-admin中info:name: @project.artifactId@group: @project.groupId@version: @project.version@description: @project.description@#还可以自定义信息author: ldx
7.1.3 修改启动类
添加@EnableAdminServer注解,将其标记为admin server
@EnableAdminServer@SpringBootApplicationpublic class AdminServerApplication {public static void main(String[] args) {SpringApplication.run(AdminServerApplication.class, args);}}
7.1.4 启动项目
启动项目,访问
localhost:8083
点击应用墙进入admin-server详情页面
在详情页面就可以查看服务的各种详情信息,还可以进入日志配置,热修改服务的日志级别
7.2 配置admin-client
将其他服务注册到admin-server中
以provider服务为例
7.2.1 引入依赖坐标
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId></dependency>
7.2.2 配置application.yml
server:port: 8082spring:# 不用再添加admin-server的地址了,因为服务可以通过Eureka注册中心自动的将服务注册到admin-server中# boot:# admin:# client:# url: http://localhost:8083application:name: providereureka:client:# eureka server的路径serviceUrl:defaultZone: http://admin:admin123@localhost:8080/eureka/# 每隔30秒就去注册中心拉取注册表信息。registry-fetch-interval-seconds: 30#需要将我的服务注册到eureka上register-with-eureka: trueinstance:#使用ip注册prefer-ip-address: true# 实例名称 最后呈现地址:ip:port# 默认值为:${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}instance-id: ${spring.cloud.client.ip-address}:${server.port}# 续约更新时间间隔,一般设置比续约到期时间少,该配置表示,每隔30秒就向服务端发送心跳。lease-renewal-interval-in-seconds: 30# 续约到期时间,可以单独给每个服务设置,如果在90秒(默认)内没有给服务发送心跳,则剔除该服务。lease-expiration-duration-in-seconds: 90management:endpoints:web:exposure:#开放所有页面节点 默认只开启了health、info两个节点include: \'*\'endpoint:health:#显示健康具体信息 默认不会显示详细信息show-details: always# 利用info端点,加入版本等信息info:name: @project.artifactId@group: @project.groupId@version: @project.version@description: @project.description@#还可以自定义信息author: ldx
7.2.3 启动项目
查看admin-server控制台
查看服务详情信息
8. Eureka 服务下线
比如有些情况是服务主机意外宕机了,也就意味着服务没办法给 eureka 心跳信息了,但是 eureka 在没有接受到心跳的情况下依赖维护该服务 90s,在这 90s 之内可能会有客户端调用 到该服务,这就可能会导致调用失败。所以我们必须要有一个机制能手动的立马把宕机的服 务从 eureka 服务列表中清除掉,避免被服务调用方调用到。
8.1 确定需要强行剔除的服务
8.2 执行接口
Eureka 提供了下线接口 用delete 方式请求
http://{ip}:{port}/eureka/apps/服务名/应用id
8.3 查看Eureka控制台
刷新eureka 发现服务消失了
但是我们没有停止服务,等一会因为心跳会重新注册的
9. Eureka 高可用
高可用是在服务架构设计中,频繁出现的词汇。微服务架构里自然也一样需要保证服务的高可用性,所以本小节将简单说明一下Eureka是如何实现高可用的。
在实际生产环境中服务器是很脆弱的,单台服务器肯定是无法满足高可用的需求,为了保证高可用性我们通常会准备多台服务器。但可以发现上文中所搭建的eureka server是单机的,若这个eureka server宕机,则会导致与之关联的全部微服务发生故障。
在微服务中我们要考虑到发生故障的情况,所以说对服务注册中心也要进行高可用部署。
官方对于Eureka 高可用的描述:
Eureka can be made even more resilient and available by running multiple instances and asking them to register with each other. In fact, this is the default behaviour, so all you need to do to make it work is add a valid serviceUrl to a peer, e.g.
就是通过多个eureka实例进行互相注册,然后修改每个实例的serviceUrl即可。Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
9.1 单点配置
之前eureka-server的单点配置
不让服务注册中心注册自己
server:port: 8080eureka:instance:hostname: localhostclient:# 是否将自己注册到Eureka服务中,本身就是所有无需注册registerWithEureka: false# 是否从Eureka中获取注册信息fetchRegistry: false# 客户端与Eureka服务端进行交互的地址serviceUrl:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
9.2 高可用配置
如果有三个Eureka,则每一个EurekaServer都需要注册到其它几个Eureka服务中,例如:有三个分别为8066、 8077、8088,则:
8066要注册到8077和8088上
8077要注册到8066和8088上
8088要注册到8066和8077上
动手搭建高可用的EurekaServer
9.2.1 创建三份application.yml
修改hosts文件 添加peer1,peer2,peer3 域名
application-8066.yml
设置port为8066,hostname为peer1,application.name为eureka-server,并将其注册到peer2和peer3中其余基本都为默认配置
必须将eureka.client.registerWithEureka 和 eureka.client.fetchRegistry 设置为true
server:port: 8066eureka:instance:hostname: peer1client:# 是否将自己注册到Eureka服务中registerWithEureka: true# 是否从Eureka中获取注册信息fetchRegistry: true# 客户端与Eureka服务端进行交互的地址serviceUrl:defaultZone: http://admin:admin123@peer2:8077/eureka/,http://admin:admin123@peer3:8088/eureka/server:#自我保护模式,当出现出现网络分区、eureka 在短时间内丢失过多客户端时,会进入自我保护模式#即一个服务长时间没有发送心跳,eureka 也不会将其删 除,默认为 trueenable-self-preservation: true#Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低 于 85%#如果低于 85%,Eureka Server 会将这些实例保护起来renewal-percent-threshold: 0.85#eureka server 清理无效节点的时间间隔,默认 60000 毫秒,即 60 秒eviction-interval-timer-in-ms: 60000spring:security:user:name: adminpassword: admin123application:name: eureka-server
application-8077.yml
设置port为8077,hostname为peer2,application.name为eureka-server,并将其注册到peer1和peer3中其余基本都为默认配置
必须将eureka.client.registerWithEureka 和 eureka.client.fetchRegistry 设置为true
server:port: 8077eureka:instance:hostname: peer2client:# 是否将自己注册到Eureka服务中,本身就是所有无需注册registerWithEureka: true# 是否从Eureka中获取注册信息fetchRegistry: true# 客户端与Eureka服务端进行交互的地址serviceUrl:defaultZone: http://admin:admin123@peer1:8066/eureka/,http://admin:admin123@peer3:8088/eureka/server:#自我保护模式,当出现出现网络分区、eureka 在短时间内丢失过多客户端时,会进入自我保护模式#即一个服务长时间没有发送心跳,eureka 也不会将其删 除,默认为 trueenable-self-preservation: true#Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低 于 85%#如果低于 85%,Eureka Server 会将这些实例保护起来renewal-percent-threshold: 0.85#eureka server 清理无效节点的时间间隔,默认 60000 毫秒,即 60 秒eviction-interval-timer-in-ms: 60000spring:security:user:name: adminpassword: admin123application:name: eureka-server
application-8088.yml
设置port为8088,hostname为peer3,application.name为eureka-server,并将其注册到peer1和peer2中其余基本都为默认配置
必须将eureka.client.registerWithEureka 和 eureka.client.fetchRegistry 设置为true
server:port: 8088eureka:instance:hostname: peer3client:# 是否将自己注册到Eureka服务中,本身就是所有无需注册registerWithEureka: true# 是否从Eureka中获取注册信息fetchRegistry: true# 客户端与Eureka服务端进行交互的地址serviceUrl:defaultZone: http://admin:admin123@peer1:8066/eureka/,http://admin:admin123@peer2:8077/eureka/server:#自我保护模式,当出现出现网络分区、eureka 在短时间内丢失过多客户端时,会进入自我保护模式#即一个服务长时间没有发送心跳,eureka 也不会将其删 除,默认为 trueenable-self-preservation: true#Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低 于 85%#如果低于 85%,Eureka Server 会将这些实例保护起来renewal-percent-threshold: 0.85#eureka server 清理无效节点的时间间隔,默认 60000 毫秒,即 60 秒eviction-interval-timer-in-ms: 60000spring:security:user:name: adminpassword: admin123application:name: eureka-server
注意
Eureka高可用部署,启动多个注册中心后,节点均出现在unavailable-replicas,查阅各类资料测试,提供方案
- eureka.client.serviceUrl.defaultZone配置项的地址,不能使用localhost,要使用域名(测试使用ip也不行,不知道是不是因为单机测试的问题,最好还是用域名)。
- spring.application.name要一致,不然注册的client服务只能发现配置第一个server。
- fetch-registry、register-with-eureka 都需要设置为true,要不然集群服务器数据不同步。
9.2.2 创建相应的启动模板
创建三个对应的启动模板
9.2.3 启动程序
9.2.4 访问注册中心
浏览器输入
localhost:8066
输入认证信息
显示有两个可用的副本,当然也可以访问8077,8088 内容类似 都展示了其他两个的副本
9.2.5 客户端配置
以provider模块为例
为defaultZone 参数添加集群配置,将其注册到多个server中
此时如果断开8866,则provider也会向8077上注册。所以依然能够访问到provider服务,从而实现服务注册中心的高可用。
server:port: 8082spring:application:name: providereureka:client:# eureka server的路径serviceUrl:defaultZone: http://admin:admin123@peer1:8066/eureka/,http://admin:admin123@peer2:8077/eureka/,http://admin:admin123@peer3:8088/eureka/# 每隔30秒就去注册中心拉取注册表信息。registry-fetch-interval-seconds: 30#需要将我的服务注册到eureka上register-with-eureka: trueinstance:#使用ip注册prefer-ip-address: true# 实例名称 最后呈现地址:ip:port# 默认值为:${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}instance-id: ${spring.cloud.client.ip-address}:${server.port}# 续约更新时间间隔,一般设置比续约到期时间少,该配置表示,每隔30秒就向服务端发送心跳。lease-renewal-interval-in-seconds: 30# 续约到期时间,可以单独给每个服务设置,如果在90秒(默认)内没有给服务发送心跳,则剔除该服务。lease-expiration-duration-in-seconds: 90management:endpoints:web:exposure:#开放所有页面节点 默认只开启了health、info两个节点include: \'*\'endpoint:health:#显示健康具体信息 默认不会显示详细信息show-details: always# 利用info端点,加入版本等信息info:name: @project.artifactId@group: @project.groupId@version: @project.version@description: @project.description@#还可以自定义信息author: ldx
10. 配置属性
名称 | 默认 | 描述 |
---|---|---|
eureka.client.eureka-connection-idle-timeout-seconds |
30 |
指示与eureka服务器的HTTP连接在关闭之前可以保持空闲状态的时间(以秒为单位)。在AWS环境中,建议将该值设置为30秒或更短,因为防火墙会在几分钟后清除连接信息,使连接处于混乱状态,从而清理连接信息。 |
eureka.client.eureka-server-connect-timeout-seconds |
5 |
指示与eureka服务器的连接需要超时之前要等待的时间(以秒为单位)。请注意,客户端中的连接由org.apache.http.client.HttpClient池化,此设置影响实际的连接创建以及从池中获取连接的等待时间。 |
eureka.client.eureka-server-d-n-s-name | 获取要查询以获取eureka服务器列表的DNS名称。如果合同通过实现serviceUrls返回服务URL,则不需要此信息。当useDnsForFetchingServiceUrls设置为true且eureka客户端希望DNS以某种方式配置时,将使用DNS机制,以便它可以动态获取更改的eureka服务器。这些更改在运行时有效。 | |
eureka.client.eureka-server-port | 当eureka服务器列表来自DNS时,获取用于构造服务URL以便与eureka服务器联系的端口。如果合同返回服务URL eurekaServerServiceUrls(String),则不需要此信息。当useDnsForFetchingServiceUrls设置为true且eureka客户端希望DNS以某种方式配置时,将使用DNS机制,以便它可以动态获取更改的eureka服务器。这些更改在运行时有效。 | |
eureka.client.eureka-server-read-timeout-seconds |
8 |
指示从尤里卡服务器读取超时需要等待多长时间(以秒为单位)。 |
eureka.client.eureka-server-total-connections |
200 |
获取从eureka客户端到所有eureka服务器的允许的连接总数。 |
eureka.client.eureka-server-total-connections-per-host |
50 |
获取从eureka客户端到eureka服务器主机的允许的连接总数。 |
eureka.client.eureka-server-url-context | 当eureka服务器列表来自DNS时,获取用于构造服务URL以便与eureka服务器联系的URL上下文。如果合同从eurekaServerServiceUrls返回服务URL,则不需要此信息。当useDnsForFetchingServiceUrls设置为true且eureka客户端希望DNS以某种方式配置时,将使用DNS机制,以便它可以动态获取更改的eureka服务器。这些更改在运行时有效。 | |
eureka.client.eureka-service-url-poll-interval-seconds |
0 |
指示轮询尤里卡服务器信息更改的频率(以秒为单位)。可以添加或删除Eureka服务器,并且此设置控制eureka客户端应该多久知道一次。 |
eureka.client.prefer-same-zone-eureka |
true |
指示此实例是否应出于延迟和/或其他原因尝试在同一区域中使用eureka服务器。理想情况下,将eureka客户端配置为与同一区域中的服务器进行通信,这些更改在运行时在下一个注册表获取周期生效(如registryFetchIntervalSeconds所指定) |
eureka.client.register-with-eureka |
true |
指示此实例是否应在eureka服务器上注册其信息以供他人发现。在某些情况下,您不希望发现实例,而只希望发现其他实例。 |
eureka.server.peer-eureka-nodes-update-interval-ms |
0 |
|
eureka.server.peer-eureka-status-refresh-time-interval-ms |
0 |
|
ribbon.eureka.enabled |
true |
允许将Eureka与功能区一起使用。 |
spring.cloud.loadbalancer.eureka.approximate-zone-from-hostname |
false |
用于确定是否应尝试
zone 从主机名获取值。 |