当前位置: 首页 > news >正文

应对过载- go-zero源码阅读

运维一个可靠的系统 一个根本要就是能够优雅的处理过载的情况。

CPU资源的不足导致的负载上升是我们工作中最常见的,如果CPU资源不足以应对请求负载,一般来说所有的请求都会变慢,CPU负载过高会造成一系列的副作用,主要包括以下几项:

  • 正在处理的(in-flight) 的请求数量上升

  • 服务器逐渐将请求队列填满,意味着延迟上升,同时队列会用更多的内存

  • 线程卡住,无法处理请求

  • cpu死锁或者请求卡主

  • rpc服务调用超时

  • cpu的缓存效率下降

应对服务器过载几种常见的策略:

  • 服务降级
    返回精度降低的回复,或者省略回复中需要经过大量计算的数据;
    例如 :平时整个文档中进行搜索,在过载的情况下只搜索文档中的一小部分
  • 服务端拒绝请求
  • 客户端主动拒绝请求

一  资源利用率信号

在多数情况下,资源利用率仅仅是只当前cpu的消耗程度,在某些情况下也会考虑内存的使用情况。

当某个请求突然大批短时请求时,会导致负载的短时急剧上升。可以使用指数型衰变算法(exponential dacay)来平滑这个值。

go-zero案例:

go-zero种cpu的统计代码位于core/stat/internal中,通过获取linux系统的中/proc/stat提供的就是系统的CPU等的任务统计信息来计算cpu的使用率。
cpu统计代码会 没间隔250ms获取一次cpu的使用率,并且每一分钟打印一次cpu的使用率。


const (
	// 250ms and 0.95 as beta will count the average cpu load for past 5 seconds
	cpuRefreshInterval = time.Millisecond * 250
	allRefreshInterval = time.Minute
	// moving average beta hyperparameter
	beta = 0.95
)

func init() {
	go func() {
		cpuTicker := time.NewTicker(cpuRefreshInterval)
		defer cpuTicker.Stop()
		allTicker := time.NewTicker(allRefreshInterval)
		defer allTicker.Stop()

		for {
			select {
			case <-cpuTicker.C:
				threading.RunSafe(func() {
					curUsage := internal.RefreshCpu()
					prevUsage := atomic.LoadInt64(&cpuUsage)
					// cpu = cpuᵗ⁻¹ * beta + cpuᵗ * (1 - beta)
                    //指数衰变算法 
					usage := int64(float64(prevUsage)*beta + float64(curUsage)*(1-beta))
					atomic.StoreInt64(&cpuUsage, usage)
				})
			case <-allTicker.C:
				printUsage()
			}
		}
	}()
}

二 服务端过载保护


go-zero中内置的过载保护代码位于/core/load/adaptiveshedder.go

sholdDrop用来检测是否符合触发过载保护条件,代码入下

func (as *adaptiveShedder) shouldDrop() bool {
	if as.systemOverloaded() || as.stillHot() {
		if as.highThru() {
			flying := atomic.LoadInt64(&as.flying)
			as.avgFlyingLock.Lock()
			avgFlying := as.avgFlying
			as.avgFlyingLock.Unlock()
			msg := fmt.Sprintf(
				"dropreq, cpu: %d, maxPass: %d, minRt: %.2f, hot: %t, flying: %d, avgFlying: %.2f",
				stat.CpuUsage(), as.maxPass(), as.minRt(), as.stillHot(), flying, avgFlying)
			logx.Error(msg)
			stat.Report(msg)
			return true
		}
	}

	return false
}

as.systemOverloaded() 方法判断当前cpu是否达到阈值,默认90%。
as.stillHot() 判断是否在冷却期。
as.highThru()判断仍是高吞吐。
如果触发过载保护,会返回过载错误信息,并记录错误日志。

相关文章:

  • Python 的“self“参数是什么?
  • 模拟前端ADC芯片LH001-91,用于开发心电、脑电医疗设备
  • CAPL 封装了的SeedKey解锁函数,高复用性
  • 异常数据处理——3σ原则、箱线图
  • vue3.0 + tsx 构建el-button
  • 基于JAVA的TCP网络QQ聊天工具系统
  • 【WLAN】【调试】netsh wlan常用命令使用说明
  • 教程图文详解 - 网络安全(第八章)
  • Python数据分析案例08——预测泰坦尼克号乘员的生存(机器学习全流程)
  • 计算机四级——操作系统原理常用知识点个人总结(上)
  • 【学姐面试宝典】—— 前端基础篇Ⅰ
  • c++之二叉树
  • 字符串训练赛
  • Android性能优化之【启动优化】
  • Java 集合与数据结构 · 接口 interfaces ·Collection 常用方法 · Map 常用方法
  • [Vue CLI 3] 配置解析之 css.extract
  • 【刷算法】求1+2+3+...+n
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • ➹使用webpack配置多页面应用(MPA)
  •  D - 粉碎叛乱F - 其他起义
  • GitUp, 你不可错过的秀外慧中的git工具
  • go append函数以及写入
  • httpie使用详解
  • linux安装openssl、swoole等扩展的具体步骤
  • Vue2.x学习三:事件处理生命周期钩子
  • 你对linux中grep命令知道多少?
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​ssh免密码登录设置及问题总结
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (动态规划)5. 最长回文子串 java解决
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一) springboot详细介绍
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转) Android中ViewStub组件使用
  • (转)我也是一只IT小小鸟
  • ******之网络***——物理***
  • .bat批处理(六):替换字符串中匹配的子串
  • .gitignore文件_Git:.gitignore
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .net开发引用程序集提示没有强名称的解决办法
  • .NET企业级应用架构设计系列之应用服务器
  • @angular/cli项目构建--Dynamic.Form
  • [2009][note]构成理想导体超材料的有源THz欺骗表面等离子激元开关——
  • [Android] 修改设备访问权限
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [ARC066F]Contest with Drinks Hard
  • [AutoSar NVM] 存储架构
  • [C#]OpenCvSharp结合yolov8-face实现L2CS-Net眼睛注视方向估计或者人脸朝向估计
  • [C++]Leetcode17电话号码的字母组合
  • [CF494C]Helping People
  • [codevs 2822] 爱在心中 【tarjan 算法】