Spring Cloud全家桶是提供的一整套微服务开源解决方案,包括服务注册与发现、配置中心、全链路监控、服务网关、负载均衡、熔断器等组件。
服务注册:只有一个服务注册到注册中心,才可能被其他服务发现并调用;
服务发现:即一个服务通过注册中心发现了其他服务;
负载均衡:客户端维护一份从注册中心获取的Provider列表清单,根据自己配置的Provider负载均衡选择算法在客户端进行请求的分发。
服务调用:一个服务对另一个服务进行调用;
隔离、熔断与降级:通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现了不同的服务调度隔离;如果服务出现故障,通过服务熔断,避免服务雪崩的问题 ;并且通过服务降级,保证可以手动实现服务正常功能;
网关路由:如果前端调用后台系统,统一从网关进入,通过网关转发请求给对应的服务;
SpringCloud是Spring官方推出的微服务治理框架。
Zuul
微服务网关是微服务架构中不可或缺的部分,它统一解决Provider路由、均衡负载、权限控制等功能
路由:将不同REST请求转发至不同的微服务提供者,其作用类似于Nginx的反向代理。同时,也起到了统一端口的作用,将很多微服务提供者的不同端口统一到了Zuul的服务端口。
认证:网关直接暴露在公网上时,终端要调用某个服务,通常会把登录后的token(令牌)传过来,网关层对token进行有效性验证。如果token无效(或没有token),就不允许访问REST服务。可以结合Spring Security中的认证机制完成Zuul网关的安全认证。
限流:高并发场景下瞬时流量不可预估,为了保证服务对外的稳定性,限流成为每个应用必备的一道安全防火墙。如果没有这道安全防火墙,那么请求的流量超过服务的负载能力时很容易造成整个服务的瘫痪。
负载均衡:在多个微服务提供者之间按照多种策略实现负载均衡。
Eureka
在微服务架构系统中,由于各服务单元颗粒度较小、数量众多,相互之间呈现网状依赖关系,因此需要服务注册中心来统一管理微服务实例,维护各服务实例的健康状态。
Spring Cloud Eureka是Spring Cloud Netflix微服务套件的一部分,基于Netflix Eureka做了二次封装,主要负责完成微服务实例的自动注册与发现,这也是微服务架构中的核心和基础功能。
Eureka服务冶理体系中的三个核心角色:服务注册中心、服务提供者以及服务消费者,其中服务提供者以及服务消费者都属于Eureka Client。
Eureka Server的主要功能为服务注册表维护和服务健康检查;
Eureka Client的主要功能为服务注册、心跳续约与健康状况查询;
服务提供者的服务注册和心跳续约一般都会通过注册中心客户端组件来完成。注册中心客户端组件还有服务发现和实例缓存的功能;
Eureka Server 的设计一开始就考虑了高可用问题,将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
Ribbon
Ribbon就是一个客户端的负载均衡开源组件,是Netflix发布的开源项目。它不像服务注册中心Eureka Server、配置中心Spring Cloud Config那样独立部署,而是作为基础设施模块,几乎存在于每个Spring Cloud微服务提供者中。
Feign组件自身不具备负载均衡能力,Spring Cloud Feign是通过集成Ribbon组件实现客户端的负载均衡。微服务间的RPC调用以及API网关的代理请求的RPC转发调用,实际上都需要通过Ribbon来实现负载均衡。
Ribbon在客户端以轮询、随机、权重等多种方式实现负载均衡。
从Eureka Client实例获取Provider服务列表清单,并且定期通过IPing实例判断清单中Provider服务实例的可用性。每次RPC调用到来时,在Provider服务列表清单中根据IRule策略类的Bean计算出每次RPC要访问的最终Provider。
Feign
Feign 使用了动态代理,使用@FeignClient调用接口的本质就是调用Feign创建的动态代理,然后根据接口上的@RequestMapping等注解,来动态构造出要请求的服务的地址并对这个地址发起请求、解析响应。
在 Spring Cloud 中使用 Feign,可以做到使用 HTTP 请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问 HTTP 请求。
Feign 整合了 Ribbon 和 Hystrix,具备负载均衡、隔离、熔断与降级功能;
Hystrix
隔离:通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现了不同的服务调度隔离;
熔断:分布式架构中的熔断器主要用于RPC接口上,为接口安装上“保险丝”,以防止RPC接口出现拥塞时导致系统压力过大而引起的系统瘫痪,当RPC接口流量过大或者目标Provider出现异常时,熔断器及时切断故障可以起到自我保护的作用。
降级:当服务不可用(服务正在等待、链接超时、网络延迟、服务器响应慢等),客户端一直等待时,调用fallback方法给客户端返回一个错误提示,不让客户端继续等待。
微服务架构在高并发的场景下,我们的优化和保护系统的方式通常有:多级缓存、资源隔离、熔断、降级、限流等等。
本文主要讲解熔断、降级、限流已防止高并发。
对微服务的几个概念进行场景化实例描述:
拿下棋做比喻:
限流:相当于尽量避免同时和两三个人同时下棋
熔断:相当于你的一颗卒被围死了,就不要利用其它棋去救它了,弃卒保帅,否则救他的棋也可能被拖死
降级:相当于尽量不要走用处不大的棋了,浪费走棋机会(资源),使已经过河的棋有更多的走棋机会(资源)发挥最大作用
“雪崩”指的是访问服务集群时绝大部分请求都超时,且在流量减少时仍无法恢复的现象。
当流量超出服务的最大qps时,服务将无法正常服务;当流量恢复正常时(小于服务的处理能力),积压的请求会被处理,虽然其中很大一部分可能会因为处理的不及时而超时,但服务本身一般还是会恢复正常的。这就相当于一个水池有一个入水口和一个出水口,如果入水量大于出水量,水池子终将盛满,多出的水会溢出来。但如果入水量降到出水量之下,一段时间后水池总会排空。雪崩并不是单一服务能产生的。
如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。因此熔断是应对微服务雪崩效应的一种链路保护机制。
微服务之间的数据交互是通过远程调用来完成的。服务A调用服务,服务B调用服务c,某一时间链路上对服务 C的调用响应时间过长或者服务C不可用,随着时间的增长,对服务C的调用也越来越多,然后服务C崩溃了,但是链路调用还在,对服务B的调用也在持续增多,然后服务B崩溃,随之A也崩溃,导致雪崩效应。
在微服务架构中,熔断机制也是起着类似的作用。当调用链路的某个微服务不可用或者响应时间太长时,会进行服务熔断,不再有该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
熔断的3 种状态:CLOSED、OPEN、HALF OPEN
CLOSED:默认状态。断路器观察到请求失败比例没有达到阈值,断路器认为被代理服务状态良好。
OPEN:断路器观察到请求失败比例已经达到阈值,断路器认为被代理服务故障,打开开关,请求不再到达被代理的服务,而是快速失败。
HALF OPEN:断路器打开后,为了能自动恢复对被代理服务的访问,会切换到半开放状态,去尝试请求被代理服务以查看服务是否已经故障恢复。如果成功,会转成 CLOSED 状态,否则转到 OPEN 状态。
限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。
常见限流方式
基于请求限流:指从外部请求的角度考虑限流。
基于资源限流:指从系统内部考虑,找到影响性能的关键资源,对其使用上限限制。
目前主流的限流方法多采用 HPS 作为限流指标。
TPS
系统吞吐量是衡量系统性能的关键指标,按照事务的完成数量来限流是最合理的。
HPS
每秒请求数,指每秒钟服务端收到客户端的请求数量。
QPS
服务端每秒能够响应的客户端查询请求数量。
三种常见的限流算法
1、计数器算法
比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题。比如 他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。
其实是因为我们统计的精度太低。那么如何很好地处理这个问题呢?或者说,如何将临界问题的影响降低呢?我们可以看下面的滑动窗口算法
滑动窗口,又称rolling window。为了解决这个问题,我们引入了滑动窗口算法。
假设一个时间窗口就是一分钟。我们将时间窗口进行划分,将滑动窗口划成了6格,所以每格代表的是10秒钟。每过10秒钟,我们的时间窗口就会往右滑动一格。
每一个格子都有自己独立的计数器counter,比如当一个请求 在0:35秒的时候到达,那么0:30~0:39对应的counter就会加1。
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
2、令牌桶算法
令牌桶算法是比较常见的限流算法之一,大概描述如下:
所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
根据限流大小,设置按照一定的速率往桶里添加令牌;
桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
3、漏桶算法
漏桶算法其实很简单,可以粗略的认为就是注水漏水过程,往桶中以一定速率流出水,以任意速率流入水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
降级也就是服务降级,当我们的服务器压力剧增为了保证核心功能的可用性 ,而选择性的降低一些功能的可用性,或者直接关闭该功能。这就是典型的丢车保帅了。
限流、熔断和服务降级是系统容错的重要设计模式,从一定意义上讲限流和熔断也是一种服务降级的手段。
熔断和服务降级主要是针对非核心业务功能,而核心业务如果流程超过预估的峰值,就需要进行限流。
对于限流,选择合理的限流算法很重要,令牌桶算法优势很明显,也是使用最多的限流算法。
在系统设计的时候,这些模式需要配合业务量的预估、性能测试的数据进行相应阈值的配置,而这些阈值最好保存在配置中心,方便实时修改。