【微服务架构】分布式限流策略
在k8s中,服务是动态扩缩容的,相应的,每个节点应该都要有所变化,如果对外宣称限频100qps,而且后续业务方真的要求百分百准确,只能把LoadingCache的过期时间调小一点,让它能够近实时的更新单节点的qps。在实际的服务中,数据上报服务一般无法确定客户端的上报时间、上报量,特别是对于这种要求高性能,服务一般都会用到HPA来实现动态扩缩容,所以,需要去间隔一段时间去获取服务的副本数。如果服务
文章目录
三层限流
1.第一层限流:合法性限流
waf 防火墙,流量管理和爬虫防控, 如 阿里云waf
2.第二层限流:网关、负载限流
1.istio 无入侵式限流
2.k8s ingress ratelimit(nginx限流)
3.流量入口nginx 连接数、请求量做限制
第三层限流:服务限流(应用层限流)
多节点:负载均衡+本地限流算法(令牌桶…)
第四层限流:用户级别限流
分布式 redis+lua 细粒度对 对单用户(uid、ip)级别做限流
限流方式
集中式(全局)限流
网关层限流服务网关,作为整个分布式链路中的第一道关卡,承接了所有用户来访请求。我们在网关层进行限流,就可以达到了整体限流的目的了。
目前,主流的网关层有以软件为代表的Nginx,还有Spring Cloud中的Gateway和Zuul这类网关层组件,也有以硬件为代表的F5。
进程内限流
单机限流
漏斗桶,令牌桶等算法限流
依赖配置中心
如果有注册中心(consul、nacos、etcd),可以实时获取注册中心节点数
如果服务的节点动态调整,单个服务的qps也能动态调整。
go-zero基于redis设计的两款分布式限流器
https://github.com/zeromicro/go-zero/tree/master/core/limit
优点:设计、实现简单,拿来即用
缺点:qps较高,redis内存消耗严重
其中,ping redis大概6-7ms左右,对应的,每次请求需要访问redis,时延都有大概6-7ms,性能下降明显
对于极致追求高性能的服务不需要考虑熔断、降级来说,是需要尽量减少网络之间的IO
kubernetes怎么实现分布式限流
istio
https://cloud.tencent.com/developer/article/1468273
ingress rate limiting
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting
k8s获取pod副本数做限流
在实际的服务中,数据上报服务一般无法确定客户端的上报时间、上报量,特别是对于这种要求高性能,服务一般都会用到HPA来实现动态扩缩容,所以,需要去间隔一段时间去获取服务的副本数。
import (
"context"
"github.com/why19970628/k8s-cheatsheet/models"
"github.com/why19970628/k8s-cheatsheet/utils"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"log"
"strings"
)
func CountDeploymentSize(c kubernetes.Interface, namespace string, deploymentName string) *int32 {
deployment, err := c.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
utils.HandlerCheck(err)
return deployment.Spec.Replicas
}
-
对于保证qps限频准确的时候,应该怎么解决呢?
在k8s中,服务是动态扩缩容的,相应的,每个节点应该都要有所变化,如果对外宣称限频100qps,而且后续业务方真的要求百分百准确,只能把LoadingCache<String, RateLimiter>的过期时间调小一点,让它能够近实时的更新单节点的qps。这里还需要考虑一下k8s的压力,因为每次都要获取副本数,这里也是需要做缓存的 -
服务从1个节点动态扩为4个节点,这个时候新节点识别为4,但其实有些并没有启动完,会不会造成某个节点承受了太大的压力
理论上是存在这个可能的,这个时候需要考虑一下初始的副本数的,扩缩容不能一蹴而就,一下子从1变为4变为几十个这种。一般的话,生产环境肯定是不能只有一个节点,并且要考虑扩缩容的话,至于要有多个副本预备的 -
如果有多个副本,怎么保证请求是均匀的
这个是依赖于k8s的service负载均衡策略的,流量是能够均匀的落到节点上的。整个限流都是基于k8s的,如果k8s出现问题,那就是整个集群所有服务都有可能出现问题了。
k8s ingress限流配置
限速的注解定义了对连接和传输速率的限制。这些可以用来减轻DDoS攻击。它采用了 “漏斗” 算法实现限制。
-
nginx.ingress.kubernetes.io/limit-connections
单个IP地址允许的并发连接数。超出此限制时,将返回503错误。 -
nginx.ingress.kubernetes.io/limit-rps
每秒从给定IP接受的请求数。突发限制设置为此限制乘以突发乘数,默认乘数为5。当客户端超过此限制时,将 返回limit-req-status-code默认值: 503,如果修改其它响应码,需要重写nginx.ingress.kubernetes.io/configuration-snippet配置,如下annotations: kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/limit-burst-multiplier: "3" nginx.ingress.kubernetes.io/limit-rpm: "1" nginx.ingress.kubernetes.io/configuration-snippet: | limit_req_status 429;
-
nginx.ingress.kubernetes.io/limit-rpm:每分钟从给定IP接受的请求数。突发限制设置为此限制乘以突发乘数,默认乘数为5。当客户端超过此限制时,将 返回limit-req-status-code默认值: 503。
-
nginx.ingress.kubernetes.io/limit-burst-multiplier:
突发大小限制速率的倍数。默认的脉冲串乘数为5,此注释将覆盖默认的乘数。当客户端超过此限制时,将 返回limit-req-status-code默认值: 503。 -
nginx.ingress.kubernetes.io/limit-rate-after:最初的千字节数,在此之后,对给定连接的响应的进一步传输将受到速率的限制。必须在启用代理缓冲的情况下使用此功能。
-
nginx.ingress.kubernetes.io/limit-rate:每秒允许发送到给定连接的千字节数。零值禁用速率限制。必须在启用代理缓冲的情况下使用此功能。
-
nginx.ingress.kubernetes.io/limit-whitelist:客户端IP源范围要从速率限制中排除。该值是逗号分隔的CIDR列表。
ingress控制器会把注解修改成如下nginx配置,此例子之修改了limit-rps=5或者limit-rpm=300,limit-burst-multiplier(放大系数)为默认值5。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-example-host
annotations:
# 每个 IP 每秒可以访问 5 次
nginx.ingress.kubernetes.io/limit-rps: 5
# 为计算限速漏桶算法的 burst size,和 limit-rps 的相乘系数
nginx.ingress.kubernetes.io/limit-burst-multiplier: 5
# 配合 limit-window 表示全局限速 100 次每秒(需要依赖 memcached,在configmap中配置)
nginx.ingress.kubernetes.io/global-rate-limit: 100
nginx.ingress.kubernetes.io/global-rate-limit-window: 1s
# 限制发送给后端服务的发送速率为 1MB 每秒
nginx.ingress.kubernetes.io/limit-rate: 1024
# 发送给后端服务的前 10MB 数据不进行限速
nginx.ingress.kubernetes.io/limit-rate-after: 10240
# 超出后的响应码
nginx.ingress.kubernetes.io/configuration-snippet: |
limit_req_status 429;
spec:
rules:
- host: "www.test.com"
http:
paths:
- path: "/"
backend:
service:
name: test
port:
number: 80
更多推荐
所有评论(0)