第二代Spring Cloud 核心组件
一. SCA Nacos 服务注册和配置中心
1.1 nacos介绍
Nacos(DynamicNamingandConfigurationService)是阿⾥巴巴开源的⼀个针对微服务架构中服务发现、配置管理和服务管理平台。
Nacos就是注册中⼼+配置中⼼的组合(Nacos=Eureka+Config+Bus)https://nacos.io
功能特性:
- 服务发现与健康检查
- 动态配置管理
- 动态DNS服务
- 服务和元数据管理(管理平台的⻆度,nacos也有⼀个ui⻚⾯,可以看到注册的服务及其实例信息(元数据信息)等),动态的服务权重调整、动态服务优雅下线,都可以去做
1.2 nacos单例服务部署
- 下载最新稳定版压缩包 nacos-server-1.4.3.tar.gz 并解压
- 执行单机启动命令
sh startup.sh -m standalone
- 访问 http://127.0.0.1:8848/nacos/#/login 默认用户名密码 nacos/nacos
1.3 nacos服务注册中心
1.3.1 服务提供者注册到nacos
改造简历微服务
-
父Pom引入 spring-cloud-alibaba-dependencies
-
创建子工程 demo-service-resume-8083-nacos
-
服务提供者工程引入nacos客户端依赖 spring-cloud-starter-alibaba-nacos-discovery
-
application.yml 添加 nacos服务发现配置
-
启动服务,观察nacos控制台
保护阈值:可以设置为0-1之间的浮点数,它其实是⼀个⽐例值(当前服务健康实例数/当前服务总实例数)
保护阈值的意义在于:
当服务A健康实例数/总实例数<保护阈值的时候,说明健康实例真的不多了,这个时候保护阈值会被触发(状态true)
nacos将会把该服务所有的实例信息(健康的+不健康的)全部提供给消费者,消费者可能访问到不健康的实例,请求失败,但这样也⽐造成雪崩要好,牺牲了⼀些请求,保证了整个系统的⼀个可⽤。
1.3.2 服务消费者从nacos获取服务提供者
改造自动投递微服务
- 新创建示例工程 demo-service-autodeliver-8092-nacos
- 其他配置和提供者一样
- 测试 http://localhost:8092/autodeliver/checkState/{userId}
1.3.3 负载均衡
Nacos客户端引⼊的时候,会关联引⼊Ribbon的依赖包,我们使⽤OpenFiegn的时候也会引⼊Ribbon的依赖,Ribbon包括Hystrix都按原来⽅式进⾏配置即可
此处,我们将简历微服务,再创建一个示例工程 demo-service-resume-8083-nacos 并启动,注册到Nacos上,便于测试负载均衡,我们通过后台也可以看出。
1.3.4 nacos数据模型(领域模型)
Namespace命名空间、Group分组、集群这些都是为了进⾏归类管理,把服务和配置⽂件进⾏归类,归类之后就可以实现⼀定的效果,⽐如隔离. ⽐如,对于服务来说,不同命名空间中的服务不能够互相访问调⽤
-
Namespace
命名空间,对不同的环境进⾏隔离,⽐如隔离开发环境、测试环境和⽣产环境
-
group
分组,将若⼲个服务或者若⼲个配置集归为⼀组,通常习惯⼀个系统归为⼀个组
-
service
某⼀个服务,⽐如简历微服务
-
dataId
配置集或者可以认为是⼀个配置⽂件
Namespace+Group+Service 如同Maven中的GAV坐标,GAV坐标是为了锁定Jar,这⾥是为了锁定服务
Namespace+Group+DataId 如同Maven中的GAV坐标,GAV坐标是为了锁定Jar,这⾥是为了锁定配置⽂件
Nacos抽象出了Namespace、Group、Service、DataId等概念,具体代表什么取决于怎么⽤(⾮常灵活)
nacos服务的分级模型:
1.3.5 nacos server 数据持久化
Nacos默认使⽤嵌⼊式数据库进⾏数据存储,它⽀持改为外部Mysql存储
- 新建数据库nacos_config,数据库初始化脚本⽂件${nacoshome}/conf/nacos-mysql.sql
- 修改${nacoshome}/conf/application.properties,增加Mysql数据源配置
1.3.6 nacos server集群
-
安装3个或3个以上的Nacos
复制解压后的nacos⽂件夹,分别命名为nacos-01、nacos-02、nacos-03 修改配置⽂件
-
修改配置文件
同⼀台机器模拟,将上述三个⽂件夹中application.properties中的server.port分别改为8848、8849、8850
同时给当前实例节点绑定ip,因为服务器可能绑定多个ip
nacos.inetutils.ip-address=127.0.0.1
复制⼀份conf/cluster.conf.example⽂件,命名为cluster.conf 在配置⽂件中设置集群中每⼀个节点的信息
127.0.0.1:8848
127.0.0.1:8849
127.0.0.1:8850
-
分别启动每一个实例
sh startup.sh -m cluster
1.4 nacos 配置中心
之前:SpringCloudConfig+Bus, 有Nacos之后,分布式配置就简单很多
如上配置文件配置完成后,即可在微服务中开启nacos配置管理
-
添加依赖 spring-cloud-starter-alibaba-nacos-config
-
微服务中如何锁定NacosServer中的配置⽂件(dataId)
通过Namespace+Group+dataId来锁定配置⽂件,Namespace不指定就默认public,Group不指定就默认DEFAULT_GROUP
dataId 完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}
-
prefix
默认为
spring.application.name
的值, 也可以通过配置项spring.cloud.nacos.config.prefix
来配置 -
spring.profile.active
即为当前环境的对应的profile. 当此值为空时,对应的连接符"-“也将不存在, dataId的拼接格式变成
${prefix}-${file-extension}
-
file-extension
为配置内容的数据格式 , 通过
spring.cloud.nacos.config.file-extension
来配置
为便于测试,我们在nacos中创建了3个配置文件
-
-
使用Spring cloud 注解 @RefreshScope实现配置自动更新
我们写一个测试controller用于测试配置更新
@RestController @RequestMapping("/config") @RefreshScope public class ConfigController { // 和取本地配置信息一样 @Value("${test}") private String test; @GetMapping("/viewconfig") public String viewconfig() { return test; } }
可以通过以下方式引入扩展的dataId
ext-config[0]: data-id: test1.yml group: DEFAULT_GROUP refresh: true #开启扩展dataId的动态刷新 ext-config[1]: data-id: test2.yml group: DEFAULT_GROUP refresh: true #开启扩展dataId的动态刷新
优先级:根据规则⽣成的dataId>扩展的dataId(对于扩展的dataId,[n]n越⼤优先级越⾼)
注意: 用配置中心时,启动前把application.yml 改成系统级别 bootstrap.yml
二. SCA Sentinel分布式系统的流量防卫兵
2.1 sentinel介绍
Sentinel是⼀个⾯向云原⽣微服务的流量控制、熔断降级组件。
替代Hystrix,针对问题:服务雪崩、服务降级、服务熔断、服务限流
Hystrix:
服务消费者(⾃动投递微服务)—>调⽤服务提供者(简历微服务), 在调⽤⽅引⼊Hystrix—>单独搞了⼀个Dashboard项⽬—>Turbine
1)⾃⼰搭建监控平台dashboard
2)没有提供UI界⾯进⾏服务熔断、服务降级等配置(⽽是写代码,⼊侵了我们源程序环境)
Sentinel:
1)独⽴可部署Dashboard/控制台组件
2)减少代码开发,通过UI界⾯配置即可完成细粒度控制(⾃动投递微服务)
Sentinel分两个部分:
-
核心库
(Java客户端)不依赖任何框架/库,能够运⾏于所有Java运⾏时环境,同时对Dubbo/SpringCloud等框架也有较好的⽀持。
-
控制台
Dashboard)基于SpringBoot开发,打包后可以直接运⾏,不需要额外的Tomcat等应⽤容器。
特征:
- 丰富的应⽤场景:Sentinel承接了阿⾥巴巴近10年的双⼗⼀⼤促流量的核⼼场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填⾕、集群流量控制、实时熔断下游不可⽤应⽤等。
- 完备的实时监控:Sentinel同时提供实时的监控功能。您可以在控制台中看到接⼊应⽤的单台机器秒级数据,甚⾄500台以下规模的集群的汇总运⾏情况。
- ⼴泛的开源⽣态:Sentinel提供开箱即⽤的与其它开源框架/库的整合模块,例如与SpringCloud、Dubbo的整合。您只需要引⼊相应的依赖并进⾏简单的配置即可快速地接⼊Sentinel。
- 完善的SPI扩展点:Sentinel提供简单易⽤、完善的SPI扩展接⼝。您可以通过实现扩展接⼝来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
2.2 sentinel部署
- 下载 sentinel sentinel-dashboard-v**.jar
- 启动 java -jar sentinel-dashboard-v**.jar &
- 用户名/密码: sentinel/sentinel
- Localhost:8080进入管理界面
2.3 服务改造
-
创建示例工程 demo-service-autodeliver-8093-sentinel
-
引入依赖 spring-cloud-starter-alibaba-sentinel
-
application.yml 修改
-
启动,使用sentinel监控
此时我们发现控制台没有任何变化,因为懒加载,我们只需要发起⼀次请求触发即可
2.4 sentinel关键概念
-
资源
它可以是Java应⽤程序中的任何内容,例如,由应⽤程序提供的服务,或由应⽤程序调⽤的其它应⽤提供的服务,甚⾄可以是⼀段代码。我们请求的API接⼝就是资源
-
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
2.5 sentinel 流量规则模块
系统并发能⼒有限,⽐如系统A的QPS⽀持1个,如果太多请求过来,那么A就应该进⾏流量控制了,⽐如其他请求直接拒绝
资源名:默认请求路径
针对来源:Sentinel可以针对调⽤者进⾏限流,填写微服务名称,默认default(不区分来源)
阈值类型/单机阈值
- QPS:(每秒钟请求数量)当调⽤该资源的QPS达到阈值时进⾏限流
- 线程数:当调⽤该资源的线程数达到阈值的时候进⾏限流(线程处理请求的时候,如果说业务逻辑执⾏时间很⻓,流量洪峰来临时,会耗费很多线程资源,这些线程资源会堆积,最终可能造成服务不可⽤,进⼀步上游服务不可⽤,最终可能服务雪崩)
是否集群:是否集群限流
流控模式:
- 直接:资源调⽤达到限流条件时,直接限流
- 关联:关联的资源调⽤达到阈值时候限流⾃⼰
- 链路:只记录指定链路上的流量
流控效果:
- 快速失败:直接失败,抛出异常
- WarmUp:根据冷加载因⼦(默认3)的值,从阈值/冷加载因⼦,经过预热时⻓,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求匀速通过,阈值类型必须设置为QPS,否则⽆效
流控模式之关联限流: 关联的资源调⽤达到阈值时候限流⾃⼰,⽐如⽤户注册接⼝,需要调⽤身份证校验接⼝(往往身份证校验接⼝),如果身份证校验接⼝请求达到阈值,使⽤关联,可以对⽤户注册接⼝进⾏限流。
Tips: 模拟密集式请求/user/validateID验证接⼝,我们会发现/user/register接⼝也被限流了
Blocked by Sentinel (flow limiting)
流控模式之链路限流: 链路指的是请求链路(调⽤链)
链路模式下会控制该资源所在的调⽤链路⼊⼝的流量。需要在规则中配置⼊⼝资源,即该调⽤链路⼊⼝的上下⽂名称。
流控效果之Warmup:
当系统⻓期处于空闲的情况下,当流量突然增加时,直接把系统拉升到⾼⽔位可能瞬间把系统压垮,⽐如电商⽹站的秒杀模块。通过WarmUp模式(预热模式),让通过的流量缓慢增加,经过设置的预热时间以后,到达系统处理请求速率的设定值。WarmUp模式默认会从设置的QPS阈值的1/3开始慢慢往上增加⾄QPS设置值。
流控效果之排队等待:
排队等待模式下会严格控制请求通过的间隔时间,即请求会匀速通过,允许部分请求排队等待,通常⽤于消息队列削峰填⾕等场景。需设置具体的超时时间,当计算的等待时间超过超时时间时请求就会被拒绝。很多流量过来了,并不是直接拒绝请求,⽽是请求进⾏排队,⼀个⼀个匀速通过(处理),请求能等就等着被处理,不能等(等待时间>超时时间)就会被拒绝
例如,QPS配置为5,则代表请求每200ms才能通过⼀个,多出的请求将排队等待通过。超时时间代表最⼤排队时间,超出最⼤排队时间的请求将会直接被拒绝。排队等待模式下,QPS设置值不要超过1000(请求间隔1ms)。
2.6 sentinel 降级规则模块
流控是对外部来的⼤流量进⾏控制,熔断降级的视⻆是对内部问题进⾏处理.
sentinel降级会在调⽤链路中某个资源出现不稳定状态时(例如调⽤超时或异常⽐例升⾼),对这个资源的调⽤进⾏限制,让请求快速失败,避免影响到其它的资源⽽导致级联错误。当资源被降级后,在接下来的降级时间窗⼝之内,对该资源的调⽤都⾃动熔断.
这⾥的降级其实是Hystrix中的熔断
策略
Sentinel不会像Hystrix那样放过⼀个请求尝试⾃我修复,就是明明确确按照时间窗⼝来,熔断触发后,时间窗⼝内拒绝请求,时间窗⼝后就恢复
-
RT(平均响应时间)
当1s内持续进⼊>=5个请求,平均响应时间超过阈值(以ms为单位),那么在接下的时间窗⼝(以s为单位)之内,对这个⽅法的调⽤都会⾃动地熔断(抛出DegradeException)。注意Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项
-Dcsp.sentinel.statistic.max.rt=xxx
来配置。 -
异常⽐例
当资源的每秒请求量>=5,并且每秒异常总数占通过量的⽐值超过阈值之后,资源进⼊降级状态,即在接下的时间窗⼝(以s为单位)之内,对这个⽅法的调⽤都会⾃动地返回。异常⽐率的阈值范围是[0.0,1.0],代表0%-100%。
-
异常数 当资源近1分钟的异常数⽬超过阈值之后会进⾏熔断。注意由于统计时间窗⼝是分钟级别的, 若timeWindow小于60s, 则结束熔断状态后仍可能再进⼊熔断状态
2.7 其他模块
这里不再细说
2.8 自定义兜底逻辑
@SentinelResource注解类似于Hystrix中的@HystrixCommand注解
@SentinelResource注解中有两个属性需要我们进⾏区分,blockHandler属性⽤来指定不满⾜Sentinel规则的降级兜底⽅法,fallback属性⽤于指定Java运⾏时异常兜底⽅法
-
在api接口资源处配置
@SentinelResource(value = "findResumeOpenState", blockHandlerClass = SentinelHandlersClass.class, blockHandler = "handleException", fallbackClass = SentinelHandlersClass.class, fallback = "handleError")
-
自定义兜底逻辑类 SentinelHandlersClass
2.9 基于nacos实现sentinel规则持久化
⽬前,SentinelDashboard中添加的规则数据存储在内存,微服务停掉规则数据就消失,在⽣产环境下不合适。我们可以将Sentinel规则数据持久化到Nacos配置中⼼,让微服务从Nacos获取规则数据。
-
添加依赖 sentinel-datasource-nacos
-
配置文件中添加nacos数据源
-
Nacos server中添加对应规则的配置集
流控规则配置集: demo-service-autodeliver-nacos-flow-rules
[ { "resource":"findResumeOpenState", "limitApp":"default", "grade":1, "count":1, "strategy":0, "controlBehavior":0, "clusterMode":false } ] # 所有属性来⾃源码FlowRule类 resource:资源名称 limitApp:来源应⽤ grade:阈值类型 0 线程数 1 QPS count:单机阈值 strategy:流控模式,0 直接 1 关联 2 链路 controlBehavior:流控效果,0 快速失败 1 Warm Up 2 排队等待 clusterMode:true/false 是否集群
降级规则配置集 demo-service-autodeliver-nacos-degrade-rules
[ { "resource":"findResumeOpenState", "grade":2, "count":1, "timeWindow":5 } ] # 所有属性来⾃源码DegradeRule类 resource:资源名称 grade:降级策略 0 RT 1 异常⽐例 2 异常数 count:阈值 timeWindow:时间窗
注意
1)⼀个资源可以同时有多个限流规则和降级规则,所以配置集中是⼀个json数组
2)Sentinel控制台中修改规则,仅是内存中⽣效,不会修改Nacos中的配置值,重启后恢复原来的值; Nacos控制台中修改规则,不仅内存中⽣效,Nacos中持久化规则也⽣效,重启后规则依然保持
三. nacos+sentinel+dubbo
改造“⾃动投递微服务”和“简历微服务”,删除OpenFeign 和 Ribbon,使⽤Dubbo RPC 和 Dubbo LB
⾸先,需要删除或者注释掉⽗⼯程中的热部署依赖
3.1 服务提供者改造
见示例工程,为演示多提供者,我们复制两个: demo-service-resume-8085-nacos-sentinel-dubbo, demo-service-resume-8086-nacos-sentinel-dubbo
Tips:
@Service为dubbo的注解
添加 spring.main: allow-bean-definition-overriding: true 配置
3.2 服务消费者改造
见示例工程: demo-service-autodeliver-8094-nacos-sentinel-dubbo
tips:
@Reference 使用dubbo注解
四. SCA小结
SCA实际上发展了三条线
- 第⼀条线:开源出来⼀些组件
- 第⼆条线:阿⾥内部维护了⼀个分⽀,⾃⼰业务线使⽤
- 第三条线:阿⾥云平台部署⼀套,付费使⽤
从战略上来说,SCA更是为了贴合阿⾥云。
⽬前来看,开源出来的这些组件,推⼴及普及率不⾼,社区活跃度不⾼,稳定性和体验度上仍需进⼀步提升,根据实际使⽤来看Sentinel的稳定性和体验度要好于Nacos。