SpringCloud核心组件总结


前几篇写了spring cloud的几个核心组件的原理和一些代码实现,这篇通篇总结一下。

首先将了微服务和微服务架构的区别,然后明确了微服务架构中面临的主要挑战,紧接着引出了基于spring cloud的分布式微服务开发框架,及其中的核心组件及作用,包括eureka注册中心、ribbon&feign客户端服务负载均衡与面向接口调用工具、hystrix服务熔断与降级、zuul通用api网关服务者四大组件,下面就从头到尾串联一下这些内容。

微服务指的是任何一个体积足够小、功能足够简单的服务,它可以是java开发的,也可以是go、node、python开发的,而微服务架构则是一种架构模式,它首先通过服务拆分将整个业务功能拆分层一个个独立的微服务,然后通过一些通用的服务和组件将他们组装在一起形成一个整体对外提供服务,微服务架构的核心我个人理解不是服务,而是服务治理,例如服务注册于发现、调用链跟踪、服务的熔断与降级等等。

spring cloud是目前java领域最流行的微服务开发框架之一,它基于spring boot构建,spring boot作为构建微服务的支撑,同时提供了一系列的组件用来完成微服务架构下的服务治理工作。

服务治理的最核心功能应该是服务注册于发现,spring cloud通过eureka来实现这个功能,spring cloud eureka是spring对netflix eureka的封装,相对于dubbo zookeeper注册中心来说,eureka遵循cap定理的ap,即保证了可用性,但在一致性方面做了妥协,从eureka集群架构上我们也可以看出来,eureka集群中并没有类似于master的东西,而是各个节点之间通过复制数据的方式来尽量的保证数据的一致性,所以也就造成了在任意时刻,不同的eureka server中的数据会有微小的差异,因此,在进行服务消费的时候需要做好服务降级的处理工作,因为有可能会访问到一个不可用的服务。

整个的eureka架构分为客户端和服务端,服务端主要负责对服务列表的维护,提供相应的http接口,同时会定时检测每个服务的心跳续约,默认没60秒检查一次,如果一个服务的心跳续约在90秒内没有刷新的话,这个服务就会被eureka server踢出服务列表,对于客户端来说,其实就可简单理解成是一个个服务了,从eureka的角度老说eureka client并没有provider和consumer的区别,客户端主要做两件事,第一是在服务启动的时候向eureka server注册服务信息,第二是以心跳的方式向eureka server发送心跳续约请求,保证服务注册信息的有效性,这个心跳续约的执行频率默认是30秒一次,另外eureka还有一个非常有趣的功能就是自我保护机制,在默认情况下,在15分钟内,如果有效的心跳续约请求不足85%的话,eureka 就会进入到自我保护机制,此时服务列表就会被冷冻,不能进行任何服务信息的删除操作,这主要是为了解决分布式环境下的网络抖动带来的消息丢失的问题,这种情况下并不是服务真的不能用,知识由于网络的原因,客户端的心跳续约请求有部分丢失,如果直接将服务踢出服务列表的话是不合适的。

由于spring cloud是基于http协议进行调用的,按照正常来说,需要提供ip和端口号,但是这不符合微服务治理的要求,因为这中调用方式已经脱离了注册中心,ribbon就是为了解决这个问题的,ribbon的最主要的功能就是面向服务名称的调用,即将ip和端口替换成服务名称,同时,它还提供了负载均衡功能,简单理解,ribbon就是与注册中心eureka关联,当基于服务名称进行调用时,首先从eureka获取所有的服务提供者地址,然后按照指定的负载均衡算法找到一个具体的provider再进行http调用,但此时还是通过RestTemplate进行调用,使用起来很不方便,索引就出现了feign,feign是对ribbon的进一步封装,使得对基于RestTemplate的调用被转换成了对java接口的调用,同时feign还提供了注入超时时间设置、数据压缩等功能,进一步对ribbon进行了升级。

