作者 | 赵奕豪(宿何)Sentinel 开源我的项目负责人
起源 |阿里巴巴云原生公众号
前言
微服务的稳定性始终是开发者十分关注的话题。随着业务从单体架构向分布式架构演进以及部署形式的变动,服务之间的依赖关系变得越来越简单,业务零碎也面临着微小的高可用挑战。
在生产环境中大家可能遇到过各种不稳固的状况,比方:
- 大促时霎时洪峰流量导致系统超出最大负载,load 飙高,零碎解体导致用户无奈下单。
- “黑马”热点商品击穿缓存,DB 被打垮,挤占失常流量。
- 调用端被不稳固第三方服务拖垮,线程池被占满,调用沉积,导致整个调用链路卡死。
这些不稳固的场景可能会导致严重后果,但很多时候咱们又容易漠视这些与流量 / 依赖相干的高可用防护。大家可能想问:如何预防这些不稳固因素带来的影响?如何针对流量进行高可用的防护?如何保障服务“稳如磐石”?这时候咱们就要请出阿里双十一起款的高可用防护中间件 —— Sentinel。在往年刚刚过来的天猫 双 11 大促中,Sentinel 完满地保障了阿里成千上万服务 双 11 峰值流量的稳定性,同时 Sentinel Go 版本也在近期正式发表 GA。上面咱们来一起理解下 Sentinel Go 的外围场景以及社区在云原生方面的摸索。
Sentinel 介绍
Sentinel 是阿里巴巴开源的,面向分布式服务架构的流量管制组件,次要以流量为切入点,从限流、流量整形、熔断降级、零碎自适应爱护等多个维度来帮忙开发者保障微服务的稳定性。Sentinel 承接了阿里巴巴近 10 年的 双 11 大促流量的外围场景,例如秒杀、冷启动、音讯削峰填谷、集群流量管制、实时熔断上游不可用服务等,是保障微服务高可用的利器,原生反对 Java/Go/C++ 等多种语言,并且提供 Istio/Envoy 全局流控反对来为 Service Mesh 提供高可用防护的能力。
今年年初,Sentinel 社区发表了 Sentinel Go 版本的公布,为 Go 语言的微服务和根底组件提供高可用防护和容错能力的原生反对,标记着 Sentinel 朝着多元化与云原生迈出了新的一步。在这半年的工夫内,社区推出了近 10 个版本,逐渐对齐了外围高可用防护和容错能力,同时也在一直裁减开源生态,与 dubbo-go、蚂蚁 MOSN 等开源社区进行共建。
就在近期,Sentinel Go 1.0 GA 版本正式公布,标记着 Go 版本正式进入生产可用阶段。Sentinel Go 1.0 版本对齐了 Java 版本外围的高可用防护和容错能力,包含限流、流量整形、并发管制、熔断降级、零碎自适应爱护、热点防护等个性。同时 Go 版本已笼罩支流开源生态,提供了 Gin、gRPC、go-micro、dubbo-go 等罕用微服务框架的适配,并提供了 etcd、Nacos、Consul 等动静数据源扩大反对。Sentinel Go 也在朝着云原生的方向一直演进,1.0 版本中也进行了一些云原生方面的摸索,包含 Kubernetes CRD data-source, Kubernetes HPA 等。对于 Sentinel Go 版本而言,咱们冀望的流控场景并不局限于微服务利用自身。云原生根底组件中 Go 语言生态占比拟高,而这些云原生组件很多时候又不足细粒度、自适应的爱护与容错机制,这时候就能够联合组件的一些扩大机制,利用 Sentinel Go 来爱护本身的稳定性。
Sentinel 底层通过高性能的滑动窗口进行秒级调用指标统计,联合 token bucket, leaky bucket 和自适应流控算法来透出外围的高可用防护能力。
那么咱们如何利用 Sentinel Go 来保障咱们微服务的稳定性?上面咱们来看几个典型的利用场景。
高可用防护的外围场景
1. 流量管制与调配
流量是十分随机性的、不可预测的。前一秒可能还惊涛骇浪,后一秒可能就呈现流量洪峰了(例如 双 11 零点的场景)。然而咱们零碎的容量总是无限的,如果忽然而来的流量超过了零碎的承受能力,就可能会导致申请解决不过去,沉积的申请解决迟缓,CPU/Load 飙高,最初导致系统解体。因而,咱们须要针对这种突发的流量来进行限度,在尽可能解决申请的同时来保障服务不被打垮,这就是流量管制。流量管制的场景是十分通用的,像脉冲流量类的场景都是实用的。
通常在 Web 入口或服务提供方(Service Provider)的场景下,咱们须要爱护服务提供方本身不被流量洪峰打垮。这时候通常依据服务提供方的服务能力进行流量管制,或针对特定的服务调用方进行限度。咱们能够联合后期压测评估外围接口的承受能力,配置 QPS 模式的流控规定,当每秒的申请量超过设定的阈值时,会主动回绝多余的申请。
上面是最简略的一个 Sentinel 限流规定的配置示例:
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "some-service", // 埋点资源名
Count: 10, // 阈值为 10,默认为秒级维度统计,即该申请单机每秒不超过 10 次
ControlBehavior: flow.Reject, // 管制成果为间接回绝,不管制申请之间的工夫距离,不排队
},
})
2. Warm-Up 预热流控
当零碎长期处于低水位的状况下,流量忽然减少时,间接把零碎拉升到高水位可能霎时把零碎压垮。比方刚启动的服务,数据库连接池可能还未初始化,缓存也处于空的状态,这时候激增的流量非常容易导致服务解体。如果采纳传统的限流模式,不加以平滑 / 削峰限度,其实也是有被打挂的危险的(比方一瞬间并发很高)。针对这种场景,咱们就能够利用 Sentinel 的 Warm-Up 流控模式,管制通过的流量迟缓减少,在肯定工夫内逐步减少到阈值下限,而不是在一瞬间全副放行,同时联合申请距离管制 + 排队的管制成果 来避免大量申请都在同一时刻被解决。这样能够给冷零碎一个预热的工夫,防止冷零碎被压垮。
3. 并发管制与熔断降级
一个服务经常会调用别的模块,可能是另外的一个近程服务、数据库,或者第三方 API 等。例如,领取的时候,可能须要近程调用银联提供的 API;查问某个商品的价格,可能须要进行数据库查问。然而,这个被依赖服务的稳定性是不能保障的。如果依赖的服务呈现了不稳固的状况,申请的响应工夫变长,那么调用服务的办法的响应工夫也会变长,线程会产生沉积,最终可能耗尽业务本身的线程池,服务自身也变得不可用。
古代微服务架构都是分布式的,由十分多的服务组成。不同服务之间互相调用,组成简单的调用链路。以上的问题在链路调用中会产生放大的成果。简单链路上的某一环不稳固,就可能会层层级联,最终导致整个链路都不可用。Sentinel Go 提供以下的能力防止慢调用等不稳固因素造成不可用:
- 并发管制(isolation 模块):作为一种轻量级隔离的伎俩,管制某些调用的并发数(即正在进行的数目),避免过多的慢调用挤占失常的调用。
- 熔断降级(circuitbreaker 模块):对不稳固的弱依赖调用进行主动熔断降级,临时切断不稳固调用,防止部分不稳固因素导致整体的雪崩。
Sentinel Go 熔断降级个性基于熔断器模式的思维,在服务呈现不稳固因素(如响应工夫变长,错误率回升)的时候临时切断服务的调用,期待一段时间再进行尝试。一方面避免给不稳固服务“雪上加霜”,另一方面爱护服务的调用方不被拖垮。Sentinel 反对两种熔断策略:基于响应工夫(慢调用比例)和基于谬误(谬误比例 / 谬误数),能够无效地针对各种不稳固的场景进行防护。
留神熔断器模式个别实用于 弱依赖调用,即降级后不影响业务主流程,开发者须要设计好降级后的 fallback 逻辑和返回值。另外须要留神的是,即便服务调用方引入了熔断降级机制,咱们还是须要在 HTTP 或 RPC 客户端配置申请超时工夫,来做一个兜底的防护。
4. 热点防护
流量是随机的,不可预测的。为了避免被大流量打垮,咱们通常会对外围接口配置限流规定,但有的场景下配置一般的流控规定是不够的。咱们来看这样一种场景——大促峰值的时候,总是会有不少“热点”商品,这些热点商品的刹时访问量十分高。个别状况下,咱们能够当时预测一波热点商品,并对这些商品信息进行缓存“预热”,以便在呈现大量拜访时能够疾速返回而不会都打到 DB 上。但每次大促都会涌现出一些“黑马”商品,这些“黑马”商品是咱们无奈当时预测的,没有被预热。当这些“黑马”商品访问量激增时,大量的申请会击穿缓存,间接打到 DB 层,导致 DB 拜访迟缓,挤占失常商品申请的资源池,最初可能会导致系统挂掉。这时候,利用 Sentinel 的热点参数流量管制,自动识别热点参数并管制每个热点值的拜访 QPS 或并发量,能够无效地避免过“热”的参数拜访挤占失常的调用资源。
再比方有的场景下咱们心愿限度每个用户调用某个 API 的频率,将 API 名称 +userId 作为埋点资源名显然是不适合的。这时候咱们能够在给 API 埋点的时候通过 WithArgs(xxx)
将 userId 作为参数传入到 API 埋点中,而后配置热点规定即可针对每个用户别离限度调用频率;同时,Sentinel 也反对针对某些具体值独自配置限流值,进行精细化流控。像其余规定一样,热点流控规定同样反对通过动静数据源进行动静配置。
Sentinel Go 提供的 RPC 框架整合模块(如 Dubbo、gRPC)均会主动将 RPC 调用的参数列表附带在埋点中,用户能够间接针对相应的参数地位配置热点流控规定。留神如果须要配置具体值限流,受类型零碎限度,目前仅反对根本类型和 string 类型。
Sentinel Go 的热点流量管制基于缓存淘汰机制 + 令牌桶机制实现。Sentinel 通过淘汰机制(如 LRU、LFU、ARC 策略等)来辨认热点参数,通过令牌桶机制来管制每个热点参数的访问量。目前的 Sentinel Go 版本采纳 LRU 策略统计热点参数,社区也已有贡献者提交了优化淘汰机制的 PR,在后续的版本中社区会引入更多的缓存淘汰机制来适配不同的场景。
5. 零碎自适应爱护
有了以上的流量防护场景,是不是就万事无忧了呢?其实不是的,很多时候咱们无奈当时就精确评估某个接口的精确容量,甚至无奈预知外围接口的流量特色(如是否有脉冲状况),这时候靠当时配置的规定可能无奈无效地爱护以后服务节点;一些状况下咱们可能忽然发现机器的 Load 和 CPU usage 等开始飚高,但却没有方法很快的确认到是什么起因造成的,也来不及解决异样。这个时候咱们其实须要做的是疾速止损,先通过一些 自动化的兜底防护伎俩,将濒临解体的微服务“拉”回来。针对这些状况,Sentinel Go 提供了一种零碎自适应爱护规定,联合零碎指标和服务容量,自适应动静调整流量。
Sentinel 零碎自适应爱护策略借鉴了 TCP BBR 算法的思维,联合零碎的 Load、CPU 使用率以及服务的入口 QPS、响应工夫和并发量等几个维度的监控指标,通过自适应的流控策略,让零碎的入口流量和零碎的负载达到一个均衡,让零碎尽可能跑在最大吞吐量的同时保证系统整体的稳定性。零碎规定能够作为整个服务的一个兜底防护策略,保障服务不挂,对 CPU 密集型的场景会有比拟好的成果。同时,社区也在联合自动化管制实践和强化学习等伎俩,继续欠缺自适应流控的成果和实用场景。在将来的版本中,社区会也推出更多试验性的自适应流控策略,来满足更多的可用性场景。
云原生摸索
云原生是 Sentinel Go 版本演进最为重要的一环。在 GA 的过程中,Sentinel Go 社区也在 Kubernetes 和 Service Mesh 等场景下进行了一些摸索。
1. Kubernetes CRD data-source
在生产环境中咱们个别都须要通过配置核心来动静治理各种规定配置。在 Kubernetes 集群中,咱们能够人造利用 Kubernetes CRD 的形式来治理利用的 Sentinel 规定。在 Go 1.0.0 版本中社区提供了根本的 Sentinel 规定 CRD 形象以及相应的 数据源实现。用户只须要先导入 Sentinel 规定 CRD 定义文件,接入 Sentinel 时注册对应的 data-source,而后依照 CRD 定义的格局编写 YAML 配置并 kubectl apply 到对应的 namespace 下即可实现动静配置规定。以下是一个流控规定的示例:
apiVersion: datasource.sentinel.io/v1alpha1
kind: FlowRules
metadata:
name: foo-sentinel-flow-rules
spec:
rules:
- resource: simple-resource
threshold: 500
- resource: something-to-smooth
threshold: 100
controlBehavior: Throttling
maxQueueingTimeMs: 500
- resource: something-to-warmup
threshold: 200
tokenCalculateStrategy: WarmUp
controlBehavior: Reject
warmUpPeriodSec: 30
warmUpColdFactor: 3
Kubernetes CRD data-source 模块地址:https://github.com/sentinel-group/sentinel-go-datasource-k8s-crd
后续社区会进一步欠缺 Rule CRD 定义并与其它社区一起探讨高可用防护相干的规范形象。
2. Service Mesh
Service Mesh 是微服务向云原生演进的趋势之一。在 Service Mesh 架构下,一些服务治理和策略管制的能力都逐步下沉到了 data plane 层。去年 Sentinel 社区在 Java 1.7.0 版本外面做了一些尝试,提供了 Envoy Global Rate Limiting gRPC Service 的实现 —— Sentinel RLS token server,借助 Sentinel 集群限流 token server 来为 Envoy 服务网格提供集群流量管制的能力。往年随着 Sentinel Go 版本的诞生,社区与更多的 Service Mesh 产品发展单干、整合。咱们与蚂蚁的 MOSN 社区进行共建,在 MOSN Mesh 中原生反对了 Sentinel Go 的流控降级能力,同时也已在蚂蚁外部落地。社区也在摸索更为通用的计划,如利用 Istio 的 Envoy WASM 扩大机制实现 Sentinel 插件,让 Istio/Envoy 服务网格能够借助 Sentinel 原生的流控降级与自适应爱护的能力来保障整个集群服务的稳定性。
3. Kubernetes HPA based on Sentinel metrics
保障服务稳定性的办法多种多样,除了各种规定对流量进行“管制”之外,“弹性”也是一种思路。对于部署在 Kubernetes 中的利用来说,能够利用 Kubernetes HPA 能力进行对服务进行程度扩缩容。HPA 默认反对多种零碎指标,并且反对自定义指标统计。目前咱们曾经在阿里云 Kubernetes 容器服务上联合 AHAS Sentinel 反对基于服务的均匀 QPS、响应工夫等作为条件进行弹性伸缩。社区也正在这一块做一些尝试,将一些 Sentinel 的服务级别的指标统计(通过量,回绝量,响应工夫等)通过 Prometheus 或 OpenTelemetry 等规范形式透出,并适配到 Kubernetes HPA 中。
当然基于 Sentinel 的弹性计划不是万灵药,它只实用于一些特定的场景,比方实用于启动速度快的无状态服务(Serverless 场景)。对于启动较慢的服务,或非本服务容量问题的场景(如依赖的 DB 容量不够),弹性的计划不能很好地解决稳定性的问题,甚至可能会加剧服务的好转。
Let’s start hacking!
理解了以上的高可用防护的场景,以及 Sentinel 在云原生方向的一些摸索,置信大家对微服务容错与稳定性的伎俩有了新的领会。欢送大家入手玩一下 demo,将微服务接入 Sentinel 来享受高可用防护和容错的能力,让服务“稳如磐石”。同时 Sentinel Go 1.0 GA 版本的公布离不开社区的奉献,感激所有参加奉献的小伙伴们。
本次 GA 咱们也新退出了两位给力的 committer —— @sanxun0325 和 @luckyxiaoqiang,两位在 1.0 版本的演进带来了 Warm Up 流控、Nacos 动静数据源以及一系列性能改良和性能优化,十分踊跃地帮忙社区答疑解惑以及 review 代码。祝贺两位!社区在将来版本中也会朝着云原生和自适应智能化的方向一直摸索和演进,也欢送更多的同学退出奉献小组,一起参加 Sentinel 将来的演进,发明有限可能。咱们激励任何模式的奉献,包含但不限于:
- bug fix
- new features/improvements
- dashboard
- document/website
- test cases
开发者能够在 GitHub 下面的 good first issue 列表上筛选感兴趣的 issue 来参加探讨和奉献。咱们会重点关注积极参与奉献的开发者,外围贡献者会提名为 Committer,一起主导社区的倒退。咱们也欢送大家有任何问题和倡议,都能够通过 GitHub issue、Gitter 或钉钉群(群号:30150716)等渠道进行交换。Now start hacking!
- Sentinel Go repo:https://github.com/alibaba/sentinel-golang
- 企业用户欢送进行注销:https://github.com/alibaba/Sentinel/issues/18
- Sentinel 阿里云企业版:https://ahas.console.aliyun.com/