本司礼物系统使用了golang的 mongo库 mgo,中间踩了一些坑,总结下避免你们再踩坑php

golang的mgo库说明里是说明了开启链接复用的,但观察实验发现,这并无根本实现链接的控制,链接复用仅在有空闲链接时生效,高并发时无可用链接会不断建立新链接,因此最终仍是须要程序员自行去限制最大链接才行。程序员

废话很少说,开始上代码golang

 

golang main入口启动时,咱们会建立一个全局session,而后每次使用时clone session的信息和链接,用于本次请求,使用后调用session.Close() 释放链接。session

 

Clone的方法注释里说明会重用原始session的socket链接,可是并发请求一大,其余协程来不及释放链接,当前协程会怎么办?并发

 

在源码中加debug,结果日志说明一切:app

不断的建立链接  AcquireSocketsocket

 $  netstat -nat|grep -i 27017|wc -l高并发

400优化

若是每一个session 不调用close,会达到恐怖的4096,并堵死其余请求,因此clone或copy session时必定要defer close掉ui

启用maxPoolLimit 参数则会限制总链接大小,链接到限制则当前协程会sleep等待  直到能够建立链接,高并发时锁有问题,会致使多建立几个链接

链接池设置方法:

一、配置中 增长 

[host]:[port]?maxPoolSize=10

二、代码中 :

dao.GlobalMgoSession.SetPoolLimit(10)

再作压测:

 $  netstat -nat|grep -i 27017|wc -l

15

 

 

结论:

每次clone session以后,操做结束时若是调用 session.Close 则会unset Socket  ,socket refer数减小,若是不设置上限,每一个协程请求到来发现无空闲链接就会建立socket链接,直到达到最大值4096,而mongo的链接数上限通常也就是1万,也就是一个端口你只能启动一两个进程保证链接不被撑爆,过多的链接数客户端效率不高,server端更会耗费内存和CPU,因此须要启用自定义链接池 , 启用链接池也须要注意若是有pooMaxLimit个协程执行过长或者死循环不释放socket链接,也会悲剧。

mgo底层socket链接池只在maxPooMaxLimit 范围内实现复用,须要自行优化。