Go实践

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

最近在一个项目中使用了Go语言,当然不可避免的遇到了一些问题,记录这些问题的解决方法,也是Go实践的一部分了。

项目中的需求很简单,从RabbitMQ读数据,然后写入Redis当中,当然这个量比较大,似乎用goroutine是一个好的解决办法。

所以刚开始的逻辑是,从MQ读取数据,然后对每个数据都用一个goroutine处理。goroutine从Redis Pool里面取Redis connection,然后写数据到Redis。Redis go library redigo,库中提供Redis Pool的API,可以很方便的管理Redis connection。

func HandlePackage(data){  
    redisConn := getConnFromPool()
    wirteRedis(data)
}

func main(){  
    for package from MQ {
        go HandlePackage(package)
    }
}

问题1: no such host

结果一跑,就出现很多 "no such host" 错误,google了一下,发现是glibc的bug。当并发很高的时候,glibc库中查找DNS的代码就会出错。根据bug描述,要么升级glibc到2.20(但是2.20版本还没有发布),要么重新编译Go的net库。于是重新编译了Go的net库后,新问题又出现了。

问题2: redis connection timeout

这次是跑着跑着,Redis很多connection都timeout了,于是仔细看了一下redigo的Pool文档,发现默认Pool是没有大小限制的,如果Pool里面没有connection,会一直创建。难怪会timeout,应该是MQ数据太多,起了太多的goroutine,所以就会创建很多Redis client,Redis Server顶不住了。

想着限制一下Pool的大小,但是看了redigo的issue,发现如果限制大小,当Pool没有资源时,Get会直接返回error。

于是根据redigo的wiki,采用了youtube开源的vitess的一个Pool,这个pool限制大小后,当资源耗尽时,再请求会阻塞,直到Pool里面有可用资源才返回。

问题3: high memory usage

这次修改后,跑着跑着,发现进程的内存一直在增长,用top命令看,发现内存的 Res 一直飙升到1.8g,采用go自带的profile工具,发现sys和Stack sys都非常高,相反heap相应的项占用都非常少,看来不是内存泄漏的问题。

从profile上看,有时候goroutine会飙升到100k,估计内存居高不下跟goroutine有关。查阅了一下,发现在Go1.3中,存在一个bug。goroutine消耗的资源,并不会释放,相反会存放在pool中,等待下次新建goroutine时使用。于是进程的内存只会增加,不会减少。

分析了一下原因,有可能是网络不好,或者Redis在做bgsave或者其它操作,导致写Redis变慢,这样数据的生产(从MQ拿数据)比数据消费(写数据到Redis)快的多,而Redis connection又限制数量,导致goroutine阻塞在从pool取Reids connection上面,于是会创建越来越多的goroutine,结果就是导致内存一直飙升,却不会释放。

后来在golang-nuts邮件列表上问了问,有个老外建议用channel做信号量,来控制goroutine的数量,这样在高峰或者特殊情况,就不会导致goroutine无限制增长。

c := make(chan bool, 50) // concurrency = 50  
for <whatever> {  
  c <- true // blocks if the channel is full
  go func() {
    defer func() { <-c }  // make room for another goroutine
    // do whatever the goroutine should do
  }
}

修改代码后,发现goroutine限制数量后,内存基本控制在200多M以内,不会有占用大内存的现象出现了。

当然现在还是Go的初级使用者,这种消费者比生产者慢的需求,用Go的buffered channel是否合适,有没有更合适的解决方法,还待进一步研究。


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

本文来自:CSDN博客

感谢作者:yunba_io

查看原文:Go实践

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

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