纪念我的两行代码,一个让内存和CPU飙升,一个让日志无法打印
Opened this issue · 1 comments
bingoohuang commented
纪念我的两行代码,一个让内存和CPU飙升,一个让日志无法打印
让内存和CPU飙升的那行代码
if reflect.DeepEqual(&lastWarnConf, warnConf) {
}
这个比较,左边是指针,右边是非指针,肯定每次都失效,结果导致频繁刷新(1分钟一次),然后raft状态同步一次,结果就是内存和CPU(RAFT状态更新、JSON序列化)都持续上升。
然后补充了一下gin的pprof的代码,再go tool pprof -http=:8080 http://192.168.26.82:12345/debug/pprof/heap
然后看到,JSON序列化竟然占了那么多内存(65%),然后各种顺藤摸瓜,终于抓到了“罪魁祸首”。
自问,我写出那行代码的时候,我难道在“神游”😭?
让连接数爆满的那行代码(缺失的)
就是这段啦,于是我就补充了这段我的史上最长注释:
func restclient(urlAddr string) {
iox.InfoReport("invoke", urlAddr)
rsp, _ := http.Get(urlAddr)
// 这里我要写一段注释,记录一下,因为下面这行代码的缺失,花了我半天纠结的问题
// 我写这个demo,本意就是要观察,启动1000个协程并发去写日志
// 日志文件按时间和大小的去定期定大小滚动,以及定期删除老旧日志,观察是否是期望那样
// 但是,本demo,无论是本机(macOS),还是Linux,都是跑着跑着,大概五六分钟的样子,日志输出就停止了
// 对的,tail -F ~/gologdemo.log,不再更新了
// 对的,watch "ls -lht ~/gologdemo.log*"也没有更新了
// gologdemo程序也没有死,也还在
// 内心感觉很慌,恰如,前几天吕勇说的,日志打着打着,就不打了,...
// 于是我把滚动打印日志的rotate.go文件,从头到尾,从尾又到头,反复读(code review)了好几遍
// 该处理记录error地方的,都统统补充处理记录了,尽管我怀疑是哪个地方的error被黑洞swallow了
// 该处理多线程竞争的地方,也没有问题,尽管郑科研言之凿凿的说,就是多线程的线程锁导致的(7-18下午4:08企业微信)
// 现象就是:日志打着打着,就停止了,没有新的日志输出了,也没有任何错误
//(苦逼的时候就是这样子,没有告警,没有错误,外表一切正常,就是不是期望结果)
// 唯一庆幸的是,macOS和Linux,尽皆如此😭😄(哭笑不得),说明不是偶然现象
// 唯一不一样的是,在Idea的debug运行的时候,竟然久久也不会出问题(一顿中饭,一个午觉,至少一个小时吧)
//(我还想着,debug模式运行也出问题的时候,我顺便debug单步调试一下)
// 于是,我开始怀疑,是不是golog实现问题,而是logrus是否有问题,又或者别的问题
// 于是,我在linux上开着strace来跑gologdemo
// 跑着跑着,报告说,accept文件句柄超标了,哈哈哈,我眼睛一亮,终于感觉抓住它了,因为似曾相似
// accept是http server的概念,难道,go http server有问题了,查了一下,没发现啥
// 顺便看看client端吧,结果发现在死循环里,http.Get(...)一直调用,我突然想到
// 有一个body是Closeable的,需要手动关闭
// 于是,加上了下面这行代码,然后重新跑应用,欧耶,一切重回正轨,三观回正了.
httpx.CloseResponse(rsp)
}
以上两行代码,特此纪念一下。想要完全避免这些“笔误”,确实不易。但是要能掌握方法快速定位。
CharLemAznable commented
看完以后默默的加了两行response.close()
...