Go nil 的 4 种分裂人格:一个 nil 引发的 2 小时线上排查
有一次线上接口返回了一个很诡异的 null。
调用方说:你们这个错误字段为什么一直有值?
我看代码,第一反应是不可能。分支里明明写着:
| |
这事最后拖了将近两个小时。
日志没有 panic,链路没有超时,数 …
goroutine 泄漏最讨厌的地方,不是它会炸,而是它不炸。
它先是悄悄多几个,再多几十个,最后把内存、延迟、CPU 一起拖下水。你回头看日志,发现代码没报错;你再看监控,发现曲线只是在往上爬。
很多人看到这种情况,第一反应是:是不是忘了 …
goroutine 从 200 慢慢涨到 2 万,线上服务还没挂,但你知道它不对劲。
监控图上那条线不陡,甚至有点温和。它不像事故,更像一个迟早会来的事故。
这时候很多人的第一反应是:把 channel buffer 调大一点。 …
代码评审里经常出现这种争论:一个 goroutine 写完结果,close(done);另一个 goroutine 等 <-done 再读结果。有人看着觉得多此一举:这不就是通知一下吗?换成一个 bool,或者 sleep 一小会儿, …
很多人写 select,脑子里都有一个抽奖箱。
几个 case 往里一扔,runtime 随机摸一个。哪个 channel 先 ready,哪个就中;都没 ready,就看 default;没有 default,就等。
这个理解不能说全错, …
线上最烦的 channel 问题,往往不是“发不出去”。
而是你以为自己在等一个值,结果等来的是零值;你以为 close(ch) 只是关门,结果它把一批阻塞的 goroutine 全部叫醒;你以为 nil channel 和 closed …
goroutine dump 里刷出一排 [chan send],你知道它卡住了。
但更麻烦的问题是:它到底卡在哪?
是 channel 本身是 nil?是已经有人在等接收,只差一次交付?是 buffer 满了?还是它已经被 runtime …
上一篇讲到最后,其实只把问题说完了一半。
如果你面对的是任务、结果、信号和访问权交接,channel 确实比 mutex 更顺手。它能把 goroutine 之间的关系写出来,让代码不只是在“保护状态”,而是在表达一段通信。
但很多 …
上一篇说到一个很典型的场景:为了写得“更 Go”,有人把一个普通 cache 写成了小型 RPC。
锁确实没了。
但你多了 request、reply channel、owner goroutine、退出顺序、取消处理。读一个 map,本来 …
有些 Go 代码,一看就知道作者很努力。
为了让一个普通 cache 看起来“更 Go”,他把 sync.RWMutex 拿掉了,换成一个专门的 goroutine 来“拥有”这份状态。每次 Get,调用方先构造 request,发进 …
goroutine 数量从 200 慢慢涨到 2 万。
监控图上那条线,不陡,但一直在爬。就像水龙头没拧紧——不喷,但也不会停。
你的第一反应是什么?
加大 buffer。
make(chan int, 100) 改成 make(chan …