k8s API限流

1. 背景

为了防止突发流量影响apiserver可用性,k8s支持多种限流配置,包括:

  • MaxInFlightLimit,server级别整体限流
  • Client限流
  • EventRateLimit, 限制event
  • APF,更细力度的限制配置

1.1 MaxInFlightLimit限流

  • apiserver默认可设置最大并发量(集群级别,区分只读与修改操作)
  • 通过参数–max-requests-inflight代表只读请求
  • –max-mutating-requests-inflight代表修改请求
  • 可以简单实现限流。

1.1.1 源码解读

  • 入口 GenericAPIServer.New中的添加hook

     	// FlowControl为nil ,代表未启用 APF,API 服务器中的整体并发量将受到 kube-apiserver 的参数 --max-requests-inflight 和 --max-mutating-requests-inflight 的限制。
    	if c.FlowControl != nil {
    		const priorityAndFairnessFilterHookName = "priority-and-fairness-filter"
    		if !s.isPostStartHookRegistered(priorityAndFairnessFilterHookName) {
    			err := s.AddPostStartHook(priorityAndFairnessFilterHookName, func(context PostStartHookContext) error {
    				genericfilters.StartPriorityAndFairnessWatermarkMaintenance(context.StopCh)
    				return nil
    			})
    			if err != nil {
    				return nil, err
    			}
    		}
    	} else {
    		const maxInFlightFilterHookName = "max-in-flight-filter"
    		if !s.isPostStartHookRegistered(maxInFlightFilterHookName) {
    			err := s.AddPostStartHook(maxInFlightFilterHookName, func(context PostStartHookContext) error {
    				genericfilters.StartMaxInFlightWatermarkMaintenance(context.StopCh)
    				return nil
    			})
    			if err != nil {
    				return nil, err
    			}
    		}
    	}
    
    
    // StartMaxInFlightWatermarkMaintenance starts the goroutines to observe and maintain watermarks for max-in-flight
    // requests.
    func StartMaxInFlightWatermarkMaintenance(stopCh <-chan struct{}) {
    	startWatermarkMaintenance(watermark, stopCh)
    }
    
    
    // startWatermarkMaintenance starts the goroutines to observe and maintain the specified watermark.
    func startWatermarkMaintenance(watermark *requestWatermark, stopCh <-chan struct{}) {
    	// 定期更新inflight使用指标
    	go wait.Until(func() {
    		watermark.lock.Lock()
    		readOnlyWatermark := watermark.readOnlyWatermark
    		mutatingWatermark := watermark.mutatingWatermark
    		watermark.readOnlyWatermark = 0
    		watermark.mutatingWatermark = 0
    		watermark.lock.Unlock()
    
    		metrics.UpdateInflightRequestMetrics(watermark.phase, readOnlyWatermark, mutatingWatermark)
    	}, inflightUsageMetricUpdatePeriod, stopCh)
      // 定期观察watermarks。这样做是为了确保他们不会落后太多。当他们
      //落后太多时,在响应接收到的下一个请求时会有很长的延迟,而观察者
      //会赶上来。
       go wait.Until(func() {
          watermark.readOnlyObserver.Add(0)
          watermark.mutatingObserver.Add(0)
      }, observationMaintenancePeriod, stopCh)
    }
    
    
  • WithMaxInFlightLimit代表限流处理函数

调用入口: staging\src\k8s.io\apiserver\pkg\server\config.go

DefaultBuildHandlerChain中,判断FlowControl为nil就开启WithMaxInFlightLimit,

if c.FlowControl != nil {
        requestWorkEstimator := flowcontrolrequest.NewWorkEstimator(c.StorageObjectCountTracker.Get)
        handler = filterlatency.TrackCompleted(handler)
        handler = genericfilters.WithPriorityAndFairness(handler, c.LongRunningFunc, c.FlowControl, requestWorkEstimator)
        handler = filterlatency.TrackStarted(handler, "priorityandfairness")
    } else {
        handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc)
    }



