微服务涉及到多个服务间的调用,为了保证服务的高可用,需要限流来防止某个服务负载过高,而导致系统崩溃。
01 限流算法
限流基于特定的限流算法,先了解常用的限流算法,主要有以下几种:
1、时间窗算法
设置一个时间窗口,统计该时间窗口内服务的访问量或TPS,并与设置的阈值比较,如果超过阈值则拒绝新的请求。窗口算法的简单实现是固定窗口算法,更精细控制的有滑动窗口算法。
2、令牌桶算法
模拟一个桶,一开始桶内有一定数量的令牌,每个请求需要先获取一个令牌,当令牌桶为空时拒绝新的请求,同时,令牌桶还可以设定一个上限,防止突发流量的出现。
3、漏斗算法
模拟一个实际漏斗,每次请求相当于向漏斗中放水,当漏斗中的水超过固定高度时,拒绝新的请求,同时可以设置漏口的大小,控制处理速度。实际应用中,可以结合以上几种算法来实现微服务项目的限流,根据不同的场景和需求,选择合适的限流算法,同时应该对限流算法进行测试和性能调优,确保限流策略的可靠性和有效性。
02 微服务请求链路
微服务架构中请求链路长,请求环节比较多,先看一张典型的微服务部署架构如下图
按请求环节分类来说,可以在三个环节进行限流,请求接入层、微服务间调用层、数据存储层。而在每个请求环节,可选择的限流中间件有多个,下面按各个环节分别介绍。
03 请求接入层
接入层管理着整个微服务系统的请求入口,并负责协调和分配请求。为了保证请求接入层的高可用,以下是常用的限流中间件:
1. Nginx
Nginx是一个高性能的Web服务器和反向代理服务器,它支持漏斗算法和令牌桶算法,可以在应用程序服务器之前扮演限流中间件的角色。Nginx提供了许多内置模块,其中一个非常有用的模块是限流模块,包括 limit_req_module 和 limit_conn_module。
1)limit_req_module:这个模块通过限制客户端请求的速率,可以保护服务器免受过多请求的压力。该模块会将请求统一放到一个队列中,请求队列中只会允许一定数量的请求,超过限制数量的请求将会被拒绝。
2)limit_conn_module:该模块通过控制相同IP地址的连接数量,可以保护服务器免受过多的连接请求的压力。这个模块可以限制每个IP地址的最大连接数,超过限制的连接会被拒绝,并返回一个特定的错误码。
2. Spring Cloud Gateway
简称Gateway是由Spring Cloud推出的基于Spring框架的API网关微服务工具。它提供了丰富的过滤器机制和插件机制,并支持集中的限流控制。下面是常用的限流功能
1)限流插件:Gateway提供了基于令牌桶算法实现的限流插件,能够对请求的总数、速率和时间间隔等维度进行限制控制。通过设置限流规则、参数等参数来限制接口的调用频率,从而保护服务,防止服务被恶意请求攻击。
2)自定义过滤器:在Gateway中可以自定义过滤器实现请求转发、请求日志、限流、请求验证等功能,在实际项目中可以根据需要动态添加过滤器,实现定制化的流量控制。
3)集成第三方限流组件:除了集成Sentinel,Gateway也支持集成其他例如Redis、Guava Cache等组件来实现限流功能。
Gateway通过强大的插件机制、自定义过滤器和集成第三方限流组件等方式,为微服务架构的限流提供了多种解决方案,并且非常易于扩展和重构,是一个非常实用的API网关工具。
3. Kong
Kong是一个开源的云原生API网关和微服务管理平台,它支持从L4/L7代理和服务网格到API管理和服务发现。Kong的限流功能非常强大,支持请求频次,请求速率,请求阶段,用户密钥等多种限制方式。
比较特别的有请求阶段限制:用于在处理请求的不同阶段设置限制,针对每个API的每个阶段配置独立的、可配置的限制策略。比如,限制TCP重新汇总的连接数,限制SSL握手或者HTTP请求等待的连接数等。还有用户密钥限制:限制单个用户或者API Key对API进行的请求频次或者速率。同时,Kong还支持为不同的用户分配不同的配额和限制。
4. Netflix Zuul
Zuul 是 Netflix 公司开源的一个基于 JVM 的路由和服务端负载均衡器。它支持灵活的路由配置和过滤器机制,可以在 Gateway 层面对接入系统进行限流。由于 Zuul 已经停止维护,这里就不过多介绍了。
04 微服务调用层
在微服务架构中,为了保护后端服务免受过多请求的影响,需要对服务间的调用进行限流。在微服务间调用层,常用的的限流中间件有
1、Netflix Hystrix
Hystrix是一个Netflix开源的延迟和容错库,可以为分布式系统提供延迟容错和弹性功能。它通过线程隔离、请求缓存和断路器等机制,保证服务调用始终可用。现在各个培训平台鼓吹Hystrix已停止维护,快使用 Alibaba Cloud Sentinel吧。
2、Alibaba Cloud Sentinel
Sentinel是一款轻量级的流量控制、熔断降级、系统负载保护的防护组件,支持多样化的应用场景,包括RPC、HTTP和消息队列等。Sentinel使用令牌桶算法和漏桶算法实现限流。令牌桶算法是较为常用的限流算法,可以控制请求的速率。漏桶算法则通过缓存流量,控制流量的处理速度。支持使用这两种算法进行限流,并支持自定义限流规则。
另外,Sentinel还提供了实时监控和告警功能,能够帮助用户发现服务性能问题并快速解决。可以在实时监控中通过控制台查看请求量、响应时间、错误码和错误率等指标,也可以配置告警策略,以自动发送警报邮件。
3、常用的消息队列
消息队列的一大特性就是削峰填谷,这不就明显是限流嘛。将消息队列用作限流,具有以下几个特点:
1)解耦:将消息发送到队列中之后,请求方不需要关心其他方如何处理这些消息,可以自己专注于其他工作。同时,处理方也可以自己独立地处理队列中的消息。
2)异步处理:请求方无需等待处理方完成相关处理,整个流程是异步的,这可以大大提高系统的处理效率。
3)高可用性:消息队列具备消息持久化、消息复制、自动恢复等特性,可以有效地避免消息丢失或者其他相关问题的出现,从而保证了系统的高可用性。
4)可扩展性:消息队列属于比较典型的分布式系统,具备可以通过增加节点或者轻松扩展硬件资源等特性,可以轻松实现相对灵活的系统扩展。
5)可调控性:通过调整消息队列的容量和处理速度,可以实现相对精准的限流策略,并可以根据不同的场景进行动态配置。
4、云原生中间件
常见的限流中间件还有Envoy和Istio等,其他开源的也可以选择,例如云原生中间件Linkerd、OpenResty、Traefik等,这里不一一介绍了。
05 数据存储层
数据存储层通常是基于数据库的,为了保护数据库免受恶意请求和过度流量影响,需要对访问数据库的请求进行限流。
1、Redission
Redisson是一个Java的分布式锁和内存数据结构库,支持各种Redis功能。Redisson还支持对请求进行限流,可以使用漏桶算法和令牌桶算法等多种限流策略。Redisson限流功能是通过分布式数据库Redis实现的,因此具有强大的可扩展性和可靠性。此外,Redisson还提供了一些方便的方法来定期刷新限流规则、定期清理过期的限流规则,提高限流的精度和效率。
2、Google Guava
Guava 是 Google 开源的一个 Java 工具包,里面提供了很多常用的工具类和函数库,其中就包括限流功能的支持。
1)RateLimiter:RateLimiter 是 Guava 提供的限流类,它可以限制某个单位时间内的事件发生频率。
2)SmoothBursty:这是基于平滑突发限流的一种算法,用于对任务的执行进行限制。
3)SmoothWarmingUp:基于平滑突发限流的一种算法,它可以在冷启动时对任务的执行进行限制,避免冷启动时任务执行过于激进,导致系统负载过高。
3、Spring Resilience4j
Spring Resilience4j 是一个基于 Spring Boot 的轻量级容错库,提供了多种容错模式,其中就包括限流功能。
1)RateLimiter:这是 Resilience4j 提供的限流类,它可以限制某个单位时间内的事件发生频率。
2)SemaphoreBasedRateLimiter:这是一种自定义的限流类,它通过 Semaphore 内置的令牌桶算法实现了限流功能。可以使用该类来实现更细粒度的限流控制。
我们知道有很多代码库实现了RateLimiter,另外也可以自己编码实现,基于 AOP实现自定义注解,限流数据可在分布式存储的Redis中。
06 小结收尾
选择适当的中间件来实现请求链各个环节的限流策略,可以提高微服务架构的可用性和稳定性。当然,不同的中间件实现方式不同,应该根据不同的场景选择一个或多个中间件限流,并结合具体的业务情况和系统瓶颈进行评估和调优,以达到更好的限流效果。