背景
- 某次晚上上线后,某个k8s服务出现频繁重启的现象,看了阿里云k8s的监控,是由于对应服务的健康检查失败导致k8s不断重新创建pod,然后重启。
- 看了下splunk里面的错误日志,由于splunk里面的日志太多,几个同事花了一些时间也没定位到是啥原因,加上太晚就决定然运维对Pod进行了扩容,这样可以减少重启的次数,第二天到公司再排查。
- 第二天到公司重新review了下代码,没发现明显问题,后来google了下,可能是fatal error 导致进程退出,进而导致健康检查失败,于是我在main函数里对错误日志做了重定向,代码如下
// 重定向错误
// 调用示例 在main函数中加入 bc_error.RedirectFatal("/opt/go/logs/app_fatal.log")
func RedirectFatal(logFileName string) {
if logFileName == "" {
logFileName = fmt.Sprintf("/opt/go/logs/%d_fatal.log", php.Time())
}
logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
PanicLogger.Errorf("服务启动出错:打开异常日志文件%s失败 err:%+v", logFileName, err)
} else if logFile != nil {
PanicLogger.Warnf("服务启动成功:打开异常日志文件%s 成功", logFileName)
// 将进程标准出错重定向至文件,进程崩溃时运行时将向该文件记录协程调用栈信息
syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
} else {
PanicLogger.Warnf("服务启动出错:打开异常日志文件%s 发生不明错误", logFileName)
}
}
-
然后上线了几个pod,终于捕获到了完整的stack fatal error , 对照代码看了是并发写map 导致了fatal error , 这种是不能revovey的,后来在map的地方加了sync.RWMutex 解决了这个问题,上线后没有重启了
-
总结不能被recover的
- 数据竞争(比如:对map进行并发读写),可以通过golang的编译标记race对代码进行检测是否存在数据竞争(比如:并发读写map)
- 内存不足
- 死锁
网友评论