查看原文
其他

Go channel死锁问题出坑记

Go开发大全 2021-07-20

(给Go开发大全加星标)

来源:软工
https://zhuanlan.zhihu.com/p/31395716

【导读】golang服务如何防止,检测,排查goroutine过多导致的故障,如死锁。

聪明的你,用golang写后端服务,各种使用channel和goroutine,把java要用线程池干的事儿用携程都搞掂了。服务线下运行一切正常,压测,单元测,联调统统通过。你露出得意的微笑,一键发布到生产环境,欣喜的发现服务崩溃了。

为什么服务会崩溃呢?

channel死锁

死锁是golang里边最常见的一类问题,我们从java和c/c++转过来的gopher在编程时候会特别注意mutex,semaphore,atomic等等的使用,反复检查会不会造成死锁。但是我们有可能会忽略掉另一个死锁大元凶:channel。

channel简直就是用来死锁的。

unbuffered channel读和写都是blocking的,也就是说读一个没人写的channel和写一个没人读的channel都会造成死锁。死锁状态下的goroutine会永远等待这个channel operation返回。这么做的goroutine多了,直接就会造成内存泄漏,服务器崩溃。

buffered channel不会吗?

也会的。buffered channel写满了之后再写就会死给你看。空的channel没人的情况下去读也死给你看。

怎么避免呢?

select {
case <-ch:
    // a read from ch has occurred
case <-time.After(1 * time.Second):
    // moving on after 1 second
}

这在官方的 effective go里边就有介绍。

第三方调用

我们往往不能天真的认为我们调用的上游服务不会挂,我们也不能淳朴的认为我们的网络环境永远是可靠的。往往一个小波动就会使得我们好多goroutine临时的卡在第三方api调用上。比如正常状况下我们期待所有goroutine20ms都会完成。但是突然网络抖动,或者第三方服务稳定性出了一点小问题,我们的goroutine都要2秒钟才会完成。

可能有人会觉得,不就是慢了一点吗,有什么大关系。

同志们,关系非常大。本来goroutine 20ms就退出的情况下,我们可能同时也就是几千个goroutine。如果goroutine生命周期变长,我们就会瞬间攒下来100*几千个goroutine,如果不加以限制的话,我们的服务就会瞬间崩溃。

所以别人的问题,可能会导致我们自己服务的失败。

怎么办?

使用circuit breaker。

我们想这样保护我们的服务:

首先设定SLA (service level agreement)

  1. 平均响应时间
  2. 容错率
  3. max qps

我们需要monitor第三方服务的调用出错率。当出错率高于某个阈值(超时也是一种错误),我们需要暂时对服务调用这个操作直接报错,这样调用的goroutine就可以迅速的退出。

我们还需要不断的尝试,看看调用状况是不是变回良好可用的状态,如果是,我们就得恢复正常的调用机制。并且重新开始计算出错率。

这个pattern其实就是大家常说的熔断器(circuit breaker)

熔断器的一个golang实现:afex/hystrix-go

怎么观测我们的服务承受的压力?

普罗米修斯:Prometheus

数据狗:Modern monitoring & analytics

NewRelic: Digital Performance Monitoring and Management | New Relic

如何debug到底goroutine卡在什么地方?

pprof : https://golang.org/pkg/net/http/pprof/

这篇文章粗浅无比的谈了一下golang服务如何防止,检测,排查goroutine过多引起的在线故障。意在抛砖引玉。聪明的你,我们一起学习,一起深入讨论。

希望我们露出得意微笑部署golang服务的时候,可以更加自信,更加成竹在胸。


 - EOF -

推荐阅读(点击标题可打开)

1、详解K8S List-Watch机制和Informer模块

2、我为什么放弃RESTful、拥抱GraphQL

3、Go泛型真的要来了!最早在Go 1.17版本支持

Go 开发大全

参与维护一个非常全面的Go开源技术资源库。日常分享 Go, 云原生、k8s、Docker和微服务方面的技术文章和行业动态。

关注后获取

回复 Go 获取6万star的Go资源库



分享、点赞和在看

支持我们分享更多好文章,谢谢!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存