func WithMaxInFlightLimit(
	handler http.Handler,
	nonMutatingLimit int,
	mutatingLimit int,
	longRunningRequestCheck apirequest.LongRunningRequestCheck,
) http.Handler {
	// 如果limit num为0就不开启限流了
	if nonMutatingLimit == 0 && mutatingLimit == 0 {
		return handler
	}
	var nonMutatingChan chan bool
	var mutatingChan chan bool
	// 构造限流的chan,类型为长度=limit的 bool chan
	if nonMutatingLimit != 0 {
		nonMutatingChan = make(chan bool, nonMutatingLimit)
		klog.V(2).InfoS("Initialized nonMutatingChan", "len", nonMutatingLimit)
	} else {
		klog.V(2).InfoS("Running with nil nonMutatingChan")
	}
	if mutatingLimit != 0 {
		mutatingChan = make(chan bool, mutatingLimit)
		klog.V(2).InfoS("Initialized mutatingChan", "len", mutatingLimit)
	} else {
		klog.V(2).InfoS("Running with nil mutatingChan")
	}
	initMaxInFlight(nonMutatingLimit, mutatingLimit)
	// 发起请求
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		requestInfo, ok := apirequest.RequestInfoFrom(ctx)
		if !ok {
			handleError(w, r, fmt.Errorf("no RequestInfo found in context, handler chain must be wrong"))
			return
		}

		// 检查是否是长时间运行的请求
		if longRunningRequestCheck != nil && longRunningRequestCheck(r, requestInfo) {
			handler.ServeHTTP(w, r)
			return
		}

	 。。。。。。。。
}



// LongRunningRequestCheck is a predicate which is true for long-running http requests.
type LongRunningRequestCheck func(r *http.Request, requestInfo *RequestInfo) bool

使用BasicLongRunningRequestCheck检查是否是watch或者pprof debug等长时间运行的请求,因为这些请求不受限制,位置

func BasicLongRunningRequestCheck(longRunningVerbs, longRunningSubresources sets.String) apirequest.LongRunningRequestCheck {
	return func(r *http.Request, requestInfo *apirequest.RequestInfo) bool {
		if longRunningVerbs.Has(requestInfo.Verb) {
			return true
		}
		if requestInfo.IsResourceRequest && longRunningSubresources.Has(requestInfo.Subresource) {
			return true
		}
		if !requestInfo.IsResourceRequest && strings.HasPrefix(requestInfo.Path, "/debug/pprof/") {
			return true
		}
		return false
	}
}

检查是只读操作还是修改操作,决定使用哪个chan限制

		var c chan bool
		isMutatingRequest := !nonMutatingRequestVerbs.Has(requestInfo.Verb)
		if isMutatingRequest {
			c = mutatingChan
		} else {
			c = nonMutatingChan
		}

