Java问答知识总结篇-基础知识
Java问答知识总结篇-JVM
Java问答知识总结篇-多线程&并发编程
Java问答知识总结篇-网络基础
Java问答知识总结篇-Spring
Java问答知识总结篇-Spring Boot
Java问答知识总结篇-Mybatis
Java问答知识总结篇-MySQL
Java问答知识总结篇-Redis
Java问答知识总结篇-MQ
Java问答知识总结篇-Nginx
Java问答知识总结篇-分布式
Java问答知识总结篇-Spring Cloud
Java问答知识总结篇-Dubbo
Java问答知识总结篇-Zookeeper
Java问答知识总结篇-ElasticSearch
Java问答知识总结篇-Netty
Java问答知识总结篇-场景分析题
Spring Cloud系列文章:Spring-Cloud
什么是服务熔断?什么是服务降级?
熔断机制是应对雪崩效应的一种微服务链路保护机制。当某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在Spring Cloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内调用20次,如果失败,就会启动熔断机制。
服务降级,一般是从整体负荷考虑。就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。这样做,虽然水平下降,但好歹可用,比直接挂掉强。
Eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别
Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用,P:分区容错性)。
- 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用。也就是说,服务注册功能对高可用性要求比较高,但zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新选leader。问题在于,选取leader时间过长,30 ~ 120s,且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够恢复,但是漫长的选取时间导致的注册长期不可用是不能容忍的。
- Eureka保证了可用性,Eureka各个节点是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点仍然可以提供注册和查询服务。而Eureka的客户端向某个Eureka注册或发现时发生连接失败,则会自动切换到其他节点,只要有一台Eureka还在,就能保证注册服务可用,只是查到的信息可能不是最新的。除此之外,Eureka还有自我保护机制,如果在15分钟内超过85%的节点没有正常的心跳,那么Eureka就认为客户端与注册中心发生了网络故障,此时会出现以下几种情况:
- Eureka不在从注册列表中移除因为长时间没有收到心跳而应该过期的服务。
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点仍然可用)
- 当网络稳定时,当前实例新的注册信息会被同步到其他节点。
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个微服务瘫痪。
负载平衡的意义什么
在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源 的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。
什么是Hystrix?它如何实现容错?
Hystrix是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。
通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。
比如一个服务调用链路是A调用B,B调用C,C调用D。如果D出现网络短时的中断,这个收就会导致整个链路堵塞在C位置,增加了C的压力,有可能导致C的崩溃,同理可能影响到B、A,最终引起服务雪崩的问题。
使用Hystrix在这种情况下的Fallback方法功能。在C服务中定义fallback(回退)处理逻辑,及时的给出反馈信息。很好的预防服务雪崩的问题。
说说 RPC 的实现原理
首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编解码的模块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列化。剩下的就是客户端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服务接口的一个代理实现,这个代理实现负责收集数据、编码并传输给服务器然后等待结果返回。
Eureka自我保护机制是什么
当Eureka Server 节点在短时间内丢失了过多实例的连接时(比如网络故障或频繁启动关闭客户端)节点会进入自我保护模式,保护注册信息,不再删除注册数据,故障恢复时,自动退出自我保护模式。
什么是Ribbon
ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。feign默认集成了ribbon。
什么是 Feigin ?它的优点是什么
- feign采用的是基于接口的注解
- feign整合了ribbon,具有负载均衡的能力
- 整合了Hystrix,具有熔断的能力
Ribbon和Feign的区别
- Ribbon都是调用其他服务的,但方式不同
- 启动类注解不同,Ribbon是@RibbonClient,feign则是@EnableFeignClients
- 服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明
- 调用方式不同,Ribbon需要自己构建http请求,模拟http请求
什么是Spring Cloud Gateway
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的入口,在微服务系统中有着非常重要的作用,网关常见的功能有路由转发、权限校验、限流控制等作用。
使用了一个RouteLocatorBuilder
的bean去创建路由,除了创建路由RouteLocatorBuilder
可以让你添加各种predicates
和filters
,predicates
断言的意思,顾名思义就是根据具体的请求的规则,由具体的route
去处理,filters
是各种过滤器,用来对请求做各种判断和修改。
什么是Spring Cloud Alibaba
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
Spring Cloud Alibaba有哪些功能
服务限流降级(Sentinel):默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
服务注册与发现(Nacos):适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
分布式配置管理(Nacos):支持分布式系统中的外部化配置,配置更改时自动刷新。
消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
分布式事务(Seata):使用
@GlobalTransactional
注解, 高效并且对业务零侵入地解决分布式事务问题。阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
Spring Cloud Alibaba的常用组件有哪些
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
Alibaba Cloud OSS:阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
什么是Nacos,介绍一下Nacos
服务发现和服务健康监测
使服务更容易注册,并通过DNS或HTTP接口发现其他服务,还提供服务的实时健康检查,以防 止向不健康的主机或服务实例发送请求。
支持基于DNS和基于RPC的服务发现。服务提供者使用原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。
Nacos提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
动态配置服务
- 以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
- 消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
- 配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
- 提供了一个简洁易用的UI (控制台样例 Demo) 帮助管理所有的服务和应用的配置。
Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,能更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
动态 DNS 服务
动态 DNS 服务支持权重路由,更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能更容易地实现以 DNS 协议为基础的服务发现,消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的 DNS APIs TODO ,管理服务的关联域名和可用的 IP:PORT 列表。
服务及其元数据管理
从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
Nacos有什么作用
服务发现与服务健康检查Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务,Nacos还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。
动态配置管理动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新部署应用程序,这使配置的更改更加高效和灵活。
动态DNS服务Nacos提供基于DNS 协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端点,让三方应用方便的查阅及发现。
服务和元数据管理Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略。
服务发现
在微服务架构中一个业务流程需要多个微服务通过网络接口调用完成业务处理,服务消费方从服务注册中心获取服务提供方的地址,从而进行远程调用,这个过程叫做服务发现。
服务发现流程
服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端。
在每个服务启动时会向服务发现中心上报自己的网络位置。在服务发现中心内部会形成一个服务注册表,服务注册表是服务发现的核心部分,是包含所有服务实例网络地址的数据库。
服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。
当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。
总结,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感知。 各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。
执行流程
- 服务提供方将自己注册到服务注册中心
- 服务消费方从注册中心获取服务地址
- 进行远程调用
服务发现数据模型
Namespace 隔离设计
命名空间(Namespace)用于进行租户粒度的隔离,Namespace 的常用场景之一是不同环境的隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
从一个租户(用户)的角度来看,如果有多套不同的环境,那么这个时候可以根据指定的环境来创建不同的 namespce,以此来实现多环境的隔离。如有开发,测试和生产三个不同的环境,那么使用一套 nacos 集群可以分别建以下三个不同的 namespace。
从多个租户(用户)的角度来看,每个租户(用户)可能会有自己的 namespace,每个租户(用户)的配置数据以及注册的服务数据都会归属到自己的 namespace 下,以此来实现多租户间的数据隔离。
命名空间管理
命名空间(Namespace)是用于隔离多个环境的(如开发、测试、生产),而每个应用在不同环境的同一个配置(如数据库数据源)的值是不一样的。因此,我们应针对企业项目实际研发流程、环境进行规划。 如某软件公司拥有开发、测试、生产三套环境,那么我们应该针对这三个环境分别建立三个namespace。
建立好所有namespace后,在配置管理与服务管理模块下所有页面,都会包含用于切换namespace(环境)的tab按钮;
注意:
namesace 为 public 是 nacos 的一个保留空间,如需要创建自己的 namespace,不要和 public 重名,以一个实际业务场景有具体语义的名字来命名,以免带来字面上不容易区分哪一个 namespace。
在编写程序获取配置集时,指定的namespace参数一定要填写命名空间ID,而不是名称。
数据模型
Nacos在经过阿里内部多年生产经验后提炼出的数据模型,是一种 服务-集群-实例 的三层模型,这样基本可以满 足服务在所有场景下的数据存储和管理。
服务:对外提供的软件功能,通过网络访问预定义的接口。
实例:提供一个或多个服务的具有可访问网络地址(IP:Port)的进程,启动一个服务,就产生了一个服务实例。
元信息:Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标 签 (label),
从作用范围来分:服务级别的元信息、集群的元信息、实例的元信息。
集群:服务实例的集合,服务实例组成一个默认集群, 集群可以被进一步按需求划分,划分的单位可以是虚拟集群,相同集群下的实例才能相互感知。
应用通过Namespace、Service、Cluster(DEFAULT)的配置,描述了该服务向哪个环境(如开发环境)的哪个集群注册实例。
Nacos支持AP和CP的切换,该如何选择呢
一般来说,如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,并能够保持心跳上报,那么就可以选择AP模式。当前主流的服务如 Spring cloud 和 Dubbo 服务,都适用于AP模式,AP模式为了服务的可能性而减弱了一致性,因此AP模式下只支持注册临时实例。
如果需要在服务级别编辑或者存储配置信息,那么 CP 是必须,K8S服务和DNS服务则适用于CP模式。
CP模式下则支持注册持久化实例,此时则是以 Raft 协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误。
模式切换代码:curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
Nacos健康检测机制
- 为什么服务中心需要健康监测机制?
如果服务中心没有健康监测机制,那么注册的服务挂掉以后(比如两个实例,挂掉了一个),订阅服务如果没有得到通知,仍然是50%的向两台机器发送请求,就会有50%的请求失败,出现严重的系统错误,所以服务中心需要检测到注册服务是否健康,如果有服务挂掉以后,需要主动将当前的可用服务信息通知到订阅方。
- nacos如何进行健康检查?
nacos有两种健康监测方式,一种是对临时服务,一种是持久化服务,服务注册时通过ephemeral
参数进行区分,ephemeral=true
代表是临时服务,ephemeral=false
代表是持久化服务,所有服务默认为临时服务
临时服务检查机制:由服务主动向服务中心上报心跳,5s上报一次,15s没有上报,服务为不健康服务,30s没有上报,注册中心摘除服务。
持久化服务检查机制:由注册中心主动探测,20s探测一次,探测失败,服务为不健康服务,但是服务不会被摘除。
- 高并发大流量下健康实例摘除引发服务雪崩
A->B->C ,A服务调用B服务,B服务调用C服务,正常情况下,假如C服务有10个实例,每个实例能够达到的QPS为500,那么整个C服务可以达到5000的qps,但是c服务如果宕机了5个服务,注册中心通知B服务目前只有5个实例可用,那么每个c实例每秒需要接收1000次请求,这个显然大大超出了实例的性能范围,机器会被打死,接着B服务也会无法提供服务,继而A服务无法提供服务。
- nacos保护阈值如何避免服务雪崩
每个服务可以设置保护阈值,0到1之间,当健康实例个数比例(健康实例个数/总实例)小于保护阈值时,为了避免服务雪崩,也会向不健康实例发送请求,这样牺牲掉一部请求,避免整个系统无法提供服务。
Nacos配置中心
Nacos除了实现了服务的注册发现之外,还将配置中心功能整合在了一起。通过Nacos的配置管理功能,我们可以将整个架构体系内的所有配置都集中在Nacos中存储。这样做的好处,在以往的教程中介绍Spring Cloud Config时也有提到,主要有以下几点:
- 分离的多环境配置,可以更灵活的管理权限,安全性更高。
- 应用程序的打包更为纯粹,以实现一次打包,多处运行的特点。
- 配置动态刷新(可以在读取配置的类上面添加注解
@RefreshScope
来实现动态刷新) - 配置回滚(可以再历史版本里面查看到配置文件修改的记录,可以选择对应的版本回滚)。
- Nacos的配置管理,基础层面都通过DataId和Group来定位配置内容,除此之外还增加了很多其他的管理功能。
分布式配置中心实现原理
- 本地应用读取云端分布式配置中心文件(第一次读取时建立长连接)。
- 本地应用读取到配置文件后,本地jvm和硬盘都会缓存一份。
- 本地应用与分布式配置中心服务器端一直保持长连接。
- 当我们的配置文件发生变化(根据版本号|MID判断),将变化结果通知本地应用及时刷新配置文件。
对于Nacos配置管理,通过Namespace、group、Data ID能够定位到一个配置集。
配置集(Data ID):
在系统中,一个配置文件通常就是一个配置集,一个配置集可以包含了系统的各种配置信息,如:一个配置集可能包含了数据源、线程池、日志级别等配置项。每个配置集都可以定义一个有意义的名称,就是配置集的ID即Data ID。
配置项:
配置集中包含的一个个配置内容就是配置项。它代表一个具体的可配置的参数与其值域,通常以 key=value
的形式存在。如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR
) 就是一个配置项。
配置分组(Group):
配置分组是对配置集进行分组,通过一个有意义的字符串(如 Buy 或 Trade )来表示,不同的配置分组下可以有相同的配置集(Data ID)。当在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用DEFAULT_GROUP
。配置分组的常见场景:可用于区分不同的项目或应用,例如:学生管理系统的配置集可以定义一个group为:STUDENT_GROUP。
命名空间(Namespace):
命名空间可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过 namespace隔离。不同的命名空间下,可以存在相同名称的配置分组(Group) 或 配置集。
常见实践用法:
Nacos抽象定义了Namespace、Group、Data ID的概念,具体这几个概念代表什么,取决于我们把它们看成什么,如:
Namespace:代表不同环境,如开发、测试、生产环境;
Group:代表某项目;
DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件。
Spring Cloud LoadBalancer (下文简称 SCL)
SpringCloud原有的客户端负载均衡方案Ribbon已经被废弃,取而代之的是SpringCloud LoadBalancer。
Spring Cloud 中内部微服务调用默认是 http 请求,主要通过下面三种 API:
RestTemplate:同步 http API
WebClient:异步响应式 http API
三方客户端封装,例如 openfeign
如果项目中加入了 spring-cloud-loadbalancer
的依赖并且配置启用了,那么会自动在相关的 Bean 中加入负载均衡器的特性。
对于 RestTemplate
,会自动对所有 @LoadBalanced
注解修饰的 RestTemplate Bean
增加 Interceptor
从而加上了负载均衡器的特性。
对于 WebClient
,会自动创建 ReactorLoadBalancerExchangeFilterFunction
,我们可以通过加入ReactorLoadBalancerExchangeFilterFunction
会加入负载均衡器的特性。
对于三方客户端,一般不需要我们额外配置什么。
Spring Cloud 2020,内置轮询、随机的负载均衡策略,默认轮询策略。可以通过 @LoadBalancerClient
注解的configuration属性指定服务级别的负载均衡策略。
@LoadBalancerClient(value = “demo-provider”, configuration = RandomLoadbalancerConfig.class)
自定义负载均衡策略
通过上文可知,目前 SCL 支持的负载均衡策略相较于 Ribbon 还是较少,需要开发者自行实现,好在 SCL 提供了便捷的 API 方便扩展使用。 这里演示自定义一个基于注册中心元数据的灰度负载均衡策略。
定义灰度负载均衡策略:
@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private String serviceId;
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request));
}
Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {
// 注册中心无可用实例 抛出异常
if (CollUtil.isEmpty(instances)) {
log.warn("No instance available {}", serviceId);
return new EmptyResponse();
}
DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
RequestData clientRequest = (RequestData) requestContext.getClientRequest();
HttpHeaders headers = clientRequest.getHeaders();
String reqVersion = headers.getFirst(CommonConstants.VERSION);
if (StrUtil.isBlank(reqVersion)) {
return super.choose(request).block();
}
// 遍历可以实例元数据,若匹配则返回此实例
for (ServiceInstance instance : instances) {
NacosServiceInstance nacosInstance = (NacosServiceInstance) instance;
Map<String, String> metadata = nacosInstance.getMetadata();
String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION);
if (reqVersion.equalsIgnoreCase(targetVersion)) {
log.debug("gray requst match success :{} {}", reqVersion, nacosInstance);
return new DefaultResponse(nacosInstance);
}
}
// 降级策略,使用轮询策略
return super.choose(request).block();
}
}
针对客户端注入灰度负载均衡策略:
@LoadBalancerClient(value = “demo-provider”, configuration = GrayRoundLoadbalancerConfig.class)
Nacos读取配置文件的有哪几种方案
Data ID
方案:指定spring.profile.active
和配置文件的DataID来使不同环境下读取不同的配置Group
方案:通过Group实现环境区分Namespace
方案:通过建立不同NameSpace来区分
服务发现产品对比
目前市面上用的比较多的服务发现中心有:Nacos
、Eureka
、Consul
和Zookeeper
。
对比项目 | Naos | Eureka | Consul | Zookeeper |
---|---|---|---|---|
一致性协议 | 支持AP和CP模型 | AP模型 | CP模型 | CP模型 |
健康检查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | CP/HTTP/gRPC/Cmd | Keep Alive |
负载均衡策略 | 权重/metadata/Selector | Ribbon | Fabio | - |
雪崩保护 | 有 | 有 | 无 | 无 |
自动注销实例 | 支持 | 支持 | 不支持 | 支持 |
访问协议 | HTTP/DNS | HTTP | HTTP/DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 支持 |
跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 支持 |
k8s集成 | 支持 | 不支持 | 支持 | 不支持 |
什么是Spring Cloud Sentinel
Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。
Sentinel 基本概念有哪些
资源:资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
Sentinel有哪些优点
丰富的适用场景:哨兵在阿里巴巴得到了广泛的应用,几乎覆盖了近10年双11(11.11)购物节的所有核心场景,比如需要限制突发流量的“秒杀”满足系统能力、消息削峰填谷、不依靠业务断路、流量控制等。
实时监控:Sentinel 还提供实时监控能力。可以实时查看单台机器的运行时信息,以及以下 500 个节点的集群运行时信息。
广泛的开源生态:Sentinel 提供与 Spring、Dubbo 和 gRPC 等常用框架和库的开箱即用集成。
多语言支持:Sentinel 为 Java、Go和C++提供了本机支持。
丰富的 SPI 扩展:Sentinel 提供简单易用的 SPI 扩展接口,可以让您快速自定义逻辑,例如自定义规则管理、适配数据源等。
Sentinel有哪几种流控模式
直接(默认):api达到限流条件,直接限流
关联:当关联的资料达到阈值时,就限流自己。当与A关联的资源B达到阈值后,就限流A
链路:链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流;它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
Sentinel有哪几种流控效果呢
直接(默认的流控处理):该方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出
FlowException
预热(Warm Up):阈值除以coldFactor(默认为3),经过预热时长后才达到阈值,案例,阀值为10+预热时长设置5秒。系统初始化的阀值为10 3 约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10
排队等待:匀速器(
RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式。这种方式严格控制了请求通过的间隔时间,也就是让请求以均匀的速度通过,对应的是漏桶算法
Sentinel 有哪些降级规则(熔断策略)
慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
常见四种限流算法
固定窗口计数器
固定窗口,相比其他的限流算法,这应该是最简单的一种。
它简单地对一个固定的时间窗口内的请求数量进行计数,如果超过请求数量的阈值,将被直接丢弃。
这个简单的限流算法优缺点都很明显。优点的话就是简单,缺点举个例子来说。
比如我们下图中固定时间窗口的区域,默认时间范围是 1 秒,限流数量是 100。
如图中括号内所示,如果在窗口内的两段时间内,总的流量之和超过100即表示已经达到限流的标准,如果出现跨窗口,即使达到限流标准,也会被视为未达到。
- 0~1秒的流量分别是50和49,加起来的总和是99,没有超过100阈值,不限流;
- 0.5
1.5的流量分别是49和58,加起来总和是107,超过了100阈值,不限流,因为0.51秒属于窗口1,1~1.5秒属于窗口2,不可交叉计算; - 1~2秒的流量分别是58和50,加起来总和是108,超过100阈值,限流,两个值在同一个固定的窗口下。
滑动窗口计数器
为了优化这个问题,于是有了滑动窗口算法。顾名思义,滑动窗口就是时间窗口在随着时间推移不停地移动。
滑动窗口把一个固定时间窗口再继续拆分成 N 个小窗口,然后对每个小窗口分别进行计数,所有小窗口请求之和不能超过我们设定的限流阈值。
以下图举例子来说:随着时间的推移,窗口的位置都会不断的移动,向后滑动,滑动的时间范围内流量之和,就是对应当前时刻的流量总值。
- 0~1秒的流量分别是50和49,加起来的总和是99,没有超过100阈值,不限流;
- 0.5~1.5的流量分别是49和58,加起来总和是107,超过了100阈值,限流,两个值在同一个固定的窗口下;
- 1~2秒的流量分别是58和50,加起来总和是108,超过100阈值,限流,两个值在同一个固定的窗口下。
漏桶(也有称漏斗 Leaky bucket)
漏桶算法名副其实,就是一个漏的桶,不管请求的数量有多少,最终都会以固定的出口流量大小匀速流出。如果请求的流量超过漏桶大小,那么超出的流量将会被丢弃。
也就是说流量流入的速度是不定的,但是流出的速度是恒定的。
这个和 MQ 削峰填谷的思想比较类似,在面对突然激增的流量的时候,通过漏桶算法可以做到匀速排队,固定速度限流。
漏桶算法的优势是匀速,匀速是优点也是缺点,很多人说漏桶不能处理突增流量,这个说法并不准确。
漏桶本来就应该是为了处理间歇性的突增流量。流量一下起来了,然后系统处理不过来,可以在空闲的时候去处理,防止了突增流量导致系统崩溃,保护了系统的稳定性。
但是换一个思路来想,其实这些突增的流量对于系统来说完全没有压力,你还在慢慢地匀速排队,其实是对系统性能的浪费。
所以,对于这种有场景来说,令牌桶算法比漏桶就更有优势。
令牌桶( Token bucket)
令牌桶算法是指系统以一定地速度往令牌桶里丢令牌。当一个请求过来的时候,会去令牌桶里申请一个令牌,如果能够获取到令牌,那么请求就可以正常进行,反之被丢弃。
现在的令牌桶算法,像 Guava 和 Sentinel 的实现都有冷启动 / 预热的方式。为了避免在流量激增的同时把系统打挂,令牌桶算法会在最开始一段时间内冷启动,随着流量的增加,系统会根据流量大小动态地调整生成令牌的速度,直到最终请求达到系统阈值。
Spring Cloud GateWay如何实现限流?
Spring Cloud GateWay使用令牌桶算法实现限流(Nginx使用漏桶算法实现限流 )
Spring Cloud GateWay默认使用Redis 的RateLimter限流算法来实现,所以需要引入Redis依赖
使用的过程中,主要配置 令牌桶填充的速率,令牌桶容量,指定限流的key
限流的Key,可以根据用户 来做限流,IP 来做限流,接口限流等等。
微服务中网关的作用
- 统一入口:为全部微服务提供唯一入口点,网关起到外部和内部隔离,保障了后台服务的安全性;
- 鉴权校验:识别每个请求的权限,拒绝不符合要求的请求;
- 动态路由:动态的将请求路由到不同的后端集群中;
- 减少客户端与服务端的耦合:服务可以独立发展,通过网关层来做映射。
Spring Cloud Gateway 详解
Spring Cloud Gateway原理的讲解,以及其主要参数router、predicate、uri的讲解。(有它就够啦)
https://www.cnblogs.com/crazymakercircle/p/11704077.html
分布式事务存在的问题
单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。
什么是Spring Cloud Seata
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
分布式事务的处理过程是怎样的
分布式事务处理过程的唯一ID+三组件模型:Transaction ID XID(全局唯一的事务ID)
三组件概念
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
处理过程
- TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID;
- XID 在微服务调用链路的上下文中传播;
- RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖;
- TM 向 TC 发起针对 XID 的全局提交或回滚决议;
- TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
Seata分布式事务框架实现原理
Seata有三个组成部分
事务协调器TC:协调者
事务管理器TM:发起方
资源管理器RM:参与方
- 发起方会向协调者申请一个全局事务id,并保存到ThreadLocal中(为什么要保存到ThreadLocal中?弱引用,线程之间不会发生数据冲突;
- Seata数据源代理发起方和参与方的数据源,将前置镜像和后置镜像写入到undo_log表中,方便后期回滚使用;
- 发起方获取全局事务id,通过改写Feign客户端请求头传入全局事务id;
- 参与方从请求头中获取全局事务id保存到ThreadLocal中,并把该分支注册到SeataServer中;
- 如果没有出现异常,发起方会通知协调者,协调者通知所有分支,通过全局事务id和本地事务id删除undo_log数据,如果出现异常,通过undo_log逆向生成sql语句并执行,然后删除undo_log语句。如果处理业务逻辑代码超时,也会回滚。