SpringCloud之Eureka原理和eureka优雅停服和安全认证
文章目录1 Eureka1.1 什么是Eureka注册中心1.2 Eureka注册中心三种角色1.2.1 Eureka Server1.2.2 Application Service (Service Provider)1.2.3 Application Client (Service Consumer)1.3 原理图2 CAP2.1 什么是CAP原则2.1.1 数据一致性2.2 如何舍弃2.3
1 Eureka
1.1 什么是Eureka注册中心
Eureka 是Netflix开发的服务发现组件, 本身是一个基于 REST的服务。Spring Cloud将它集成在其子项目 spring-cloud-netflix 中, 以实现 Spring Cloud 的服务注册于发现, 同时还提供了负载均衡、 故障转移等能力。
1.2 Eureka注册中心三种角色
1.2.1 Eureka Server
通过 Register、 Get、 Renew 等接口提供服务的注册和发现。
1.2.2 Application Service (Service Provider)
服务提供方:把自身的服务实例注册到 Eureka Server 中
1.2.3 Application Client (Service Consumer)
服务调用方:通过 Eureka Server 获取服务列表, 消费服务
1.3 原理图

Register(服务注册): 把自己的 IP 和端口注册给 Eureka。Renew(服务续约): 发送心跳包, 每 30 秒发送一次。 告诉 Eureka 自己还活着。Cancel(服务下线): 当 provider 关闭时会向 Eureka 发送消息, 把自己从服务列表中删除。 防止 consumer 调用到不存在的服务。Get Registry(获取服务注册列表): 获取其他服务列表。Replicate(集群中数据同步): eureka 集群中的数据复制与同步。Make Remote Call(远程调用): 完成服务的远程调用。
1.4 Eureka 特点
可用性(AP原则):Eureka在设计时就紧遵AP原则,Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用,只不过查到的信息可能不是最新的(不保证强一致性)。去中心化架构:Eureka Server可以运行多个实例来构建集群,不同于ZooKeeper的选举 leader的过程,Eureka Server采用的是Peer to Peer对等通信。这是一种去中心化的架构,无master/slave之分,每一个Peer都是对等的。节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的serviceUrl指向其他节点。每个节点都可被视为其他节点的副本。请求自动切换:在集群环境中如果某台Eureka Server宕机,Eureka Client的请求会自动切换到新的Eureka Server节点上,当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中。节点间操作复制:当节点开始接受客户端请求时,所有的操作都会在节点间进行复制操作,将请求复制到该Eureka Server当前所知的其它所有节点中。自动注册&心跳:当一个新的Eureka Server节点启动后,会首先尝试从邻近节点获取所有注册列表信息,并完成初始化。Eureka Server通过getEurekaServiceUrls()方法获取所有的节点,并且会通过心跳契约的方式定期更新。自动下线:默认情况下,如果Eureka Server在一定时间内没有接收到某个服务实例的心跳(默认周期为30秒),Eureka Server将会注销该实例(默认为90秒,eureka.instance.lease-expiration-duration-in-seconds进行自定义配置)。保护模式:当Eureka Server节点在短时间内丢失过多的心跳时,那么这个节点就会进入自我保护模式。
除了上述特点,Eureka还有一种自我保护机制,如果在15分钟内超过 85% 的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务;Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)- 当网络稳定时,当前实例新注册的信息会被同步到其它节点中。
1.5 Eureka工作流程
了解完 Eureka 核心概念,自我保护机制,以及集群内的工作原理后,我们来整体梳理一下Eureka的工作流程:
Eureka Server启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过Replicate同步注册表,每个Eureka Server都存在独立完整的服务注册表信息。Eureka Client启动时根据配置的Eureka Server地址去注册中心注册服务。Eureka Client会每30s向Eureka Server发送一次心跳请求,证明客户端服务正常。- 当
Eureka Server 90s内没有收到Eureka Client的心跳,注册中心则认为该节点失效,会注销该实例。 - 单位时间内
Eureka Server统计到有大量的Eureka Client没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端。 - 当
Eureka Client心跳请求恢复正常之后,Eureka Server自动退出自我保护模式。 Eureka Client定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地。- 服务调用时,
Eureka Client会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。 Eureka Client获取到目标服务器信息,发起服务调用。Eureka Client程序关闭时向Eureka Server发送取消请求,Eureka Server将实例从注册表中删除。
Eureka 为了保障注册中心的高可用性,容忍了数据的非强一致性,服务节点间的数据可能不一致,Client-Server 间的数据可能不一致。比较适合跨越多机房、对注册中心服务可用性要求较高的使用场景。
2 CAP原理
3 eureka优雅停服
3.1 Eureka自我保护
3.1.1 自我保护的条件
一般情况下, 微服务在Eureka上注册后, 会每30秒发送心跳包,Eureka通过心跳来判断服务是否健康, 同时会定期删除超过90秒没有发送心跳服务。
3.1.2 Eureka Server收不到微服务的心跳
- 是微服务自身的原因
- 是微服务与
Eureka之间的网络故障,通常(微服务的自身的故障关闭)只会导致个别服务出现故障, 一般不会出现大面积故障, 而(网络故障)通常会导致Eureka Server在短时间内无法收到大批心跳。
考虑到这个区别,Eureka设置了一个阀值, 当判断挂掉的服务的数量超过阀值时,Eureka Server认为很大程度上出现了网络故障, 将不再删除心跳过期的服务。
3.1.3 eureka阀值
15分钟之内是否低于85%;Eureka Server在运行期间,会统计心跳失败的比例在15分钟内是否低于85%这种算法叫做Eureka Server的自我保护模式
3.2 为什么需要eureka自我保护
- 因为同时保留
好数据与坏数据总比丢掉任何数据要更好, 当网络故障恢复后,这个Eureka节点会退出自我保护模式。 Eureka还有客户端缓存功能(也就是微服务的缓存功能)。 即便Eureka集群中所有节点都宕机失效, 微服务的Provider和Consumer都能正常通信。- 微服务的
负载均衡策略会自动剔除死亡的微服务节点
3.3 关闭自我保护
修改 Eureka Server 配置文件
#关闭自我保护:true 为开启自我保护, false 为关闭自我保护
eureka.server.enableSelfPreservation=false
#清理间隔(从服务列表删除无用服务的时间间隔,单位:毫秒, 默认是 60*1000)
eureka.server.eviction.interval-timer-in-ms=60000
3.4 优雅停服
环境:springboot:2.1.3 springcloud:Greenwich.SR5
3.4.1 不需要在Eureka Server中配置关闭自我保护
3.4.2 添加actator的坐标依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3.4.3 修改properties文件
###### 优雅停服######
##启用 shutdown
management.endpoint.shutdown.enabled=true
# 暴露所有端点
management.endpoints.web.exposure.include=*
#禁用密码验证
management.endpoints.shutdown.sensitive=false
3.4.4 发送关闭服务的URL请求
post请求
public static String doPost(String url,Map<String,String> param) {
//创建HTTPClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try{
//创建httpget请求
HttpPost httpPost = new HttpPost(url);
if(MapUtils.isNotEmpty(param)) {
List<NameValuePair> paramList= new ArrayList<>();
param.forEach((a,b)->paramList.add(new BasicNameValuePair(a,b)));
//模拟表单
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramList,"utf-8");
//UrlEncodedFormEntity 来设置 body,消息体内容类似于“KEY1=VALUE1&KEY2=VALUE2&...
httpPost.setEntity(formEntity);
}
//执行请求
response = httpClient.execute(httpPost);
if(response.getStatusLine().getStatusCode()==200) {
System.out.println("========成功========");
resultString = EntityUtils.toString(response.getEntity(),"utf-8");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(response!=null)response.close();
httpClient.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
main方法发送
public static void main(String[] args) throws Exception {
String url ="http://127.0.0.1:9080/actuator/shutdown";
//该 url 必须要使用 dopost 方式来发送
HttpClientUtil.doPost(url,null);
}
在main方法发送后,就可以在本地看到启动的服务自己就关闭了,也可以在服务注册管理页面查看
4 eureka的安全认证
4.1 在Eureka Server中添加 security 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
4.2 修改Eureka Server配置文件
#开启 http basic 的安全认证 没有用 需要通过下面方法来关闭或开启
#spring.security.basic.enabled=true
spring.security.user.name=user
spring.security.user.password=123456
# 修改访问集群节点的 url
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka2:8761/eureka/
4.3 修改微服务的配置文件添加访问注册中心的用户名与密码
spring.application.name=eureka-provider
server.port=9090
#设置服务注册中心地址, 指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
#启用 shutdown
management.endpoints.shutdown.enabled=true
#禁用密码验证
management.endpoints.shutdown.sensitive=false
4.4 关闭csrf认证
Spring Cloud 2.0 以上的security默认启用了csrf检验,要在eurekaServer端配置security的csrf检验为false
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); //关闭csrf
//开启认证 若注释掉,就关闭认证了
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
更多推荐



所有评论(0)