Spring Cloud 系列之 Netflix Eureka 注册中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Netflix Eureka 注册中心(一)
本篇文章讲解 Eureka 集群、架构原理、自我保护、优雅停服、安全认证等功能实现。
1|0高可用 Eureka 注册中心
点击链接观看:高可用 Eureka 注册中心视频(获取更多请关注公众号「哈喽沃德先生」)
1|1注册中心 eureka-server
创建项目
在 Spring Cloud 系列之 Netflix Eureka 注册中心(一)的项目父工程下再创建一个 eureka-server02
注册中心的项目,如果是多机器部署不用修改端口,通过 IP 区分服务,如果在一台机器上演示需要修改端口区分服务。
添加依赖
pom.xml
配置文件
集群配置下,注册中心需要相互注册实现信息的同步。
eureka-server 的 application.yml
eureka-server02 的 application.yml
启动类
启动类不变,启动两个 server。
访问
访问:http://localhost:8761/ 或者 http://localhost:8762/ 都出现如下图说明互相注册成功。
Status
显示方式为默认值,如果想要清晰可见每个服务的 IP + 端口需要通过以下配置来实现。
显示 IP + 端口
一个普通的 Netflix Eureka 实例注册的 ID 等于其主机名(即,每个主机仅提供一项服务)。 Spring Cloud Eureka 提供了合理的默认值,定义如下:spring.cloud.client.hostname:spring.cloud.client.hostname:{spring.application.name}:\({spring.application.instance_id:\){server.port}}},也就是:主机名:应用名:应用端口。
我们也可以可以自定义进行修改:
1|2服务提供者 service-provider
点击链接观看:服务提供者 service-provider 视频(获取更多请关注公众号「哈喽沃德先生」)
创建项目
在刚才的父工程下创建一个 service-provider
服务提供者的项目。
添加依赖
pom.xml
配置文件
application.yml
实体类
Product.java
编写服务
ProductService.java
ProductServiceImpl.java
控制层
ProductController.java
该项目我们可以通过单元测试进行测试,也可以直接通过 url 使用 postman 或者浏览器来进行测试。
启动类
ServiceProviderApplication.java
注册中心
访问注册中心,可以看到用户服务已经注册至注册中心。
1|3服务消费者 service-consumer
创建项目
在刚才的父工程下创建一个 service-consumer 服务消费者的项目。
添加依赖
pom.xml
配置文件
application.yml
实体类
Product.java
Order.java
消费服务
OrderService.java
对于服务的消费我们这里讲三种实现方式:
- DiscoveryClient:通过元数据获取服务信息
- LoadBalancerClient:Ribbon 的负载均衡器
- @LoadBalanced:通过注解开启 Ribbon 的负载均衡器
DiscoveryClient
点击链接观看:DiscoveryClient 视频(获取更多请关注公众号「哈喽沃德先生」)
Spring Boot 不提供任何自动配置的RestTemplate
bean,所以需要在启动类中注入 RestTemplate
。
OrderServiceImpl.java
LoadBalancerClient
点击链接观看:LoadBalancerClient 视频(获取更多请关注公众号「哈喽沃德先生」)
OrderServiceImpl.java
@LoadBalanced
点击链接观看:@LoadBalanced 视频(获取更多请关注公众号「哈喽沃德先生」)
启动类注入 RestTemplate
时添加 @LoadBalanced
负载均衡注解,表示这个 RestTemplate
在请求时拥有客户端负载均衡的能力。
OrderServiceImpl.java
控制层
OrderController.java
访问
访问:http://localhost:9090/order/1
2|0Eureka 架构原理
- Register(服务注册):把自己的 IP 和端口注册给 Eureka。
- Renew(服务续约):发送心跳包,每 30 秒发送一次,告诉 Eureka 自己还活着。如果 90 秒还未发送心跳,宕机。
- Cancel(服务下线):当 Provider 关闭时会向 Eureka 发送消息,把自己从服务列表中删除。防止 Consumer 调用到不存在的服务。
- Get Registry(获取服务注册列表):获取其他服务列表。
- Replicate(集群中数据同步):Eureka 集群中的数据复制与同步。
- Make Remote Call(远程调用):完成服务的远程调用。
3|0CAP 原则
CAP 原则又称 CAP 定理,指的是在一个分布式系统中具有以下其中两个特性:
- Consistency (一致性)
- Availability (可用性)
- Partition tolerance(分区容错性)
CAP 由 Eric Brewer 在 2000 年 PODC 会议上提出。该猜想在提出两年后被证明成立,成为我们熟知的 CAP 定理。CAP 三者不可兼得。
特性 | 定理 |
---|---|
Consistency | 也叫做数据原子性,系统在执行某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。等同于所有节点访问同一份最新的数据副本。 |
Availability | 每一个操作总是能够在一定的时间内返回结果,这里需要注意的是"一定时间内"和"返回结果"。一定时间内指的是,在可以容忍的范围内返回结果,结果可以是成功或者是失败。 |
Partition tolerance | 在网络分区的情况下,被分隔的节点仍能正常对外提供服务(分布式集群,数据被分布存储在不同的服务器上,无论什么情况,服务器都能正常被访问)。 |
3|1取舍策略
CAP 三个特性只能满足其中两个,那么取舍的策略就共有三种:
- CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但放弃 P 的同时也就意味着放弃了系统的扩展性,也就是分布式节点受限,没办法部署子节点,这是违背分布式系统设计的初衷的。
- CP without A:如果不要求A(可用),相当于每个请求都需要在服务器之间保持强一致,而P(分区)会导致同步时间无限延长(也就是等待数据同步完才能正常访问服务),一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。设计成 CP 的系统其实不少,最典型的就是分布式数据库,如 Redis、HBase 等。对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。
- AP without C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。
3|2总结
现如今,对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,节点只会越来越多,所以节点故障、网络故障是常态,因此分区容错性也就成为了一个分布式系统必然要面对的问题。那么就只能在 C 和 A 之间进行取舍。但对于传统的项目就可能有所不同,拿银行的转账系统来说,涉及到金钱的对于数据一致性不能做出一丝的让步,C 必须保证,出现网络故障的话,宁可停止服务,可以在 A 和 P 之间做取舍。
总而言之,没有最好的策略,好的系统应该是根据业务场景来进行架构设计的,只有适合的才是最好的。
4|0Eureka 自我保护
4|1启动自我保护条件
一般情况下,服务在 Eureka 上注册后,会每 30 秒发送心跳包,Eureka 通过心跳来判断服务是否健康,同时会定期删除超过 90 秒没有发送心跳的服务。
有两种情况会导致 Eureka Server 收不到微服务的心跳
- 微服务自身的原因
- 微服务与 Eureka 之间的网络故障
自我保护模式
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,同时提示一个警告。这种算法叫做 Eureka Server 的自我保护模式。
4|2为什么要启动自我保护
- 因为同时保留"好数据"与"坏数据"总比丢掉任何数据要更好,当网络故障恢复后,这个 Eureka 节点会退出"自我保护模式"。
- Eureka 还有客户端缓存功能(也就是微服务的缓存功能)。即使 Eureka 集群中所有节点都宕机失效,微服务的 Provider 和 Consumer 都能正常通信。
- 微服务的负载均衡策略会自动剔除死亡的微服务节点。
4|3如何关闭自我保护
注册中心配置自我保护
5|0Eureka 优雅停服
配置了优雅停服以后,将不需要 Eureka Server 中配置关闭自我保护。本文使用 actuator 实现。
5|1添加依赖
服务提供者添加 actuator 依赖
5|2配置文件
服务提供者配置度量指标监控与健康检查
5|3优雅停服
使用 POST 请求访问:http://localhost:7070/actuator/shutdown 效果如下
6|0Eureka 安全认证
6|1添加依赖
注册中心添加 security 依赖
6|2配置文件
注册中心配置安全认证
6|3修改访问集群节点的 url
核心代码就是有色部分:http://root:123456@
localhost:8762/eureka/
注册中心的配置文件
服务提供者的配置文件
服务消费者的配置文件
6|4过滤 CSRF
Eureka 会自动化配置 CSRF 防御机制,Spring Security 认为 POST, PUT, and DELETE http methods 都是有风险的,如果这些 method 发送过程中没有带上 CSRF token 的话,会被直接拦截并返回 403 forbidden。
官方给出了解决的方法,具体可以参考 spring cloud issue 2754,里面有大量的讨论,这里提供两种解决方案。
首先注册中心配置一个 @EnableWebSecurity
配置类,继承 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
,然后重写 configure
方法。
方案一
使 CSRF 忽略 /eureka/**
的所有请求
方案二
保持密码验证的同时禁用 CSRF 防御机制
6|5访问
使用配置好的用户名和密码登录以后可看到注册中心界面,启动服务提供者和服务消费者,功能正常使用,至此 Eureka 注册中心所有的知识点就讲解结束了。