微服务架构在现代软件开发中变得越来越重要。它通过将大型应用程序拆分成小而自治的服务单元,使开发、部署和维护变得更加灵活和高效。然而,微服务架构也引入了一些新的挑战,其中之一就是“雪崩”问题。
在这篇文章中,我们将探讨什么是雪崩问题,以及如何应对它。 雪崩问题是指在微服务架构中,一个微服务的故障可能会引发级联效应,导致整个系统不可用。这个问题可能会对业务造成严重影响,因此了解如何预防和处理雪崩问题至关重要。
此外,还将介绍 Sentinel 框架,这是一款由阿里巴巴开源的微服务流量控制组件。 Sentinel 可以帮助我们实时监控微服务的性能,并提供流量控制和熔断降级功能,以减轻雪崩问题的影响。然后,我还将探讨 Sentinel 的功能和优势,并演示如何将其集成到微服务项目中。
在微服务架构中,各个微服务之间的依赖错综复杂,一个微服务通常需要依赖多个其他微服务,形成了复杂的调用关系,如下图所示:
在这种情况下,如果某个微服务(如服务I)发生故障,它所依赖的微服务(如A、P、H等)的业务也会受到阻塞。初始阶段,只有依赖服务I的部分业务受到影响,而不依赖服务I的业务似乎不受影响:
然而,由于依赖服务I的业务请求被阻塞,这导致Tomcat服务器上的线程不会释放,从而导致越来越多的用户请求堆积,进一步导致越来越多的线程被阻塞:
服务器的线程和并发处理能力是有限的,如果请求持续阻塞,最终会导致服务器资源耗尽,使得所有其他服务也变得不可用,从而导致整个系统陷入瘫痪,这就是所谓的"雪崩"现象:
在雪崩现象中,一个微服务的故障会引发级联效应,使得整个系统不可用。为了防止雪崩问题的发生,需要采取一些措施来提高系统的稳定性和可用性。接下来,将讨论雪崩问题的原因以及解决方案。
雪崩问题通常由以下几个因素引起:
微服务依赖关系: 微服务之间的复杂依赖关系使得一个微服务的故障可能影响到许多其他微服务。这种依赖关系网络增加了系统的脆弱性。
延迟积累 :当一个微服务变得不可用或响应变慢时,请求会在等待响应的过程中逐渐积累。这会导致服务器资源不断耗尽,进而导致系统崩溃。
高并发请求 :随着时间的推移,越来越多的请求会积累,而且这些请求通常是高并发的。这会导致服务器的线程资源耗尽,无法响应新的请求。
解决雪崩问题的常见方式有四种:
1. 超时处理
超时处理是通过设置合理的请求超时时间来应对雪崩问题。当一个微服务无法及时响应请求时,系统会设定一个最大允许等待时间。如果请求处理时间超过了这个时间限制,系统会立即返回错误信息,而不会无限制地等待。这可以防止请求积累并占用系统资源。
2. 仓壁模式
仓壁模式是一种线程隔离的策略,它通过限制每个业务能够使用的线程数来避免耗尽整个Tomcat服务器的资源。在这种模式下,每个微服务的线程资源被隔离开,因此如果一个微服务出现异常,只会影响到其自身的线程,而不会影响其他微服务的线程。
例如,如上图所示,服务A依赖于服务B和服务C,在服务A中为服务B和服务C分别分配了各自的线程池,即使其中一个微服务发生异常,也只会浪费该微服务的线程,不会影响其他微服务。
3. 熔断降级
熔断降级是通过断路器来统计业务执行的异常比例,当异常比例超出阈值时,会触发熔断机制,拦截访问该业务的所有请求。这样可以避免异常的微服务继续接受请求,减轻其负载,同时也阻止了可能导致雪崩的请求传递。
断路器会统计访问某个服务的请求数量以及异常比例,如下图所示:
当异常比例过高时,认为服务存在导致雪崩的风险,断路器将拦截访问该服务的所有请求,形成熔断,如下图所示:
此时,访问服务D的请求会被拦截,从而避免雪崩效应的扩散。
4. 流量控制
流量控制是通过限制业务访问的每秒查询率(QPS)来防止雪崩问题。这可以确保系统不会因流量的突然增加而崩溃。通过设定每个微服务的最大QPS值,可以限制请求的数量,防止过多的请求积累并占用系统资源。
例如,如上图所示,现在有大量的请求,但只有在限定的QPS下的请求数量才能访问该服务,从而防止过多的请求对系统造成负担。
雪崩问题是指在微服务架构中,微服务之间相互依赖,当其中一个微服务发生故障或不可用时,其它微服务的请求也会受到影响,最终导致整个系统不可用的现象。可以总结为:
针对雪崩问题,可以采取以下措施:
限流:限制每个微服务的请求并发数,防止过多请求积累,从而减轻服务器压力。是一种预防措施。
超时处理、线程隔离、降级熔断:这些方法是在某个微服务出现故障时,将故障控制在一定范围,避免它蔓延至整个系统,从而避免雪崩。是一种补救措施。
这些措施有助于提高系统的稳定性和可用性,防止雪崩问题的发生。限流是一种预防措施,而超时处理、线程隔离、降级熔断等是应对已发生问题时的补救措施。综合使用这些方法可以有效应对雪崩问题。
Sentinel 是一款由阿里巴巴开源的微服务流量控制组件。它被设计用来解决微服务架构中的流量控制和熔断降级等问题。
官网地址:https://sentinelguard.io/zh-cn/index.html。
Sentinel 具有以下特点和功能:
丰富的应用场景: Sentinel可以应用于多种场景,包括处理突发流量、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。它在阿里巴巴双十一大促销活动等高流量场景中得到了验证。
完备的实时监控: Sentinel提供实时的监控功能,允许您查看接入应用的单台机器的秒级数据,甚至是小型集群的汇总运行情况。这有助于及时发现问题并进行调整。
广泛的开源生态: Sentinel提供了与其他开源框架和库的整合模块,如与Spring Cloud、Dubbo、gRPC等的整合。这使得在不同技术栈中快速接入Sentinel变得更加容易。
完善的SPI扩展点: Sentinel具有丰富的扩展接口,允许开发人员通过实现这些接口来定制逻辑,如规则管理和动态数据源适配等。这提供了高度的可扩展性。
Sentinel 的核心功能包括流量控制、熔断降级、系统负载保护、实时监控和控制台等,它在微服务架构中起到了重要的作用,帮助开发者确保系统的稳定性和可用性。
Hystrix 是 Netflix 开源的一款用于处理分布式系统中的延迟和容错问题的库。它和 Sentinel 的作用差不多,主要用于防止分布式系统中的雪崩效应,提供了线程隔离、熔断降级、超时控制等功能。Hystrix已经被广泛用于构建弹性和可靠的微服务架构。
Sentinel 和 Hystrix 的对比:
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于慢调用比例或异常比例 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速排队模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
上述表格总结了这两个流量控制和容错处理框架的主要特点。这些特点包括隔离策略、熔断降级策略、实时指标实现、规则配置、扩展性、基于注解的支持、限流、流量整形、系统自适应保护、控制台功能以及常见框架的适配。
使用 Sentinel 的情况:
需要细粒度的流量控制: 如果需要对不同的微服务或接口进行精细的流量控制,Sentinel 提供了信号量隔离和基于 QPS 的限流策略,可以更灵活地管理流量。
实时监控和控制台功能: Sentinel 提供了实时监控和丰富的控制台功能,允许查看秒级监控数据、配置规则以及进行机器发现。这对于监控和管理微服务非常有用。
支持多种数据源: Sentinel 支持多种数据源,包括内存、Nacos、Zookeeper等,这使得配置规则更加灵活。
需要灵活的扩展性: Sentinel 提供多个扩展点,允许通过自定义实现来满足特定需求,如规则管理、动态数据源等。
需要支持流量整形: Sentinel 支持慢启动和匀速排队模式,可帮助应对流量突发情况。
需要系统自适应保护: Sentinel 支持系统自适应保护,可以根据系统状态动态调整保护策略。
使用 Hystrix 的情况:
Spring Cloud项目: 如果项目是基于Spring Cloud构建的,Hystrix 是 Spring Cloud Netflix 的一部分,因此更容易集成。
需要线程池隔离: 如果需要使用线程池隔离来隔离不同微服务的调用,Hystrix 提供了线程池隔离的支持。
需要更广泛的社区支持: Hystrix 有一个广泛的社区支持,因为它是 Netflix 开源的项目之一,有更多的文档和教程可供参考。
总之,应该根据项目需求、技术栈和团队的熟悉程度来选择使用 Sentinel 还是 Hystrix 。在某些情况下,两者也可以同时使用以获得更全面的容错和熔断降级能力。
1. 下载 Sentinel:
Sentinel 官方提供了一个UI控制台,方便我们对系统进行保护的操作,下载 Sentinel 的地址:https://github.com/alibaba/Sentinel/releases。
2. 运行:
将 JAR 包放到任意非中文目录,执行下面的命令运行 Sentinel:
java -jar sentinel-dashboard-1.8.1.jar
可以发现,Sentinel 是一个 Spring Boot 项目,默认的端口号是 8080:
如果要修改 Sentinel 的默认端口、账户、密码,可以通过下列配置:
配置项 | 默认值 | 说明 |
---|---|---|
server.port |
8080 | 服务端口 |
sentinel.dashboard.auth.username |
sentinel | 默认用户名 |
sentinel.dashboard.auth.password |
sentinel | 默认密码 |
例如,修改端口:
java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar
3. 服务 Sentinel 控制台
访问http://localhost:8080
页面,就可以看到 Sentinel 的控制台,默认的用户和密码都是 sentinel
:
下面,我们的目标是将Sentinel集成到 cloud-demo 项目中,cloud-demo 是一个简单的微服务项目demo,其结构如下图所示:
现在要求在 order-service 微服务中集成 Sentinel,实现的步骤如下:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
application.yml
配置文件中添加 Sentinel 控制台地址spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台地址
order-service
服务,访问任意接口,触发 Sentinel 监控再次查看 Sentinel 控制台: