单节点Eureka搭建
启动类
@EnableEurekaServer
@SpringBootApplication public class EurekaServerApplication{ public static void main(String[] args){ SpringApplication.run(EurekaServerApplication.class, args); } }
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
application.yml
eureka:
client:
register-with-eureka:false
fetch-registry:false
service-url:
defaultZone:http://localhost:7900/eureka/
Eureka多结点
eureka所有操作调用, 全部是基于Restful协议的
application-euk1.yml
eureka:
client:
register-with-eureka:false
fetch-registry:false
service-url:
defaultZone:http://euk2.com:7002/eureka/
instance:
hostname:euk1.com
server:
port:7001
application-euk2.yml
eureka:
client:
register-with-eureka:false
fetch-registry:false
service-url:
defaultZone:http://euk1.com:7001/eureka/
instance:
hostname:euk2.com
server:
port:7002
application.yml
spring:
profiles:
active:euk1
Register
服务注册
想要参与服务注册发现的实例首先需要向Eureka服务器注册信息
注册在第一次心跳发生时提交
Renew
续租(模型概念),心跳(实现方式)
Eureka客户需要每30秒发送一次心跳来续租
10:00 00 第一次
10:00 30
10:01
10:01 30 最后
更新通知Eureka服务器实例仍然是活动的。如果服务器在90秒内没有看到更新,它将从其注册表中删除实例
Fetch Registry
Eureka客户端从服务器获取注册表信息并将其缓存在本地。
之后,客户端使用这些信息来查找其他服务。
通过获取上一个获取周期和当前获取周期之间的增量更新,可以定期(每30秒)更新此信息。
节点信息在服务器中保存的时间更长(大约3分钟),因此获取节点信息时可能会再次返回相同的实例。Eureka客户端自动处理重复的信息。
在获得增量之后,Eureka客户机通过比较服务器返回的实例计数来与服务器协调信息,如果由于某种原因信息不匹配,则再次获取整个注册表信息。
Cancel
Eureka客户端在关闭时向Eureka服务器发送取消请求。这将从服务器的实例注册表中删除实例,从而有效地将实例从通信量中取出。
Time Lag
同步时间延迟
来自Eureka客户端的所有操作可能需要一段时间才能反映到Eureka服务器上,然后反映到其他Eureka客户端上。这是因为eureka服务器上的有效负载缓存,它会定期刷新以反映新信息。Eureka客户端还定期地获取增量。因此,更改传播到所有Eureka客户机可能需要2分钟。
Communication mechanism
通讯机制
Http协议下的Rest请求
默认情况下Eureka使用Jersey和Jackson以及JSON完成节点间的通讯
服务注册
新建一个web项目,引入starter spring-cloud-starter-netflix-eureka-client
客户端配置选项
#续约发送间隔默认30秒,心跳间隔
eureka.instance.lease-renewal-interval-in-seconds=5
#表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
eureka.client.registry-fetch-interval-seconds=5
# 续约到期时间(默认90秒)
eureka.instance.lease-expiration-duration-in-seconds=60
服务端配置选项
#关闭自我保护模式
eureka.server.enable-self-preservation=false
#失效服务间隔
eureka.server.eviction-interval-timer-in-ms=3000
Rest风格协议
官方地址:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
Eureka元数据
application.yml
eureka:
instance:
metadata-map:
dalao:test
Eureka的元数据有两种:标准元数据和自定义元数据。
标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
自定义元数据:可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但是一般不改变客户端行为,除非客户端知道该元数据的含义。
可以在配置文件中对当前服务设置自定义元数据,可后期用户个性化使用
元数据可以配置在eureka服务器和eureka的客户端上
EurekaClient
EurekaClient 可以在客户端获取eureka服务器上的注册者信息
org.springframework.cloud.client.discovery与com.netflix.discovery.DiscoveryClient
- org.springframework.cloud.client.discovery是SpringCloud对注册中心client的抽象封装,提供公用功能
- org.springframework.cloud.client.discovery定义用来服务发现的客户端接口。
- 是客户端进行服务发现的核心接口是spring cloud用来进行服务发现的顶级接口,在common中可以看到其地位。
- 在Netflix Eureka和Consul中都有具体的实现类。
代表通用于服务发现的读操作,例如在 eureka或consul中。
String description();//获取实现类的描述。 List<String> getServices();//获取所有服务实例id。 List<ServiceInstance> getInstances(String serviceId);//通过服务id查询服务实例信息列表。
com.netflix.discovery.DiscoveryClient为Eureka注册中心客户端的接口,功能更丰富
自我保护机制
Eureka在CAP理论当中是属于AP , 也就说当产生网络分区时,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 Server在一定时间内,没有接收到某个微服务心跳,会将某个微服务注销(90S)
但是当网络故障时,微服务与Server之间无法正常通信,上述行为就非常危险,因为微服务正常,不应该注销
Eureka Server通过自我保护模式来解决整个问题,当Server在短时间内丢失过多客户端时,那么Server会进入自我保护模式,会保护注册表中的微服务不被注销掉。
当网络故障恢复后,退出自我保护模式。
思想:宁可保留健康的和不健康的,也不盲目注销任何健康的服务。
自我保护触发
客户端每分钟续约数量小于客户端总数的85%时会触发保护机制
自我保护机制的触发条件:
- 每分钟心跳次数( renewsLastMin ) 小于 numberOfRenewsPerMinThreshold 时
- 并且开启自动保护模式开关( eureka.server.enable-self-preservation = true ) 时,触发自我保护机制,不再自动过期租约
- numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比
- ( eureka.server.renewalPercentThreshold, 默认0.85 )
expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2
为什么乘以 2:
默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x2
服务实例数:10个,期望每分钟续约数:10 * 2=20,期望阈值:20*0.85=17,自我保护少于17时触发
Actuator监控应用
添加依赖,官方地址:https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
默认端点
springboot2.0只暴露了health和info端点,提供的监控信息无法满足需求
application.yml
management:
endpoints:
web:
exposure:
include:*
Eureka 健康检查
由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问
看eureka界面中的status
- 比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务,我们需要将微服务的健康状态也同步到server
- 只需要启动eureka的健康检查就行,这样微服务就会将自己的健康状态同步到eureka
添加依赖,官方地址:
application.yml
eureka:
client:
healthcheck:
enabled: true
HealthStatusService
@Service public class HealthStatusService implements HealthIndicator{ private Boolean status = true; public void setStatus(Boolean status) { this.status = status; } @Override public Health health() { // TODO Auto-generated method stub if(status) return new Health.Builder().up().build(); return new Health.Builder().down().build(); } public String getStatus() { // TODO Auto-generated method stub return this.status.toString(); } }
Controller
@GetMapping("/health") public String health(@RequestParam("status") Boolean status) { healthStatusSrv.setStatus(status); return healthStatusSrv.getStatus(); }
开启Eureka安全连接,application.yml
spring:
security:
user:
name:test
password:test
如果服务注册报错
Root name 'timestamp' does not match expected ('instance') for type [simple
是默认开启了防止跨域攻击
手动关闭
在服务端增加配置类
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { // TODO Auto-generated method stub http.csrf().disable(); super.configure(http); } }