golang 服务中 context 超时处理的思考
文章目录
- 前言
- 起因:日志告警引发的思考
- 什么是context
- context的作用
- context超时之后
- 继续执行 or 中断
- 最后
前言
公司运行的服务代码中,随处可见各种各样的日志信息,其中大多数是用来记录各种异常的日志,一方面,当出现问题时,通过日志我们可以快速的定位引发问题的原因;另外我们可以通过日志平台,对一些错误级别比较高的日志进行监控,从而能够快速响应系统可能会出现的问题。
起因:日志告警引发的思考
虽然日志告警很有用,但如果告警次数过于频繁,反而会降低开发人员对于系统异常的敏感度,使得告警变得毫无意义。因此,我们需要对告警进行治理。最近,由于一次治理线上频发的超时告警,使得笔者开始思考起context deadline exceed异常的问题。
什么是context
在Go语言中,Context是一个非常重要的概念,它存在于一个完整的业务生命周期内,Context类型是一个接口类型,它定义了四个方法:Deadline()、Done()、Err()和Value()。其中,Deadline()方法返回context的截止日期,Done()方法返回一个只读的channel,当Context被取消或超时时,该channel会被关闭,Err()方法返回Context被取消的原因,Value()方法返回Context中与key相关联的值。
context的作用
在实际应用中,我们可以使用Context包来传递请求的元数据,例如请求ID、超时信息等等。此外,我们还可以使用context包来控制goroutine的生命周期(最常见的),例如在HTTP请求处理程序中,我们可以使用context包来取消正在处理的请求。
可以说,我们的服务里,随处可见携带context参数的方法。
context超时之后
先来看一段例子
package mainimport ("context""fmt""time"
)func timeConsuming(ctx context.Context, costTime int) {ctx.Done()for i := 1; i <= costTime; i++ {// 模拟一些耗时操作time.Sleep(1 * time.Second)fmt.Printf("协程正在运行第%v次...\n", i)}
}func main() {// 创建一个父级 context,设置超时时间为 5 秒钟parentCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)defer cancel()// 创建一个子级 context,用于控制协程childCtx, childCancel := context.WithCancel(parentCtx)defer childCancel()costTime := 5 // 模拟耗时 5 秒钟// 启动一个协程go func(ctx context.Context) {for {select {case <-ctx.Done():// 如果收到取消信号,退出协程fmt.Println("协程退出")returncase <-time.After(15 * time.Second):fmt.Println("协程超时")default:timeConsuming(childCtx, costTime)}}}(childCtx)// 等待 3 秒钟,然后取消子级 contexttime.Sleep(3 * time.Second)fmt.Println("取消协程")childCancel()// 继续等待 3 秒钟,模拟主协程的一些其他操作time.Sleep(3 * time.Second)fmt.Println("主协程退出")
}
上面代码的执行结果如下
协程正在运行第1次...
协程正在运行第2次...
取消协程
协程正在运行第3次...
协程正在运行第4次...
协程正在运行第5次...
协程退出
主协程退出
虽然说Context可以用来管理goroutine,但是可以看到,Context超时之后,goroutine仍然在执行完成之后才会退出,Context无法真正做到强制杀死goroutine
回到文章最开始提到的线上超时告警频发的问题,经过排查我们发现,一波超时告警的出现实际上只是几条请求引起的(都是同一个trace_id)。究其原因,是我们下游的服务在单次业务请求中,会与很多第三方接口发生交互(在本篇文章的case是并发调用redis),而在业务执行到并发调用redis之前,业务逻辑就已经发生了超时。
超时后,上游调用端不再继续等待响应,直接返回了超时异常。
前面已经提到过,goroutine是无法强制杀死的,此时goroutine携带着已经超时的context依旧在执行着业务逻辑,在执行到并发调用redis时,由于context已经超时,调用无一例外的全部抛出超时错误(实际上并未真正发生调用redis,redis客户端代码在调用前判断了context的状态),
从而导致个位数的超时请求却引起了大量日志的超时告警。
...
//If Done is not yet closed, Err returns nil.
// If Done is closed, Err returns a non-nil error explaining why:
// Canceled if the context was canceled
// or DeadlineExceeded if the context's deadline passed.
// After Err returns a non-nil error, successive calls to Err return the same error.
if ctx.Err() != nil { // 这里抛出了context deadline exceeded 异常return nil, ctx.Err()
}
...
继续执行 or 中断
知道了问题,其实处理起来就比较容易了,我们将context的状态的判断改写到了合适的位置(在一些耗时的节点之间判断了context的状态,如果判断超时,则直接结束后续的业务流程)
日志告警清净了!
但是,这样的处理方式具有普适性吗?可以思考一下,在某些超时的情况中,即便上游已经返回了超时异常,我们仍然希望下游能够将这次业务完整的执行完。
举一个例子,下游在执行完返回之前,会将本次执行的结果进行缓存。而上游在调用下游之前,也会去取缓存,取到了就直接返回(假设上下游服务共用一套缓存集群)。假如某些请求耗时比较久,而且我们在判断请求超时之后直接中断下游任务的执行,那么,缓存将永远不会生成,上游后续的调用依旧会超时。这种情况下,即便是超时了,我们也希望下游任务能够完整执行,并生成缓存,后续上游就可以直接拿到业务结果返回,避免大量耗时的调用。
最后
本篇描述的本身是一个极为常见的问题及处理方案。但是在平时处理问题的过程中,如果勤加思考,仍然会有所收获和提升。
提个题外话,现在是2023年5月21日,今年(或许从去年开始)的形势确实不太好。小伙伴们或多或少能够感受到就业形势的严峻(有前同事因各种各样的原因10个月没有找到新工作)。越是这样的情况下,越是要好好打磨,提升自己,以应对未来的艰难险阻;
共勉之~

相关文章:
golang 服务中 context 超时处理的思考
文章目录 前言起因:日志告警引发的思考什么是contextcontext的作用context超时之后继续执行 or 中断 最后 前言 公司运行的服务代码中,随处可见各种各样的日志信息,其中大多数是用来记录各种异常的日志,一方面,当出现…...
遇到Uniapp配置meta不生效怎么解决
Uniapp是一种基于 Vue.js 的跨平台应用开发框架,其开发简单、易上手,可以快速构建出 iOS、Android 和 H5 页面,成为现在移动应用开发的重要工具之一。然而,跨平台应用的开发也带来了一些问题,比如本文即是解决 uniapp …...
C语言基础知识:位与位字段
目录 位与字节 位 比特 字节 对齐特性 位字段 位与字节 位 二进制数系统中,每个0或1就是一个位(bit),位是数据存储的最小单位。其中8 bit就称为一个字节(Byte)。计算机中的CPU位数指的是CPU一次能处理的最大位数࿰…...
新版android studio gradle插件7.4.2.pom一直无法下载问题
android studio同步时候出现org.gradle.api.plugins.UnknownPluginException,Plugin [id: com.android.application, version: 7.4.2] was not found in any of the following sources: pom插件一直无法下载,搞了好几天,简直想砸电脑&#x…...
Shell——变量和引用
1.总结变量的类型及含义? 2.实现课堂案例计算长方形面积?(6种方式) 3.定义变量urlhttps://blog.csdn.net/weixin_45029822/article/details/103568815 (通过多种方法实现) 1)截取网站访问的协…...
实际开发中一些实用的JS数据处理方法
写在开头 JavaScript 是一种脚本语言,最初是为了网页提供交互式前端功能而设计的,而现在,通过 Node.js,JavaScript 还可以用于编写服务器端代码。 JavaScript 具有动态性、基于原型的面向对象特性、弱类型、多范式、支持闭包执行…...
10:00进去,10:05就出来了,这问的也太变态了···
从外包出来,没想到死在另一家厂子了。 自从加入这家公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到5月一纸通知,所有人不许加班,薪资直降30%,顿时有吃不起饭的赶脚。 好在有个兄弟内推…...
GPT时代,最令人担心的其实是“塔斯马尼亚效应”
目录 教育到底教什么? 过度依赖GPT可能导致文明退化 GPT可以帮助人类破解“学海无涯极限”悖论 春季学期伊始,全球各地的老师们如临大敌,因为学生们带着ChatGPT杀过来了。Study.com的调研显示,每10个学生中就有超过9个知道Chat…...
基于容器技术和服务发现的全新大数据平台弹性伸缩方法
随着科技的不断发展,各个行业都在不断地数字化和智能化。在这个过程中,大数据技术成为了许多行业的重要支撑。而随着大数据技术的普及,行业分类和设备装置的不断更新换代,弹性伸缩成为了一个不可避免的问题。本文将介绍基于服务发…...
php8 match
刚从 php7 升级到 php8 时 我在使用 switch 语句,结果出现了一个提示: "switch statement can be converted to match expression" 翻译过来就是: switch语句可以转换为match表达式 我当时在想,match 应该是php8 的…...
ADS-B接收机Radarcape
1.设备简介 Radarcape是一款便携、高性能、功能强大的ADS-B地面接收机。Radarcape的设备清单包含:ADS-B接收机主机,专业级ADS-B天线,GPS天线,电源线,网线。 2. 功能特点 Radarcape可以通过网口输出飞机的原始数据D…...
软件测评师2012年下半年考试真题<更新中。。。>
1.2012 年下半年全国计算机技术与软件专业技术资格(水平)考试日期是 11月4号。 2.在 CPU 中,控制器 不仅要保证指令的正确执行,还要能够处理异常事件。 3.循环冗余校验码(CRC) 利用生成多项式进行编码。设数据位为 k 位…...
ChatGPT 使用 拓展资料:开始构建你的优质Prompt
ChatGPT 使用 拓展资料:开始构建你的优质Prompt...
Hystrix原理
一.概述 在软件架构领域,容错特指容忍并防范局部错误,不让这种局部错误不断扩大。我们在识别风险领域,风险可以分为已知风险和未知风险,容错直接应对的就是已知风险,这就要求针对的场景是:系统之间调用延时…...
内网外网分离模式下,通过网关转发,来部署前后端分离的系统
前言 最近为某银行系统部署了一套商城系统,网络环境比较特别,思路记录下,其中商场系统使用前后端分离模式部署。 该银行网络环境: 外网服务器:外网可以访问到它,不能访问外网。 网关服务器:跟…...
基于 Amazon API Gatewy 的跨账号跨网络的私有 API 集成
一、背景介绍 本文主要讨论的问题是在使用 Amazon API Gateway,通过 Private Integration、Private API 来完成私有网络环境下的跨账号或跨网络的 API 集成。API 管理平台会被设计在单独的账号中(亚马逊云科技提供的是多租户的环境),因为客观上不同业务…...
SSH远程连接时报错kex_exchange_identification: Connection closed by remote host
简介 在SSH服务器上进行远程内容时,会经常出现kex_exchange_identification: Connection closed by remote host内容,主要是由于远程计算机登录节点的数量限制问题。 解释 在 SSH 服务器上,最大并发登录会话数是由 ‘MaxSessions’ 参数来…...
一、CNNs网络架构-基础网络架构
目录 1.LeNet 2.AlexNet 2.1 激活函数:ReLU 2.2 随机失活:Droupout 2.3 数据扩充:Data augmentation 2.4 局部响应归一化:LRN 2.5 多GPU训练 2.6 论文 3.ZFNet 3.1 网络架构 3.2 反卷积 3.3 卷积可视化 3.4 ZFNet改…...
[开发|C++] C++的基本运算符说明笔记
基本运算符说明 C是一种功能强大的编程语言,提供了多种运算符来执行各种基本操作。下面是一些常见的C基本运算符及其说明: 算术运算符: :加法运算符,用于执行两个操作数的相加操作。 -:减法运算符…...
抖音定位功能的作用
随着智能手机和社交网络的普及,人们日常生活中对于位置信息的需求也越来越高。而抖音作为一款以短视频为主的社交应用,其定位技术也备受关注。本文将就抖音的定位功能进行探究,介绍抖音如何获取、处理和利用用户的位置信息,并探讨…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
