Spring Cloud 原理
概述
本文先从其最核心的几个组件入手,来剖析一下其底层工作原理。也就是EurekaRibbonFeignHystrixuul
这几个组件
业务场景介绍
先来一个业务场景,假设开发一个电商网站,要实现支付订单的功能,流程如下:
-
创建一个订单之后,如果用户立刻支付了这个订单,我们需要将订单状态更新为"已支付"
-
扣减相应的商品库存
-
通知仓储中心,进行发货
-
给用户的这次购物增加相应的积分
针对上述流程,我们需要有订单服务、库存服务、仓储服务、积分服务
.整个流程的答题思路如下:
- 用户针对一个订单完成支付之后,就回去找订单服务,更新订单状态
- 订单服务调用库存服务,完成相应功能
- 订单服务调用仓储服务,完成相应功能
- 订单服务调用积分服务,完成相应功能
至此,整个支付订单的业务流程结束
各服务间的调用过程图:
对Spring Cloud 的主要组件做一下总结
Netflix Eureka
-
Eureka 服务端:也称服务注册中心,同其他服务注册中心一样,支持高可用配置。如果Eureka 以集群模式部署,当集群中有分片出现故障时,那么Eureka 就转入自我保护模式。它允许在分片故障期间继续提供服务的发现和注册,当故障分片恢复运行时,集群中其他分片会把它们的状态再次同步回来
-
Eureka客户端:主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,Eureka客户端想注册中心注册自身提供的服务并周期性发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性地刷新服务状态
-
Eureka Server 的高可用实际上就是将自己作为服务向其他注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用效果
Eureka 详解
服务提供者
- 服务注册
服务提供者在启动的时候会通过REST 请求的方式将自己注册到Eureka Server上,同时带上了自己的服务的一些元数据信息。Eureka Server接收到这个REST请求之后,将元数据信息存储在一个双层结构Map 中,其中第一层的key是服务名,第二层的key是具体服务的实例名
- 服务同步
两个服务提供者分别注册到了两个不同的服务注册中心上,也就是说,它们的信息分别被两个服务注册中心所维护。此时,由于服务注册中心之间因互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到
- 服务续约
在注册完服务之后,服务提供者会维护一个心跳用来维持告诉Eureka Server:我还活着,以防止Eureka Server 的提出任务将该服务实例从服务列表中排除出去,我们称该操作为服务续约
代码体现
# 定义服务续约任务的调用间隔时间 默认30秒
eureka.instance.lease-renewak-interval-in-seconds=30
# 定义服务失效的时间,默认90秒
eureka.instance.lease-expiration-duration-in-seconds=90
服务消费者
- 获取服务
当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server 会维护一份只读的服务来返回给客户端,同时该缓存清单会每隔30秒更新一次
代码实现
# 缓存清单的更新时间,默认30秒
eureka.client.registry-fetch-interval-seconds=30
- 服务调用
服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例名的元数据信息。在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡
对于访问实例的选择,Eureka中有Region和Zone的概念,一个Region中可以包含多个Zone,每个服务客户端需要被注册到一个Zone中,所以每个客户端对应一个Region和一个Zone。在进行服务调用的时候,优先访问同处一个一个Zone中的服务提供方,若访问不到,就访问其他的Zone
- 服务下线
当服务实例进行正常的关闭操作时,他会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。服务端在接收到请求之后,将该服务状态置为下线(DOWN),并把该下线事件传播出去