hystrix的主要功能是提供服务熔断和降级的功能,同时它也有一定的服务限流的功能。在微服务架构下,一个客户端请求通常对应了后端的多个服务,而且调用链往往比较深,服务与服务之间的调用也错综复杂,一但有一个服务不可用或响应缓慢就会导致服务报错或请求堆积,造成服务的雪崩,为了解决这个问题,spring cloud引入了hystrix,基于hystrix的的处理流程是这样的,首先会判断hystrix的熔断器是否开启,如果开启,则直接返回给用户降级结果(降级方式包括fallback method和fallback factory两种),如果熔断器未开启,则判断线程池和信号量是否已经达到处理上限,如果是则返回降级结果,否则进行服务调用,如果调用过程中出现错误或超时,此时会将metrics上报错误信息,metrics会统计一个窗口期内的错误占比,来控制断路器是否开启。

下面逐一总结一下hystrix的两种隔离策略和断路器的触发条件。hystrix提供了线程池隔离和信号量隔离两种隔离策略,基于线程池的隔离策略是通过线程池将用户请求线程和服务调用线程分离,用户线程通过Future的方式来持有服务调用线程,这种隔离策略的效率比较高,同时支持异步调用和超时控制,基于信号量的隔离级别本质上就是一个计数器,可以简单理解为Semaphore,可以通知并发数,但用户线程和服务调用没有分离,一个线程怼到底,不支持异步,多数情况下都会使用基于线程池的隔离策略,另外由于线程池和信号量都是有限资源,所以也有一定的限流的作用。

对于熔断器的触发规则是基于滑动窗口的,默认一个滑动窗口是10秒,一个滑动窗口被分成10个bucket,metrics会统计每个bucket内部的错误数,当错误占比达到指定阈值并且滑动窗口内的请求数量已达到最低限制时,就会开启熔断器。例如规定在一个滑动窗口内最少有20个请求,并且失败占比超过50%才触发熔断器开启。

当熔断器开启后,默认在60秒内会尝试自动回复,即重新检测相关指标是否满足条件。

zuul是spring cloud中的通用api网关服务,同为微服务开发框架的dubbo中并没有提供一个通用的api网关服务,一般我们如果使用dubbo构建微服务架构的时候回自己通过spring mvc这类的web层框架搭建api网关层。zuul作为api网关的主要作用是提供服务的路由,同时也提供了filter、负载均衡等功能,zuul的本质是Servlet + Ribbon,通过重写servlet的service方法嵌入filter的逻辑,并通过ribbon实现基于服务名称的调用,可以说实现原理还是比较简单的,另外zuul作为处理请求的最前端,我们也会利用它的filter实现例如限流和权限认证的逻辑。

下面简单描述一个各个组件的核心实现原理,eureka的实现原理相对比较服务,服务端本质是一个web server,检测心跳续约的功能通过定时任务完成,客户端是一个类似于http client的东西与server端进行http通信,心跳续约也是通过定时任务来实现。

ribbon的本质是对RestTemplate进行了一层封装,内部引入了LoadBalancerInterceptor对调用进行拦截,然后从eureka client的本地缓存中获取服务列表,并根据具体的负载均衡策略(IRule)从对应的服务列表中选择一个provider进行调用,从而实现了面向服务的调用和负载均衡的功能。

feign是对ribbon的封装,它实际上是利用spring的bean扫描和FactoryBean,将对应的接口以BeanDefinition的方式注册到IoC容器中,并将其与一个指定的FactoryBean关联,这样当对接口进行依赖注入的时候,就会调用对应的FactoryBean的getObject方法,而这里则是通过jdk动态地理的方式将请求转发到了Ribbon层,同时feign还依赖的hystrix提供了基于整个接口的服务降级策略。

hystrix在实现上大量使用的RxJava反应式编程,由于代码跟踪比较困难,小编目前也没搞的太明白,但在最外层,hystrix是通过spring api对@HystrixCommand注解进行扫描并创建对应的代理对象,来将调用请求接入Hystrix的。

Zuul的原理上面已经说了。

你可能感兴趣的:(Spring-Cloud)