如果队列未满,有空位置,则更新排队数字

  • 使用select 向c中写入true,如果能写入到说明队列未满
  • 记录下对应的指标
		select {
			case c <- true:
				// We note the concurrency level both while the
				// request is being served and after it is done being
				// served, because both states contribute to the
				// sampled stats on concurrency.
				if isMutatingRequest {
					watermark.recordMutating(len(c))
				} else {
					watermark.recordReadOnly(len(c))
				}
				// default代表队列已满
				defer func() {
					<-c
					if isMutatingRequest {
						watermark.recordMutating(len(c))
					} else {
						watermark.recordReadOnly(len(c))
					}
				}()
				handler.ServeHTTP(w, r)

但是如果请求的group中含有 system:masters,则放行, 因为apiserver认为这个组是很重要的请求,不能被限流.

  • group=system:masters 对应的clusterRole 为cluster-admin, 队列已满,如果请求的group中没有 system:masters,则返回http 429错误,并且丢弃请求
				// at this point we're about to return a 429, BUT not all actors should be rate limited.  A system:master is so powerful
				// that they should always get an answer.  It's a super-admin or a loopback connection.
				if currUser, ok := apirequest.UserFrom(ctx); ok {
					for _, group := range currUser.GetGroups() {
						if group == user.SystemPrivilegedGroup {
							handler.ServeHTTP(w, r)
							return
						}
					}
				}

  • http 429 代表当前有太多请求了,请重试,并设置 response 的header Retry-After =1
// We need to split this data between buckets used for throttling.
				metrics.RecordDroppedRequest(r, requestInfo, metrics.APIServerComponent, isMutatingRequest)
				metrics.RecordRequestTermination(r, requestInfo, metrics.APIServerComponent, http.StatusTooManyRequests)
				tooManyRequests(r, w)

func tooManyRequests(req *http.Request, w http.ResponseWriter) {
	// Return a 429 status indicating "Too Many Requests"
	w.Header().Set("Retry-After", retryAfter)
	http.Error(w, "Too many requests, please try again later.", http.StatusTooManyRequests)
}

1.2 Client限流

client-go默认的qps为5,但是只支持客户端限流,只能由各个发起端限制

  • 集群管理员无法控制用户行为。

1.3 EventRateLimit

  • EventRateLimit在1.13之后支持,只限制event请求
  • 集成在apiserver内部webhoook中
  • 可配置某个用户、namespace、server等event操作限制,通过webhook形式实现。

集群管理员可以通过以下方式指定事件速率限制:

  • 启用 EventRateLimit 准入控制器;

  • 在通过 API 服务器的命令行标志 --admission-control-config-file 设置的文件中, 引用 EventRateLimit 配置文件:

    apiVersion: apiserver.config.k8s.io/v1
    kind: AdmissionConfiguration
    plugins:
      - name: EventRateLimit
        path: eventconfig.yaml
    ...
    

    可以在配置中指定的限制有四种类型:

    • Server:API 服务器收到的所有(创建或修改)Event 请求共享一个桶。
    • Namespace:每个名字空间都对应一个专用的桶。
    • User:为每个用户分配一个桶。
    • SourceAndObject:根据事件的来源和涉及对象的各种组合分配桶。

    eventconfig.yaml 示例

    apiVersion: eventratelimit.admission.k8s.io/v1alpha1
    kind: Configuration
    limits:
      - type: Namespace
        qps: 50
        burst: 100
        cacheSize: 2000
      - type: User
        qps: 10
        burst: 50
    

原理

  • 具体原理可以参考提案,每个eventratelimit 配置使用一个单独的令牌桶限速器
  • 每次event操作,遍历每个匹配的限速器检查是否能获取令牌,如果可以允许请求,否则返回429。

优点

  • 实现简单,允许一定量的并发
  • 可支持server/namespace/user等级别的限流

缺点

  • 仅支持event,通过webhook实现只能拦截修改类请求

  • 所有namespace的限流相同,没有优先级

参考文档:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/#eventratelimit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/6778.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】内存管理+模板

前言&#xff1a; 本章将详细讲解C内存管理和模板的实现。 第一部分我们讲解C内存管理&#xff0c;C语言中有malloc/calloc/realloc等开辟空间和free释放空间&#xff0c;那么C将符合实现呢&#xff1f; 第二部分我们会一起来初步认识模板与泛型编程&#xff0c;并详细探讨函…

微服务高级篇【1】之微服务保护

文章目录前言一 初识Sentinel1.1 雪崩问题1.2 解决方法1.3 小结1.4 服务保护技术对比1.5 Sentinel介绍1.6 Sentinel安装1.7 微服务整合Sentinel二 测试工具&#xff1a;Jmeter2.1 Jmeter安装和配置2.2 Jmeter快速入门2.2.1 设置中文语言2.2.2 设置Jmeter桌面快捷图标2.3 Jmeter…

已经提了离职,还有一周就走,公司突然把我移出企业微信,没法考勤打卡, 还要继续上班吗?...

黎明前的黑暗最容易出事&#xff0c;离职前的几天也最容易出幺蛾子&#xff0c;比如下面这位网友的遭遇&#xff1a;已经提了离职&#xff0c;还有一周就正式离职了&#xff0c;公司突然把我移出企业微信&#xff0c;没法考勤打卡了&#xff0c; 还要继续上班吗&#xff1f;该怎…

BGP小型实验

实验分析 1.主要考察的是对BGP配置的熟练 2.实验需要在R1与R5分别发布一条路由可以在BGP 中使用network 网段 掩码命令 3.R1与R2,R4与R5是EBGP&#xff0c;而R2,R3,R4是IBGP 实验操作 1.配置接口ip,与环回路由 以R1为例 2.AS内部需要实现非直连的建立是需要保证IBGP内部是通的所…

蓝桥杯30天真题冲刺|题解报告|第三十天

大家好&#xff0c;我是snippet&#xff0c;今天是我们这次蓝桥省赛前一起刷题的最后一天了&#xff0c;今天打了一场力扣周赛&#xff0c;前面3个题都是有思路的&#xff0c;第三个题只过了一半的案例&#xff0c;后面看完大佬们的题解彻悟&#xff0c;下面是我今天的题解 目录…

蓝桥杯备考

数论&#xff1a;判断素数&#xff0c;鸽笼定理&#xff0c;抽屉理论 注意事项&#xff1a; long类型的数后面要加L long s 2658417853L; 保留几位小数&#xff1a; System.out.printf(“%.2f”, arg); 四舍五入问题&#xff1a;比如保留两位小数&#xff0c;就在数的后面再…

java基础知识汇总

目录 1、Java基础语法 1、类型转换问题 1. 运算符 1.1 算术运算符&#xff08;理解&#xff09; 1.2 赋值运算符&#xff08;应用&#xff09; 1.3 自增自减运算符&#xff08;理解&#xff09; 1.4 关系运算符&#xff08;应用&#xff09; 1.5 逻辑运算符&#xff08…

【CSS】清除浮动 ④ ( 清除浮动 - 使用双伪元素清除浮动 | 代码示例 )

文章目录一、清除浮动 - 使用双伪元素清除浮动二、代码示例一、清除浮动 - 使用双伪元素清除浮动 为 .clearfix:before 和 .clearfix:after 并集选择器 , 设置如下样式 : /* 清除浮动 - 使用双伪元素清除浮动 */.clearfix:before,.clearfix:after {content: "";displ…

ERTEC200P-2 PROFINET设备完全开发手册(1)

本教程为ERTEC200P-2的基础开发教程&#xff0c;可以掌握PN设备开发的基本流程。虽然没有涉及PN协议的详细解析&#xff0c;但是希望根据本文档多多练习&#xff0c;熟能生巧&#xff0c;逐渐能够掌握PN设备开发。 &#xff08;注意&#xff1a;本手册基于西门子DEVKIT V47协议…

oracle导入的表中文名称乱码无法删除导致删除用户也失败

由于一开始弄数据库的时候忘记设置编码格式&#xff0c; 导致导入dmp文件之后带中文的表名变成了乱码 然后plsql右键删除表显示表不存在 一开始的时候寻思备份下表结构跟表数据 直接删除用户完事了 删除用户报递归遍历错误 寻思重装这个数据库太过于耗时 不值当的 就是看那几…

【JWT鉴权】如何来写一个token令牌认证登录?

目录一. &#x1f981; 话题引入1.2 什么是JWT&#xff1f;二. &#x1f981; 技术体现2.1 引入依赖2.2 编写JWT工具类2.3 编写登录方法2.4 编写JWT拦截器验证令牌2.5 编写要配置拦截的接口三. &#x1f981; 话题终结一. &#x1f981; 话题引入 在做项目过程中&#xff0c;我…

【halcon】为啥匹配到ROI外面去了?

背景 匹配到ROI外面去了 中心恰好在roi有效区域内&#xff01;&#xff08;粉色是ROI区域&#xff09; 网上查到的资料&#xff01; PaintRegion改变外部环境 //HOperatorSet.ReduceDomain(image, ho_ProductRegionAll, out imgReduced); //替换为&#xff1a; HObject all…

Web前端 HTML、CSS

HTML与CSSHTML、CSS思维导图一、HTML1.1、HTML基础文本标签1.2、图片、音频、视频标签1.3、超链接、表格标签1.4、布局1.5、表单标签1.6、表单项标签综合使用1.7、HTML小结二、CSS&#xff08;简介&#xff09;2.1、引入方式2.2、选择器2.3、CSS属性Web前端开发总览 Html&…

Linux基础操作 常用命令 Centos

Linux 1.Linux的引言 Linux是一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。伴随着互联网的发展&#xff0c;Linux得到了来自全世界软件爱好者、组织、公司的支持。它除了在服务器操作系统方面保持…

面试题-学习网络协议必备:七层模型与协议之间的映射关系

一、概念 OSI七层模型是计算机网络中的一种标准化分类和描述方式&#xff0c;它将网络协议划分为不同的层次&#xff0c;每个层次负责不同的功能。这种模型被广泛应用于网络设计、开发和维护&#xff0c;以便于不同系统之间的互操作性和相互通信。 二、各层介绍 第一层&#x…

vue项目代理配置大全

1.vite &#xff08;vue3-admin-element-template-master&#xff09; server: {host: 0.0.0.0, //服务器ip地址 port: 5566, //本地端口fs: {strict: false, // 支持引用除入口目录的文件},open: true, // 是否自动在浏览器打开proxy: {/pcapi: {target: https:....../pcapi…

老板想要可视化大屏?零代码开发3D可视化大屏,只要10分钟

上周末和供应链管理的朋友一起喝茶&#xff0c;我吐槽着我做报表的繁琐&#xff0c; 他用很疑惑的眼神看着我说&#xff1a;这事不是在模板上改改数据就行了吗&#xff1f;我连忙逼他给我分享了这个香饽饽。 回到家&#xff0c;我直接开始研究起了可视化大屏&#xff0c;后悔自…

Android告别Shape.xml

天下苦shape.xml久已&#xff0c;特别是遇上不靠谱的UI&#xff0c;圆角背景色边框&#xff0c;三个属性就能给你折腾出来几百种组合&#xff0c;每个组合都要写对应的shape.xml&#xff0c;太折腾人了&#xff01; 展示 效果图 代码 /*** 设置shape*/ BindingAdapter(// 圆角…

44学习自动化运维工具 Chef 的基本用法,包括厨师编写、节点管理

Chef是一种自动化运维工具&#xff0c;它允许您定义基础设施的状态&#xff0c;并根据需要管理这些状态。在这里&#xff0c;我们将学习Chef的基本用法&#xff0c;包括如何编写和管理Cookbook和Node。 安装Chef 在使用Chef之前&#xff0c;您需要在管理节点和目标节点上安装…
最新文章