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

Go 语言生产服务故障案例精析

        大多数 Go 开发者都停留在简单的增删改查层面,对 Go 语言本身掌握程度不够,对常用依赖或者开源组件掌握不够,在开发项目过程中总会不经意间引入一些千奇百怪的问题,并且在遇到线上问题时往往束手无策。下面列举一些线上问题以及相应的解决思路,希望大家能从这些问题中吸取经验,总结出一套属于自己的解决问题的方法论。

1. 两种情况导致 502 状态码的情况

        服务端开发最常见的问题可能就是 HTTP 状态码异常了,其中 502 状态码最常见并且最复杂。

1.1.1 panic 异常

        我们可以将 Go 服务中的 panic 异常分为两种:一种是请求级别的 panic 异常,即 Go 服务在处理 HTTP 请求时发生了 panic 异常;与之相对的,我们称之为服务级别的 panic 异常。需要说明的是,两种类型的 panic 异常都会导致 502 状态码。

        1.1.1.1 panic 异常导致 502 状态码

        下面先来介绍服务级别的 panic 异常是如何导致 502 状态码的。服务级别的 panic 异常会导致 Go 服务异常退出,这时候网关侧必然会返回大量 502 状态码,同时网关侧会出现大量的错误日志,如下所示:

connect () failed (111: Connection refused) while connecting to upstream

        从上面的日志可知,网关发起 HTTP 请求需要先建立 TCP 连接,但是 Go 服务已经退出了,即没有进程在监听目标端口了,TCP 连接自然也就无法建立了,于是网关便向客户端返回了 502 状态码。这种情况还是比较容易处理的,只需要使用函数 recover 捕获异常就能避免 Go 服务的退出,参考下面的代码:

defer func(){if err := recover(); err != nil {buf = buf[:runtime.Stack(buf,false)]log.Fatalf("go panic err:%v \n stack:%s",err,buf)}
}()

        接下来讲解请求级别的 panic 异常是如何导致 502 状态码的。我们先写一个简单的程序验证一下,代码如下所示:

package mainfunc main() {server := &http.Server{Addr: "0.0.0.0:8080",}http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {panic("panic test")w.Write([]byte(r.URL.Path + ">ping response"))})_ = server.ListenAndServe()
}

        在上面的代码中,我们在 HTTP 请求处理函数中抛出了 panic 异常。另外需要再次强调,本例中的访问链路是客户端--网关Nginx--Go 服务。编译上面的程序,并通过 curl 命令发起 HTTP 请求,结果如下所示:

[root@localhost ~]#curl --request POST 'http://127.0.0.1/ping' -v
<HTTP/1.1 502 Bad Gateway

        由上面的结果可知,客户端确实收到了 502 状态码,并且多次执行 crul 命令的结果都是一样的。另外,如果你这时候看控制台,你会发现 Go 服务并没有退出,但是控制台输出了以下日志:

2024/08/28 09:59:20 http: panic serving xxxx:56850: panic test
goroutine 6 [running]:
net/http.(*conn).serve.func1()

        参考上面的输出结果,Go 服务没有退出,说明一定有函数 recover 捕获了异常,并输出了协程调用栈,可是既然都捕获 panic 异常了,为什么网关返回的还是 502 状态码呢?我们可以查看网关的错误日志,如下所示:

[error] upstream prematurely closed connection while reading response header from upstream

         参考上面的错误日志,网关 Nginx 在等待上游 Go 服务返回 HTTP 响应时,上游 Go 服务过早地关闭了 TCP 连接。为什么呢? 估计是 Go 服务在处理 HTTP 请求时, 使用函数 recover 捕获了异常,并关闭了 TCP 连接。是这样吗?我们简单看一下 Go 语言底层处理 HTTP 请求的逻辑,如下所示:

func (c *conn) serve(ctx context.Context){defer func(){if err := recover();err != nil && ErrAbortHandler {......c.server.logf("http:panic serving %v:%v\n%s",c.remoteAddr,err,buf)c.close()}}()
}

        在上面的代码中,针对 TCP 连接,Go 语言都会创建新的协程来处理从该连接接收到的 HTTP 请求,并且使用了函数 recover 来捕获 panic 异常。可以看到,当发生了 panic 异常之后,Go 语言一方面输出了协程调用栈来帮助开发者排查问题,另一方面直接关闭了 TCP 连接,这也是网关 Nginx 返回 502 状态码的根本原因。

        最后总结下,请求级别的 panic 异常同样会导致 502 状态码。幸运的是,这种情况的 502 非常容易排查:一来我们可以在上游 Go 服务标准输出查看到错误日志;

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 黑马JavaWeb开发笔记09——ElementUI代码引入教程、Element常用组件使用(Table, Pagination, Dialog, Form)
  • python爬虫源码:selenium+browsermobproxy实现浏览器请求抓取
  • 7- 排序算法
  • 如何本地搭建Whisper语音识别模型
  • netty之ChannelOption
  • 数据库入门: 从 0 到 1 理解数据管理
  • Visual Basic:企业级应用开发的稳健之选
  • Dubbo ZooKeeper Spring Boot整合
  • Java | Leetcode Java题解之第381题O(1)时间插入、删除和获取随机元素-允许重复
  • Java-InputStream、MultipartFile和File相互转换工具类
  • Day50 | 108.冗余连接 109.冗余连接II
  • IO进程day04(进程)
  • Linux之shell脚本的if分支
  • AI搜索“懒人神器”,如何向谷歌和百度发起挑战?
  • 大数据-106 Spark Graph X 计算学习 案例:1图的基本计算、2连通图算法、3寻找相同的用户
  • 【comparator, comparable】小总结
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 0x05 Python数据分析,Anaconda八斩刀
  • CSS3 变换
  • dva中组件的懒加载
  • Idea+maven+scala构建包并在spark on yarn 运行
  • JAVA 学习IO流
  • Java编程基础24——递归练习
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Material Design
  • MySQL用户中的%到底包不包括localhost?
  • nginx 负载服务器优化
  • nodejs调试方法
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • session共享问题解决方案
  • vue 配置sass、scss全局变量
  • vue:响应原理
  • windows下使用nginx调试简介
  • 浮动相关
  • 跨域
  • 前端攻城师
  • 悄悄地说一个bug
  • 世界上最简单的无等待算法(getAndIncrement)
  • 学习JavaScript数据结构与算法 — 树
  • 与 ConTeXt MkIV 官方文档的接驳
  • Hibernate主键生成策略及选择
  • 从如何停掉 Promise 链说起
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • 组复制官方翻译九、Group Replication Technical Details
  • ​14:00面试,14:06就出来了,问的问题有点变态。。。
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • !$boo在php中什么意思,php前戏
  • # 安徽锐锋科技IDMS系统简介
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (2)STL算法之元素计数