SpringCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件,为开发人员提供了快速构建微服务应用提供帮助,包括:
配置管理
服务注册与发现
断路器
智能路由
服务间调用
负载均衡
微代理
控制总线
一次性令牌
全局锁
领导选举
分布式会话
集群状态
分布式消息
��
使用 Spring Cloud 的开发人员可以开箱即用的实现这些模式的服务和应用程序。这些服务可以任何环境下运行,包括分布式环境,也包括开发人员自己的笔记本电脑以及各种托管平台。
首先,他们都是分布式管理框架。
(1)Dubbo
是二进制传输,占用带宽会少一点。SpringCloud是http 传输,带宽会多一点,同时使用http协议一般会使用JSON报文,消耗会更大。
(2)Dubbo 开发难度较大,所依赖的jar包有很多问题大型工程无法解决。
SpringCloud 对第三方的继承可以一键式生成,天然集成。
(3)服务调用方式 dubbo是RPC springcloud Rest
Api;
(4)注册中心
Dubbo 是zookeeper
Springcloud是Eureka,也可以是zookeeper、consul;
(5)服务网关,Dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul/Gateway路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。
最大的区别有两个:
Dubbo关注的领域是SpringCloud的一个子集。Dubbo专注于服务治理,其在服务治理、灰度发布、流量分发方面比SpringCloud更全面。SpringCloud覆盖整个微服务架构领域。
SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。Dubbo使用RPC调用效率高一些,Spring
Cloud使用HTTP调用效率低,使用更简单。
严格来说,这两种方式各有优劣。虽然在一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更为合适。
REST风格的系统交互更方便,RPC调用服务提供方和调用方式之间依赖太强
REST调用系统性能较低,RPC调用效率比REST高。
REST的灵活性可以跨系统跨语言调用,RPC只能在同语言内调用。
REST可以和Swagger等工具整合,自动输出接口API文档
SpringBoot:专注于快速方便的开发单个个体微服务(关注微观);
SpringCloud:关注全局的微服务协调治理框架,将SpringBoot开发的一个个单体微服务组合并管理起来(关注宏观);
SpringBoot可以离开SpringCloud独立使用,但是SpringCloud不可以离开SpringBoot,属于依赖关系。
在Spring Cloud中使用了Hystrix 来实现断路器的功能,断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决,如果问题似乎已经得到纠正,应用程序可以尝试调用操作。
断路器增加了稳定性和灵活性,以一个系统,提供稳定性,而系统从故障中恢复,并尽量减少此故障的对性能的影响。它可以帮助快速地拒绝对一个操作,即很可能失败,而不是等待操作超时(或者不返回)的请求,以保持系统的响应时间。如果断路器提高每次改变状态的时间的事件,该信息可以被用来监测由断路器保护系统的部件的健康状况,或以提醒管理员当断路器跳闸,以在打开状态。
在最新版本的SpringCloud中,Netflix的组件已经被移除了,包括Hystrix、Ribbon等,我们可以用阿里的Sentinel来代替Hystrix。
(1)服务发现——Netflix Eureka
由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个Java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。
(2)客服端负载均衡——老版本Netflix Ribbon、新版本用LoadBalancer
老版本用的是Ribbon,主要提供客户侧的软件负载均衡算法。Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等。Ribbon内置可插拔、可定制的负载均衡组件。
新版本提供的是LoadBalancer,内置于SpringCloud的Common中,功能与Ribbon类似,目前没有Ribbon强大,不过由于Ribbon已经从SpringCloud中移除,可以用LoadBalancer来代替。
(3)断路器——老版本用Netflix Hystrix,新版本用Sentinel
断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作。
由于Histrix已经从SpringCloud中移除,可以用阿里的Sentinel来代替。
(4)服务网关——老版本用Netflix Zuul,新版本用Gateway
类似nginx,反向代理的功能,不过netflix自己增加了一些配合其他组件的特性。
由于Zuul已经从SpringCloud中移除,可以用SpringCloud官方提供的Gateway来代替。
(5)分布式配置——Spring Cloud Config
这个还是静态的,得配合Spring Cloud Bus + Kafka实现动态的配置更新。
可以选用阿里的Nacos来代替。
Zookeeper保证了CP(C:一致性,P:分区容错性)
Eureka保证了AP(A:高可用)
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用。也就是说,服务注册功能对高可用性要求比较高,但zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新选leader。
问题在于,选取leader时间过长,30~120s,且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够恢复,但是漫长的选取时间导致的注册长期不可用是不能容忍的。
Eureka保证了可用性,Eureka各个节点是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点仍然可以提供注册和查询服务。而Eureka的客户端向某个Eureka注册或发现时发生连接失败,则会自动切换到其他节点,只要有一台Eureka还在,就能保证注册服务可用,只是查到的信息可能不是最新的。除此之外,Eureka还有自我保护机制,如果在15分钟内超过85%的节点没有正常的心跳,那么Eureka就认为客户端与注册中心发生了网络故障,此时会出现以下几种情况:
Eureka不在从注册列表中移除因为长时间没有收到心跳而应该过期的服务。
Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点仍然可用)。
当网络稳定时,当前实例新的注册信息会被同步到其他节点。
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个微服务瘫痪。
服务隔离:如果整个系统雪崩是由于一个接口导致的,由于这一个接口响应不及时导致问题,那么我们就有必要对这个接口进行隔离,就是只允许这个接口最多能接受多少的并发,做了这样的限制后,该接口的主机就会空余线程出来接收其他的情况,不会被哪个坏了的接口占用满。
Hystrix 就是一个不错的服务隔离框架。
服务雪崩:雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。从源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估。
当整个微服务系统中,有一个节点出现异常情况,就有可能在高并发的情况下出现雪崩,导致调用它的上游系统出现响应延迟,响应延迟就会导致 tomcat连接本耗尽,导致该服务节点不能正常的接收到正常的情况,这就是服务雪崩行为。
Hystrix两种隔离策略:线程池隔离THREAD 、信号量SEMAPHORE隔离。
熔断发生的三个必要条件:
(1)有一个统计的时间周期,滚动窗口
相应的配置属性metrics.rollingStats.timeInMilliseconds
默认 10000 毫秒
(2)请求次数必须达到一定数量
相应的配置属性
circuitBreaker.requestVolumeThreshold默认 20 次
(3)失败率达到默认失败率
相应的配置属性
circuitBreaker.errorThresholdPercentage 默认 50%
用到的注解:
@EnableEurekaServer
// 注册服务中心
@EnableEurekaClient
// 服务提供端
(1)服务注册与续约:
首先服务注册到EurekaServer上,注册之后服务提供者会维护一个心跳,用来告诉eureka server“我还OK”,也就是续约Renew,
心跳默认三十秒检测一次。
(2)服务剔除:
当服务实例正常下线时,服务实例会告诉EurekaServer“我要下线了”,将服务状态改为 down。 有时服务会出现非正常下线,eureka
server 在启动时会去创建一个定时任务检测服务提供者,剔除服务,检测时间默认90秒。
(3)自我保护:
默认配置下,如果EurekaServer每分钟收到心跳续约的数量低于一个阈值(instance的数量(60/每个instance的心跳间隔秒数)自我保护系数),并且持续15分钟,就会触发自我保护。
在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。
它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。该模式可以通过eureka.server.enable-self-preservation
=false来禁用,同时eureka.instance.lease-renewal-interval-in-seconds可以用来更改心跳间隔
Ribbon是一个客户端的负载均衡器,它提供对大量的HTTP和TCP客户端的访问控制。
客户端负载均衡即是当浏览器向后台发出请求的时候,客户端会向 Eureka Server读取注册到服务器的可用服务信息列表,然后根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求。
重要注解:@Loadbalanced
注解修饰RestTemplate
负载均衡策略:线性轮询、随机、重试机制。
Ribbon内部有一个chooseServer()方法用于选择服务。
SpringCloudGateway是SpringCloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。
使用了一个RouteLocatorBuilder的bean去创建路由,除了创建路由RouteLocatorBuilder可以让你添加各种predicates和filters,predicates断言的意思,顾名思义就是根据具体的请求的规则,由具体的route去处理,filters是各种过滤器,用来对请求做各种判断和修改。
当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应
当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)
断路器有完全打开状态:一段时间内达到一定的次数无法调用,并且多次监测没有恢复的迹象 断路器完全打开 那么下次请求就不会请求到该服务
半开:短时间内有恢复迹象,断路器会将部分请求发给该服务,正常调用时 断路器关闭
关闭:当服务一直处于正常状态能正常调用
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在SpringCloud中,有分布式配置中心组件springcloudconfig
,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。
在spring cloud config 组件中,分两个角色,一是config server,二是config client。
提供动态路由
统一处理调用过程中的安全、权限问题
跨域处理
全局动态路由的hystrix(熔断、降级、限流)处理
简化客户端调用复杂度,统一处理外部请求。
数据裁剪以及聚合,根据不同的接口需求,对数据加工后对外。
多渠道支持,针对不同的客户端提供不同的网关支持。
遗留系统的微服务化改造,可以作为新老系统的中转组件。
Ribbon和Feign都是用于调用其他服务的,不过方式不同。
(1)启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的@EnableFeignClients。
(2)服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
(3)调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。
RoundRobinRule:
轮询策略,Ribbon以轮询的方式选择服务器,这个是默认值。所以示例中所启动的两个服务会被循环访问;
RandomRule:
随机策略,也就是说Ribbon会随机从服务器列表中选择一个进行访问;
BestAvailableRule:
最大可用策略,即先过滤出故障服务器后,选择一个当前并发请求数最小的;
WeightedResponseTimeRule:
带有加权的轮询策略,对各个服务器响应时间进行加权处理,然后在采用轮询的方式来获取相应的服务器;
AvailabilityFilteringRule:
可用过滤策略,先过滤出故障的或并发请求大于阈值的一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个;
ZoneAvoidanceRule:
区域感知策略,先使用主过滤条件(区域负载器,选择最优区域)对所有实例过滤并返回过滤后的实例清单,依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数(默认1)和最小过滤百分比(默认0),最后对满足条件的服务器则使用RoundRobinRule(轮询方式)选择一个服务器实例。
当我们项目中引入SpringCloudSleuth后,每次链路请求都会添加一串追踪信息,格式是[server-name,
main-traceId,sub-spanId,boolean]:
server-name:服务结点名称。
main-traceId:一条链路唯一的ID,为TraceID。
sub-spanId:链路中每一环的ID,为SpanID。
boolean:是否将信息输出到Zipkin等服务收集和展示。
Sleuth的实现是基于HTTP的,为了在数据的收集过程中不能影响到正常业务,Sleuth会在每个请求的Header上添加跟踪需求的重要信息。这样在数据收集时,只需要将Header上的相关信息发送给对应的图像工具即可,图像工具根据上传的数据,按照Span对应的逻辑进行分析、展示。