Golang 介绍及踩坑系列之三

Chang · · 2577 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

聪明的你,用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 : golang.org/pkg/net/http

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

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


有疑问加站长微信联系(非本文作者)

本文来自:知乎专栏

感谢作者:Chang

查看原文:Golang 介绍及踩坑系列之三

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2577 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传