目录
八、SpringCloud篇
Why SpringCloud
GateWay / Zuul
Eureka / Zookeeper
Feign / Ribbon
Ribbon
Hystrix / Sentinel
Sentinel
Config / Nacos
Bus / Stream
Sleuth / Zipkin
安全认证
灰度发布
多版本隔离
各组件调优
Spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。
SpringCloud(微服务解决方案) |
Dubbo(分布式服务治理框架) |
Rest API (轻量、灵活、swagger) |
RPC远程调用(高效、耦合) |
Eureka、Nacos |
Zookeeper |
使用方便 |
性能好 |
即将推出SpringCloud2.0 |
断档5年后17年重启 |
SpringBoot是Spring推出用于解决传统框架配置文件冗余,装配组件繁杂的基于Maven的解决方案,旨在快速搭建单个微服务,SpringCloud是依赖于SpringBoot的,而SpringBoot并不是依赖与SpringCloud,甚至还可以和Dubbo进行优秀的整合开发
MartinFlower 提出的微服务之间是通过RestFulApi进行通信,具体实现
Spring Boot
Spring Boot 通过简单的步骤就可以创建一个 Spring 应用。
Spring Boot 为 Spring 整合第三方框架提供了开箱即用功能。
Spring Boot 的核心思想是约定大于配置。
Spring Boot 解决的问题
Spring Boot 优点
自动装配:Spring Boot 会根据某些规则对所有配置的 Bean 进行初始化。可以减少了很多重复性的工作。
比如使用 MongoDB 时,只需加入 MongoDB 的 Starter 包,然后配置 的连接信息,就可以直接使用 MongoTemplate 自动装配来操作数据库了。简化了 Maven Jar 包的依赖,降低了烦琐配置的出错几率。
内嵌容器:Spring Boot 应用程序可以不用部署到外部容器中,比如 Tomcat。
应用程序可以直接通过 Maven 命令编译成可执行的 jar 包,通过 java-jar 命令启动即可,非常方便。
应用监控:Spring Boot 中自带监控功能 Actuator,可以实现对程序内部运行情况进行监控,
比如 Bean 加载情况、环境变量、日志信息、线程信息等。当然也可以自定义跟业务相关的监控,通过Actuator 的端点信息进行暴露。
spring-boot-starter-web //用于快速构建基于 Spring MVC 的 Web 项目。spring-boot-starter-data-redis //用于快速整合并操作 Redis。spring-boot-starter-data-mongodb //用于对 MongoDB 的集成。spring-boot-starter-data-jpa //用于操作 MySQL。
自定义一个Starter
Spring Boot Admin(将 actuator 提供的数据进行可视化)
GateWay⽬标是取代Netflflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux等技术开发,提供统⼀的路由⽅式(反向代理)并且基于 Filter(定义过滤器对请求过滤,完成⼀些功能) 链的⽅式提供了⽹关基本的功能,例如:鉴权、流量控制、熔断、路径重写、⽇志监控。
组成:
请求前pre类型过滤器:做参数校验、权限校验、流量监控、⽇志输出、协议转换等,
请求前post类型的过滤器:做响应内容、响应头的修改、⽇志的输出、流量监控等。
GateWayFilter 应⽤到单个路由路由上 、GlobalFilter 应⽤到所有的路由上
服务注册中⼼本质上是为了解耦服务提供者和服务消费者,为了⽀持弹性扩缩容特性,⼀个微服务的提供者的数量和分布往往是动态变化的。
区别 |
Zookeeper |
Eureka |
Nacos |
CAP |
CP |
AP |
CP/AP切换 |
可用性 |
选举期间不可用 |
自我保护机制,数据不是最新的 |
|
组成 |
Leader和Follower |
节点平等 |
|
优势 |
分布式协调 |
注册与发现 |
注册中心和配置中心 |
底层 |
进程 |
服务 |
Jar包 |
Eureka通过⼼跳检测、健康检查和客户端缓存等机制,提⾼系统的灵活性、可伸缩性和可⽤性。
Eureka缓存
新服务上线后,服务消费者不能立即访问到刚上线的新服务,需要过⼀段时间后才能访问?或是将服务下线后,服务还是会被调⽤到,⼀段时候后才彻底停⽌服务,访问前期会导致频繁报错!
服务注册到注册中⼼后,服务实例信息是存储在Registry表中的,也就是内存中。但Eureka为了提⾼响应速度,在内部做了优化,加⼊了两层的缓存结构,将Client需要的实例信息,直接缓存起来,获取的时候直接从缓存中拿数据然后响应给 Client。
Eureka之所以设计⼆级缓存机制,也是为了提⾼ Eureka Server 的响应速度,缺点是缓存会导致 Client获取不到最新的服务实例信息,然后导致⽆法快速发现新的服务和已下线的服务。
解决方案
自我保护机制开启条件
健康检查
采用 JDK 的动态代理方式生成代理对象,当我们调用这个接口,实际上是要去调用远程的 HTTP API
比如请求类型是 GET 还是 POST,请求的 URI 是什么
通过该组件我们可以将请求信息采用指定的编码方式进行编解码后传输
负责 Feign 中记录日志的,可以指定 Logger 的级别以及自定义日志的输出
负责 HTTP 请求执行的组件,Feign 中默认的 Client 是通过 JDK 的 HttpURLConnection 来发起请求的,在每次发送请求的时候,都会创建新的 HttpURLConnection 链接,Feign 的性能会很差,可以通过扩展该接口,使用 Apache HttpClient 等基于连接池的高性能 HTTP 客户端。
负责重试的组件,Feign 内置了重试器,当 HTTP 请求出现 IO 异常时,Feign 会限定一个最大重试次数来进行重试操作。
可以为 Feign 添加多个拦截器,在请求执行前设置一些扩展的参数信息。
Feign最佳使用技巧
比如添加指定的请求头信息,这个可以用在服务间传递某些信息的时候。
FULL 会输出全部完整的请求信息。
异常解码器中可以获取异常信息,而不是简单的一个code,然后转换成对应的异常对象返回。
HystrixFeign.builder 中可以看到继承了 Feign 的 Builder,增加了 Hystrix的SetterFactory, build 方法里,对 invocationHandlerFactory 进行了重写, create 的时候返回HystrixInvocationHandler, 在 invoke 的时候会将请求包装成 HystrixCommand 去执行,这里就自然的集成了 Hystrix
使用方式
负载均衡算法
自定义负载均衡算法
自定义负载均衡使用场景(核心)
灰度发布是能够平滑过渡的一种发布方式,在发布过程中,先发布一部分应用,让指定的用户使用刚发布的应用,等到测试没有问题后,再将其他的全部应用发布。如果新发布的有问题,只需要将这部分恢复即可,不用恢复所有的应用。
多版本隔离跟灰度发布类似,为了兼容或者过度,某些应用会有多个版本,这个时候如何保证 1.0 版本的客户端不会调用到 1.1 版本的服务,就是我们需要考虑的问题。
当线上某个实例发生故障后,为了不影响用户,我们一般都会先留存证据,比如:线程信息、JVM 信息等,然后将这个实例重启或直接停止。然后线下根据一些信息分析故障原因,如果我能做到故障隔离,就可以直接将出问题的实例隔离,不让正常的用户请求访问到这个出问题的实例,只让指定的用户访问,这样就可以单独用特定的用户来对这个出问题的实例进行测试、故障分析等。
服务雪崩场景
自己即是服务消费者,同时也是服务提供者,同步调用等待结果导致资源耗尽
解决方案
服务方:扩容、限流,排查代码问题,增加硬件监控
消费方:使用Hystrix资源隔离,熔断降级,快速失败
Hystrix断路保护器的作用
Hystrix使用上遇到的坑
Hystrix 的配置项非常多,如果不对接配置中心,所有的配置只能在代码里修改,在集群部署的难以应对紧急情况,我们项目只设置一个 CommandKey,其他的都在配置中心进行指定,紧急情况如需隔离部分请求时,只需在配置中心进行修改以后,强制更新即可。
当请求失败或者超时,会执行回退逻辑,如果有大量的回退,则证明某些服务出问题了,这个时候我们可以在回退的逻辑中进行埋点操作,上报数据给监控系统,也可以输出回退的日志,统一由日志收集的程序去进行处理,这些方式都可以将问题暴露出去,然后通过实时数据分析进行告警操作
当我们用了线程池隔离模式的时候,被隔离的方法会包装成一个 Command 丢入到独立的线程池中进行执行,这个时候就是从 A 线程切换到了 B 线程,ThreadLocal 的数据就会丢失
网关是所有请求的入口,路由的服务数量会很多,几十个到上百个都有可能,如果用线程池隔离,那么需要创建上百个独立的线程池,开销太大,用信号量隔离开销就小很多,还能起到限流的作用。
[^常见问题]: Hystrix的超时时间要⼤于Ribbon的超时时间,因为Hystrix将请求包装了起来,特别需要注意的是,如果Ribbon开启了重试机制,⽐如重试3 次,Ribbon 的超时为 1 秒,那么Hystrix 的超时时间应该⼤于 3 秒,否则就会出现 Ribbon 还在重试中,⽽ Hystrix 已经超时的现象。
Sentinel是⼀个⾯向云原⽣微服务的流量控制、熔断降级组件。
替代Hystrix,针对问题:服务雪崩、服务降级、服务熔断、服务限流
Hystrix区别:
丰富的应⽤场景:Sentinel 承接了阿⾥巴巴近 10 年的双⼗⼀⼤促流量的核⼼场景,例如秒杀、消息削峰填⾕、集群流量控制、实时熔断下游不可⽤应⽤等。
完备的实时监控:可以看到500 台以下规模的集群的汇总也可以看到单机的秒级数据。
⼴泛的开源⽣态:与 SpringCloud、Dubbo的整合。您只需要引⼊相应的依赖并进⾏简单的配置即可快速地接⼊ Sentinel。
区别:
# |
Sentinel |
Hystrix |
隔离策略 |
信号量隔离 |
线程池隔离/信号量隔离 |
熔断降级策略 |
基于响应时间或失败比率 |
基于失败比率 |
实时指标实现 |
滑动窗口 |
滑动窗口(基于 RxJava) |
扩展性 |
多个扩展点 |
插件的形式 |
限流 |
基于 QPS,支持基于调用关系的限流 |
不支持 |
流量整形 |
支持慢启动、匀速器模式 |
不支持 |
系统负载保护 |
支持 |
不支持 |
控制台 |
开箱即用,可配置规则、查看秒级监控、机器发现等 |
不完善 |
常见框架的适配 |
Servlet、Spring Cloud、Dubbo、gRPC |
Servlet、Spring Cloud Netflix |
Nacos是阿⾥巴巴开源的⼀个针对微服务架构中服务发现、配置管理和服务管理平台。
Nacos就是注册中⼼+配置中⼼的组合(Nacos=Eureka+Confifig+Bus)
Nacos功能特性
保护阈值:
当服务A健康实例数/总实例数 < 保护阈值 的时候,说明健康实例真的不多了,这个时候保护阈值会被触发(状态true),nacos将会把该服务所有的实例信息(健康的+不健康的)全部提供给消费者,消费者可能访问到不健康的实例,请求失败,但这样也⽐造成雪崩要好,牺牲了⼀些请求,保证了整个系统的⼀个可⽤。
Nacos 数据模型(领域模型)
可以通过 Spring Cloud 原⽣注解 @RefreshScope 实现配置⾃动更新
Spring Cloud Stream 消息驱动组件帮助我们更快速,更⽅便的去构建消息驱动微服务的
本质:屏蔽掉了底层不同MQ消息中间件之间的差异,统⼀了MQ的编程模型,降低了学习、开发、维护MQ的成本,⽬前⽀持Rabbit、Kafka两种消息
全链路追踪
Trace ID:当请求发送到分布式系统的⼊⼝端点时,Sleuth为该请求创建⼀个唯⼀的跟踪标识Trace ID,在分布式系统内部流转的时候,框架始终保持该唯⼀标识,直到返回给请求⽅
Span ID:为了统计各处理单元的时间延迟,当请求到达各个服务组件时,也是通过⼀个唯⼀标识SpanID来标记它的开始,具体过程以及结束。
Spring Cloud Sleuth (追踪服务框架)可以追踪服务之间的调⽤,Sleuth可以记录⼀个服务请求经过哪些服务、服务处理时⻓等,根据这些,我们能够理清各微服务间的调⽤关系及进⾏问题追踪分析。
耗时分析:通过 Sleuth 了解采样请求的耗时,分析服务性能问题(哪些服务调⽤⽐较耗时)
链路优化:发现频繁调⽤的服务,针对性优化等
聚合展示:数据信息发送给 Zipkin 进⾏聚合,利⽤ Zipkin 存储并展示数据。
认证中最常用的一种方式,也是最简单的。存在多节点session丢失的情况,可通过nginx粘性Cookie和Redis集中式Session存储解决
服务端针对请求头中base64加密的Authorization 和用户名和密码进行校验。
Session 只是一个 key,会话信息存储在后端。而 Token 中会存储用户的信息,然后通过加密算法进行加密,只有服务端才能解密,服务端拿到 Token 后进行解密获取用户信息。
JWT(JSON Web Token)用户提供用户名和密码给认证服务器,服务器验证用户提交信息的合法性;如果验证成功,会产生并返回一个 Token,用户可以使用这个 Token 访问服务器上受保护的资源。
Token最佳实践
虽然不能修改 Token 的信息,但是能在验证层面做一层过滤来进行处理。
为了防止数据被别人爬取,最常见的就是监控使用频率,程序写出来的爬虫程序访问频率是有迹可循的
比如提现的功能,要求在提现时再次进行验证码的验证,防止不是本人操作。
银行 APP 对环境有很高的要求,使用时如果断网,APP 会自动退出,重新登录,因为网络环境跟之前使用的不一样了,还有一些浏览器的信息之类的判断,这些都是可以用来保证后端 API 的安全。
如果 Token 的加密密钥泄露了,也就意味着别人可以伪造你的 Token,可以将密钥存储在配置中心,以支持动态修改刷新,需要注意的是建议在流量低峰的时候去做更换的操作,否则 Token 全部失效,所有在线的请求都会重新申请 Token,并发量会比较大。
痛点:
通过灰度发布,先让一部分用户体验新的服务,或者只让测试人员进行测试,等功能正常后再全部发布,这样能降低发布失败带来的影响范围。
灰度后如果发现这个节点有问题,那么只需回滚这个节点即可,当然不回滚也没关系,通过灰度策略隔离,也不会影响正常用户
可以通过Ribbon的负载均衡策略进行灰度发布,可以使用更可靠的Discovery
Discovery
基于Discovery 服务注册发现、Ribbon 负载均衡、Feign 和 RestTemplate 调用等组件的企业级微服务开源解决方案,包括灰度发布、灰度路由、服务隔离等功能
grayVersions = {"discovery-article-service":["1.01"]}
本地复用测试服务-Eureka Zone亮点
region 地理上的分区,比如北京、上海等
zone 可以简单理解为 region 内的具体机房
在调用的过程中会优先选择相同的 zone 发起调用,当找不到相同名称的 zone 时会选择其他的 zone 进行调用,我们可以利用这个特性来解决本地需要启动多个服务的问题。
[^]: 当你访问修改的服务 A 时,这个服务依赖了 B、C 两个服务,B 和 C 本地没有启动,B 和 C 找不到相同的 zone 就会选择其他的 zone 进行调用,也就是会调用到测试环境部署的 B 和 C 服务,这样一来就解决了本地部署多个服务的问题。
当你对网关进行压测时,会发现并发量一直上不去,错误率也很高。因为你用的是默认配置,这个时候我们就需要去调整配置以达到最优的效果。
首先我们可以对容器进行调优,最常见的就是内置的 Tomcat 容器了,
server.tomcat.accept-count //请求队列排队数server.tomcat.max-threads //最大线程数server.tomcat.max-connections //最大连接数
Hystrix 的信号量(semaphore)隔离模式,并发量上不去很大的原因都在这里,信号量默认值是 100,也就是最大并发只有 100,超过 100 就得等待。
//信号量zuul.semaphore.max-semaphores //信号量:最大并发数//线程池hystrix.threadpool.default.coreSize //最大线程数hystrix.threadpool.default.maximumSize //队列的大hystrix.threadpool.default.maxQueueSize //等参数
配置Gateway并发信息,
gateway.host.max-per-route-connections //每个路由的连接数 gateway.host.max-total-connections //总连接数
调整Ribbon 的并发配置,
ribbon.MaxConnectionsPerHost //单服务并发数ribbon.MaxTotalConnections //总并发数
修改Feign默认的HttpURLConnection 替换成 httpclient 来提高性能
feign.httpclient.max-connections-per-route//每个路由的连接数feign.httpclient.max-connections //总连接数
Gateway+配置中心实现动态路由
Feign+配置中心实现动态日志