Spring Cloud及其相关组件介绍
一、概念
微服务架构:把应⽤拆分成为⼀个个微⼩的服务,不同的服务可以使⽤不同的开发语⾔和存储,服务之间往往通过Restful等轻量级通信。微服务架构关键在于微⼩、独⽴、轻量级通信。微服务架构强调的⼀个重点是“业务需要彻底的组件化和服务化”。
优点:①微服务很⼩,便于特定业务功能的聚焦 。②每个微服务都可以被⼀个⼩团队单独实施(开发、测试、部署上。线、运维),团队合作⼀定程度解耦,便于实施敏捷开发。③便于重⽤和模块之间的组装。④独⽴,那么不同的微服务可以使⽤不同的语⾔开发,松耦合。微服务架构下,我们更容易引⼊新技术。⑤微服务架构下,我们可以更好的实现DevOps开发运维⼀体化。
缺点:微服务架构下,分布式复杂难以管理,当服务数量增加,管理将越加复杂,分布式链路跟踪难等。
Spring Cloud 核⼼组件
第一代 第二代
注册中心 Netflix Eureka 阿⾥巴巴 Nacos
客户端负载均衡 Netflix Ribbon 阿⾥巴巴 Dubbo LB、Spring Cloud Loadbalancer
熔断器 Netflix Hystrix 阿⾥巴巴 Sentinel
网关 Spring Cloud Gateway
配置中心 官⽅ Spring Cloud Config 阿⾥巴巴 Nacos、携程 Apollo
服务调用 Netflix Feign 阿⾥巴巴 Dubbo RPC
消息驱动 官⽅ Spring Cloud Stream
链路追踪 Spring Cloud Sleuth/Zipkin
体系结构如下图
二、Spring Cloud核心组件
2.1 Eureka服务注册中⼼
Eureka 包含两个组件:Eureka Server 和 Eureka Client,Eureka Client是⼀个Java客户端,⽤于简化与Eureka Server的交互;Eureka Server提供服务发现的能⼒,各个微服务启动时,会通过Eureka Client向Eureka Server 进⾏注册⾃⼰的信息(例如⽹络信息),Eureka Server会存储该服务的信息。
Eureka客户端详解
注册中心服务端配置注解@EnableEurekaServer, 客户端微服务配置@EnableDiscoveryClient开启服务发现。
服务注册:1)当我们导⼊了eureka-client依赖坐标,配置Eureka服务注册中⼼地址 2)服务在启动时会向注册中⼼发起注册请求,携带服务元数据信息 3)Eureka注册中⼼会把服务的信息保存在Map中。
服务续约:服务每隔30秒会向注册中⼼续约(⼼跳)⼀次(也称为报活),如果没有续约,租约在90秒后到期,然后服务会被失效。每隔30秒的续约操作我们称之为⼼跳检测。
获取服务列表:每隔30秒服务会从注册中⼼中拉取⼀份服务列表,这个时间可以通过配置修改。1)服务消费者启动时,从 EurekaServer服务列表获取只读备份,缓存到本地 2)每隔30秒,会重新获取并更新数据 3)每隔30秒的时间可以通过配置eureka.client.registry-fetch-interval-seconds修改。
Eureka服务端详解
服务下线:1)当服务正常关闭操作时,会发送服务下线的REST请求给EurekaServer。2)服务中⼼接受到请求后,将该服务置为下线状态。
失效剔除:Eureka Server会定时(间隔值是eureka.server.eviction-interval-timer-in-ms,默认60s)进⾏检查,如果发现实例在在⼀定时间(此值由客户端设置的eureka.instance.lease-expiration-duration-in-seconds定义,默认值为90s)内没有收到⼼跳,则会注销此实例。
⾃我保护:服务提供者和注册中心网络有问题,不代表服务提供者不可用。如果在15分钟内超过85%的客户端节点都没有正常的⼼跳,那么Eureka就认为客户端与注册中⼼出现了⽹络故障,Eureka Server⾃动进⼊⾃我保护机制。自我保护时:不会剔除任何服务实例,保证大多数服务仍然可用。Eureka Server可以接受新服务的注册和查询请求, 但不会同步到其它节点。网络稳定时会同步到其它节点。
2.2 Ribbon负载均衡
Ribbon是Netflix发布的负载均衡器。Eureka⼀般配合Ribbon进⾏使⽤,Ribbon利⽤从Eureka中读取到服务信息,在调⽤服务提供者提供的服务时,会根据⼀定的算法进⾏负载。
代码中使⽤如下,在RestTemplate上添加对应注解即可。
@Bean // Ribbon负载均衡 @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); }
负载均衡策略:1.轮询 2.随机 3.重试 (默认是轮询,500ms内判断是否存活) 4. 最小连接数策略 5. 区域权衡策略(默认策略, 扩展了轮询。过滤超时和连接数过多的服务器,还会过滤不符合要求zone区域里面的所有节点)
2.3 Hystrix熔断器
雪崩效应:简历微服务响应时间过⻓,⼤量请求阻塞,⼤量线程不会释放,会导致服务器资源耗尽,最终导致上游服务甚⾄整个系统瘫痪。
解决方案:
服务熔断:切断对下游服务的调⽤。
服务降级:就是当某个服务熔断之后,服务器将不再被调⽤,此刻客户端可以⾃⼰准备⼀个本地的fallback回调,返回⼀个缺省值。
服务限流: 限制总并发数(⽐如数据库连接池、线程池),限制瞬时并发数(如nginx限制瞬时并发连接数),限制时间窗⼝内的平均速率(如Guava的RateLimiter、nginx的limit_req模块,限制每秒的平均速率)
限制远程接⼝调⽤速率、限制MQ的消费速率等。
2.4 Feign远程调⽤组件
Feign是Netflix开发的⼀个轻量级RESTful的HTTP服务客户端(⽤它来发起请求,远程调⽤的),是以Java接⼝注解的⽅式调⽤Http请求,⽽不⽤像Java中通过封装HTTP请求报⽂的⽅式直接调⽤,Feign被⼴泛应⽤在Spring Cloud 的解决⽅案中。类似于Dubbo,服务消费者拿到服务提供者的接⼝,然后像调⽤本地接⼝⽅法⼀样去调⽤,实际发出的是远程的请求。
本质:封装了Http调⽤流程,更符合⾯向接⼝化的编程习惯,类似于Dubbo的服务调⽤。Feign = RestTemplate+Ribbon+Hystrix。
Feign配置应用
服务消费者⼯程中引⼊Feign依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
服务消费者⼯程启动类使⽤注解@EnableFeignClients添加Feign⽀持
@SpringBootApplication @EnableDiscoveryClient // 开启服务发现 @EnableFeignClients // 开启Feign
创建Feign接⼝
// name:调⽤的服务名称,和服务提供者yml⽂件中spring.application.name保持⼀致 @FeignClient(name="lagou-service-resume") public interface ResumeFeignClient { //调⽤的请求路径 @RequestMapping(value = "/resume/openstate/{userId}",method=RequestMethod.GET) public Integer findResumeOpenState(@PathVariable(value ="userId") Long userId); }
Feign对负载均衡的⽀持
#针对的被调⽤⽅微服务名称,不加就是全局⽣效 lagou-service-resume: ribbon: #请求连接超时时间 #ConnectTimeout: 2000 #请求处理超时时间 #ReadTimeout: 5000 #对所有操作都进⾏重试 OkToRetryOnAllOperations: true MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第⼀次调⽤ MaxAutoRetriesNextServer: 0 #切换实例的重试次数 NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RoundRobinRule #负载策略调整
Feign对熔断器的⽀持
# 开启Feign的熔断功能 feign: hystrix: enabled: true
hystrix超时设置
hystrix: command: default: execution: isolation: thread: ###Hystrix的超时时⻓设置 timeoutInMilliseconds: 15000
⾃定义FallBack处理类(需要实现FeignClient接⼝)
/** * 降级回退逻辑需要定义⼀个类,实现FeignClient接⼝,实现接⼝中的⽅法*/ @Component // 别忘了这个注解,还应该被扫描到 public class ResumeFallback implements ResumeServiceFeignClient { @Override public Integer findDefaultResumeState(Long userId) { return -6; } }
Feign⽀持对请求和响应进⾏GZIP压缩,以减少通信过程中的性能损耗。通过下⾯的参数 即可开启请求与响应的压缩功能。
feign: compression: request: enabled: true # 开启请求压缩 mime-types: text/html,application/xml,application/json # 设置压缩的数据类型,此处也是默认值 min-request-size: 2048 # 设置触发压缩的⼤⼩下限,此处也是默认值 response: enabled: true # 开启响应压缩
Feign的⽇志级别配置
1) 开启Feign⽇志功能及级别
@Configuration public class FeignConfig { @Bean Logger.Level feignLevel() { return Logger.Level.FULL; } }
2) 配置log⽇志级别为debug
logging:
level:
# Feign⽇志只会对⽇志级别为debug的做出响应
com.lagou.edu.controller.service.ResumeServiceFeignClient:debug
2.5 GateWay⽹关组件
⽹关在架构中的位置
⼀个请求—>⽹关根据⼀定的条件匹配—匹配成功之后可以将请求转发到指定的服务地址;⽽在这个过程中,我们可以进⾏⼀些⽐较具体的控制(限流、⽇志、⿊⽩名单)。
2.6 Spring Cloud Config 分布式配置中⼼
使用场景:1)集中配置管理,⼀个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的(⼀次修改、到处⽣效)2)不同环境不同配置,⽐如数据源配置在不同环境(开发dev,测试test,⽣产prod)
中是不同的 3)运⾏期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池⼤⼩等配置修改后可⾃动更新 4)如配置内容发⽣变化,微服务可以⾃动更新配置。
2.7 Spring Cloud Stream消息驱动组件
Spring Cloud Stream进⾏了很好的上层抽象,可以让我们与具体消息中间件解耦合,屏蔽掉了底层具体MQ消息中间件的细节差异,就像Hibernate屏蔽掉了具体数据库(Mysql/Oracle⼀样)。如此⼀来,我们学习、开发、维护MQ都会变得轻松。⽬前Spring Cloud Stream⽀持RabbitMQ和Kafka。本质:屏蔽掉了底层不同MQ消息中间件之间的差异,统⼀了MQ的编程模型,降低了学习、开发、维护MQ的成本。
三、常见问题及解决方案
3.1 场景1:上线⼀个新的服务实例,但是服务消费者⽆感知,过了⼀段时间才知道某⼀个服务实例下线了,服务消费者⽆感知,仍然向这个服务实例在发起请求。
原因:Eureka 服务发现慢的原因主要有两个,⼀部分是因为服务缓存导致的,另⼀部分是因为客户端缓存导致的。
解决办法:EurekaClient负责跟EurekaServer进⾏交互,在EurekaClient中的com.netflix.discovery.DiscoveryClient.initScheduledTasks() ⽅法中,初始化了⼀个 CacheRefreshThread 定时任务专⻔⽤来拉取 Eureka Server 的实例信息到本地。所以我们需要缩短这个定时拉取服务信息的时间间隔(eureka.client.registryFetchIntervalSeconds)来快速发现新的服务。Ribbon会从EurekaClient中获取服务信息,ServerListUpdater是Ribbon中负责服务实例更新的组件,默认的实现是PollingServerListUpdater,通过线程定时去更新实例信息。定时刷新的时间间隔默认是30秒,当服务停⽌或者上线后,这边最快也需要30秒才能将实例信息更新成最新的。我们可以将这个时间调短⼀点,⽐如 3 秒。
将这些服务端缓存和客户端缓存的时间全部缩短后,跟默认的配置时间相⽐,快了很多。我们通过调整参数的⽅式来尽量加快服务发现的速度,但是还是不能完全解决报错的问题,间隔时间设置为3秒,也还是会有间隔。所以我们⼀般都会开启重试功能,当路由的服务出现问题时,可以重试到另⼀个服务来保证这次请求的成功。
3.2 场景2:Spring Cloud 各组件超时
Ribbon如果采⽤的是服务发现⽅式,就可以通过服务名去进⾏转发,需要配置Ribbon的超时。Ribbon的超时可以配置全局的ribbon.ReadTimeout和ribbon.ConnectTimeout。也可以在前⾯指定服务名,为每个服务单独配置,⽐如user-service.ribbon.ReadTimeout。其次是Hystrix的超时配置,Hystrix的超时时间要⼤于Ribbon的超时时间,因为Hystrix将请求包装了起来,特别需要注意的是,如果Ribbon开启了重试机制,⽐如重试3次,Ribbon的超时为1秒,那么Hystrix的超时时间应该⼤于3秒,否则就会出现Ribbon还在重试中,⽽Hystrix已经超时的现象。
Feign本身也有超时时间的设置,如果此时设置了Ribbon的时间就以Ribbon的时间为准,如果没设置Ribbon的时间但配置了Feign的时间,就以Feign的时间为准。Feign的时间同样也配置了连接超时时间(feign.client.config.服务名称.connectTimeout)和读取超时时间(feign.client.config.服务名称.readTimeout)。建议,我们配置Ribbon超时时间和Hystrix超时时间即可。
四、Spring Cloud⾼级进阶
4.1 微服务监控之分布式链路追踪技术 Sleuth +Zipkin
核⼼思想:记录日志。
简介:Spring Cloud Sleuth (追踪服务框架)可以追踪服务之间的调⽤,Sleuth可以记录⼀个服务请求经过哪些服务、服务处理时⻓等,根据这些,我们能够理清各微服务间的调⽤关系及进⾏问题追踪分析。耗时分析:通过Sleuth了解采样请求的耗时,分析服务性能问题(哪些服务调⽤⽐较耗时)链路优化:发现频繁调⽤的服务,针对性优化等Sleuth就是通过记录⽇志的⽅式来记录踪迹数据的。
相关概念:
Trace:服务追踪的追踪单元是从客户发起请求(request)抵达被追踪系统的边界开始,到被追踪系统向客户返回响应(response)为⽌的过程。
Trace ID:为了实现请求跟踪,当请求发送到分布式系统的⼊⼝端点时,只需要服务跟踪框架为该请求创建⼀个唯⼀的跟踪标识Trace ID,同时在分布式系统内部流转的时候,框架失踪保持该唯⼀标识,直到返回给请求⽅。
Span ID:为了统计各处理单元的时间延迟,当请求到达各个服务组件时,也是通过一个唯⼀标识Span ID来标记它的开始,具体过程以及结束。
4.2 微服务统⼀认证⽅案 Spring Cloud OAuth2+JWT
微服务架构下统⼀认证思路
基于Session的认证⽅式
在分布式的环境下,基于session的认证会出现⼀个问题,每个应⽤服务都需要在session中存储⽤户身份信息,通过负载均衡将本地的请求分配到另⼀个应⽤服务需要将session信息带过去,否则会重新认证。我们可以使⽤Session共享、Session黏贴等⽅案。Session⽅案也有缺点,⽐如基于cookie,移动端不能有效使⽤等。
基于token的认证⽅式
基于token的认证⽅式,服务端不⽤存储认证数据,易维护扩展性强, 客户端可以把token 存在任意地⽅,并且可以实现web和app统⼀认证机制。其缺点也很明显,token由于⾃包含信息,因此⼀般数据量较⼤,⽽且每次请求都需要传递,因此⽐较占带宽。另外,token的签名验签操作也会给cpu带来额外的处理负担。
OAuth2介绍
OAuth(开放授权)是⼀个开放协议/标准,允许⽤户授权第三⽅应⽤访问他们存储在另外的服务提供者上的信息,⽽不需要将⽤户名和密码提供给第三⽅应⽤或分享他们数据的所有内容。允许⽤户授权第三⽅应⽤访问他们存储在另外的服务提供者上的信息,⽽不需要将⽤户名和密码提供给第三⽅应⽤或分享他们数据的所有内容。
五、第⼆代 Spring Cloud 核⼼组件(SCA)
简介:市场上主要使⽤的还是SCN。Alibaba 更进⼀步,搞出了Spring Cloud Alibaba(SCA),SCA 是由⼀些阿⾥巴巴的开源组件和云产品组成的,2018年,Spring Cloud Alibaba 正式⼊住了 Spring Cloud 官⽅孵化器。Nacos(服务注册中⼼、配置中⼼,Sentinel哨兵(服务的熔断、限流等), Dubbo RPC/LB, Seata分布式事务解决⽅案。
5.1 SCA Nacos 服务注册和配置中⼼
Nacos就是注册中⼼+配置中⼼的组合(Nacos=Eureka+Config+Bus)。
5.2 SCA Sentinel 分布式系统的流量防卫兵
Sentinel是⼀个⾯向云原⽣微服务的流量控制、熔断降级组件。替代Hystrix,针对问题:服务雪崩、服务降级、服务熔断、服务限流。
Hystrix和Sentinel对比
Hystrix:服务消费者(⾃动投递微服务)—>调⽤服务提供者(简历微服务)在调⽤⽅引⼊Hystrix—> 单独搞了⼀个Dashboard项⽬—>Turbine 1)⾃⼰搭建监控平台 dashboard 2)没有提供UI界⾯进⾏服务熔断、服务降级等配置(⽽是写代码,⼊侵了我们源程序环境)。
Sentinel:1)独⽴可部署Dashboard/控制台组件 2)减少代码开发,通过UI界⾯配置即可完成细粒度控制(⾃动投递微服务)。
5.3 SCA 小结
1)因为内容重叠,SCA 中的分布式事务解决⽅案 Seata 会在紧接着的Mysql课程中讲解。
2)SCA实际上发展了三条线。第⼀条线:开源出来⼀些组件。第⼆条线:阿⾥内部维护了⼀个分⽀,⾃⼰业务线使⽤。第三条线:阿⾥云平台部署⼀套,付费使⽤。从战略上来说,SCA更是为了贴合阿⾥云。⽬前来看,开源出来的这些组件,推⼴及普及率不⾼,社区活跃度不⾼,稳定性和体验度上仍需进⼀步提升,根据实际使⽤来看Sentinel的稳定性和体验度要好于Nacos。