go 语言的宕机恢复(recover)
go 语言中的三种报错机制
第一种,也就是常说的 error 类型错误,不需要 recover 拯救,处理方式自己决定
第二种,panic 和 recover 是紧密集合的,有点类似 try catch,recover 能捕获到 panic
第三种,一些 Go 语言系统级别的错误,比如发生死锁,数据竞争,这种错误程序会立刻报错,无法 recover
recove 的作用
在 go 语言中,错误一般会由 error 触发,但是如果比较严重的错误(通常是没有恰当处理的 error,也可是手动触发) 会造成 panic 。 一旦主程序 panic ,会导致整个程序挂掉。如果这个错误不是那么严重,我们希望程序可以继续往下执行,而不是整个程序挂掉。
- 用
recover函数,对panic错误进行拦截,避免上传给主函数,进而避免整个程序挂掉。 - 可以在程序崩溃前,做一些操作,举个例子,当 web 服务器遇到不可预料的严重问题时,在崩溃前应该将所有的连接关闭,如果不做任何处理,会使得客户端一直处于等待状态。
下面例子
如果给 out 函数传入两个相同的形参,就会引发 panic。
如果没有 recover 拦截,fmt.Print 这行是执行不到的。
func main() {
Out(1, 1)
fmt.Println("*******此行函数依然能继续执行******")
}
func Out(numb1, numb2 int) bool {
defer func() {
if r := recover(); r != nil { # 在此处对panic进行拦截,不会将错误继续上报上去。
fmt.Println("异常已扑捉,避免继续往上层传递")
}
}()
if numb1 == numb2 {
panic("两个数不能相等")
}
return numb1 > numb2
}
知识点
- recover 仅在延迟函数
defer中有效 - 因为
Go语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,recover 的宕机恢复机制就对应其他语言中的 try/catch 机制。 - 谨记一点
recover只能恢复本协程的panic。
注意:即使是子协程内引发的 panic 依然会导致主程序的挂掉,如下面的例子
func main() {
go OutOne()
go OutTwo()
time.Sleep(time.Minute)
}
func OutOne() {
panic("错误")
}
func OutTwo() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Print("****此处继续执行***")
}
}

进阶
那么上面情况该怎么解决?
其实就是在发生 panic 的协程里面,用 recover 进行拦截。让它传不到主函数。
func main() {
go OutOne()
go OutTwo()
time.Sleep(time.Minute)
}
func OutOne() {
defer func() {
if r := recover(); r != nil {
fmt.Println("OutOne 的报错已经别扑捉", r)
}
}()
panic("错误")
}
func OutTwo() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Println("****此处继续执行***")
}
}
当panic、defer和子函数混合使用时的执行顺序
func f() {
fmt.Println("打开文件b")
defer func() {
fmt.Println("关闭文件b")
}()
panic("文件b读取异常")
}
func main() {
fmt.Println("打开文件a")
defer func() { fmt.Println("关闭文件a") }()
f()
fmt.Println("文件正常执行")
}
# 输出
打开文件a
打开文件b
关闭文件b
关闭文件a
panic: 文件b读取异常
- 记住这个例题,当
go语言发生panic时,会首先执行已经“进栈”的defer函数,最后然后在报出panic的错误。传给上层的函数。 - 当子函数发生
panic的时候,函数依然是会先执行已经“进栈”的defer函数,而爆出panic。
defer
在 go的代码中,defer 有点类似于压栈操作,只有被执行到了,才会入栈(延迟执行),但是实际上,defer函数是编译过程中,通过调整代码顺序实现
错误日志如何查看
package main
import "log"
func main() {
err := funcA()
if err != nil {
log.Println("日志输出错误")
}
}
func funcA() error {
panic("错误")
}
输出:

- 观察错误输出顺序,错误就是一个入栈的过程,会从底到上的打印,直到遇到
recover。 - 日志能不能输出这条错误,要看这条日志能不能走到。
参考文献
go 语言的宕机恢复(recover)的更多相关文章
- Vertica集群单节点宕机恢复方法
Vertica集群单节点宕机恢复方法 第一种方法: 直接通过admintools -> 5 Restart Vertica on Host 第二种方法: 若第一种方法无法恢复,则清空宕机节点的c ...
- mysql group replication 主节点宕机恢复
一.mysql group replication 生来就要面对两个问题: 一.主节点宕机如何恢复. 二.多数节点离线的情况下.余下节点如何继续承载业务. 在这里我们只讨论第一个问题.也就是说当主结点 ...
- Go语言 异常panic和恢复recover用法
Go语言 异常panic和恢复recover用法 背景:Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在 ...
- 存在单点故障的namenode宕机恢复测试
前提:如果namenode没有做HA,那么至少应该启用secondarynamenode,以便namenode宕机之后手动恢复数据 实验环境:3个节点(cenos 6.10) 测试前数据: 1.为了确 ...
- HBase–RegionServer宕机恢复原理
Region Server宕机总述 HBase一个很大的特色是扩展性极其友好,可以通过简单地加机器实现集群规模的线性扩展,而且机器的配置并不需要太好,通过大量廉价机器代替价格昂贵的高性能机器.但也正因 ...
- drbd虚拟机宕机恢复方法
问题现象 云南计算节点YN-ec-compute-19因系统盘损坏宕机且操作系统无法恢复,其上本地虚拟机无法疏散且无法迁移 拟采用drbd备份的数据对compute19上的虚拟机进行恢复 恢复方法 1 ...
- CDH集群主节点宕机恢复
1 情况概述 公司的开发集群在周末莫名其妙的主节点Hadoop-1的启动固态盘挂了,由于CM.HDFS的NameNode.HBase的Master都安装在Hadoop-1,导致了整个集群都 ...
- MySQL - 高可用性:少宕机即高可用?
我们之前了解了复制.扩展性,接下来就让我们来了解可用性.归根到底,高可用性就意味着 "更少的宕机时间". 老规矩,讨论一个名词,首先要给它下个定义,那么什么是可用性? 1 什么是可 ...
- MySQL 系列(四) 主从复制、读写分离、模拟宕机、备份恢复方案生产环境实战
本章内容: 主从复制 简介原理 备份主库及恢复从库,配置从库生效 读写分离 如果主宕机了,怎么办? 双主的情况 MySQL 备份及恢复方案 备份单个及多个数据库 mysqldump 的常用参数 如何增 ...
- HBase RegionServer宕机处理恢复
本文分析RegionServer宕机后这个region server上的region是如何在其他region server上恢复的. region server宕机后发生了什么 HMaster有一 ...
随机推荐
- KMP 算法(Knuth–Morris–Pratt algorithm)的基本思想
KMP 算法(Knuth–Morris–Pratt algorithm)的基本思想 阅读本文之前,您最好能够了解 KMP 算法解决的是什么问题,最好能用暴力方式(Brute Force)解决一下该问题 ...
- JZOJ 5343. 【NOIP2017模拟9.3A组】健美猫
题面 其中 \(1 \leq n \leq 2 \times 10^6\) 分析 考虑每次移动,发现负数对答案贡献少 \(1\),非负数多 \(1\) 每次移动都加了 \(1\) 负数变非负数关键点在 ...
- Python常见面试题006 类方法、类实例方法、静态方法有何区别?
006. Python中类方法.类实例方法.静态方法有何区别? 全部放一个里面篇幅过大了,就拆分成1个个发布 示例代码 class Human: def __init__(self, name): s ...
- 通过反射机制简化 JDBC ResultSet 实体类的注入
提出问题 查询完某个表之后,一般都是把结果的每一个字段注入到一个实体类中.比如,数据库 users 表,查询出来的结果注入到 User 实体类中. 通过 while 遍历 ResultSet,把字段对 ...
- 基于JavaScript的OpenGL 01 之Hello Triangle
1. 引言 本文基于JavaScript语言,描述OpenGL(即,WebGL)的绘制流程,这里描述的是OpenGL的核心模式(Core-profile) 笔者这里不过多描述每个名词.函数和细节,更详 ...
- django我学习的第一个web框架
第一个APP----------联通后台管理系统 第二个APP----------baby商场
- LeetCode-593 有效的正方形
来源:力扣(LeetCode)链接:https://leetcode.cn/problems/valid-square 题目描述 给定2D空间中四个点的坐标 p1, p2, p3 和 p4,如果这四个 ...
- golang输出字母a-z
方法1: func main() { for i := 0; i < 10; i++ { ss := 'a' + i fmt.Printf("==%c", ss) } }
- TP-Link路由器后台密码爆破
title: TP-Link路由器后台密码爆破 author: 杨晓东 permalink: TP-Link路由器后台密码爆破 date: 2021-10-02 11:27:04 categories ...
- vue3 loading 等待效果
一.自定义组件 loading.vue <template> <div class="loading" v-show="msg.show"&g ...