现在的项目是用nodejs开发了手游的服务端,数据库用的是mysql,目前还在开发阶段,访问量很少,就自己人测试访问下。 但是发现问题是有时候就4-5个人或者更多一点的访问的时候会出现等待,基本上就要等到nginx断开再重连了,或者这个时候重启一下nodejs,再连马上就能连上。我开始怀疑是nodejs阻塞造成的,于是我在服务器上用PM2多开了几个进程,maxSockets也设置到100了,但是发现还是会出现这种问题,我现在就不知道是什么原因造成了的,这问题也不知道怎么查?从哪下手查,刚接触nodejs没多久。 PS:开始以为是数据库的问题,但是我测试了当我服务器连不上的时候,我马上运行我本地代码,连接数据库又是正常的,就不知道什么原因了。 刚接触nodejs不久,还望给位帮忙分析分析,该怎么处理。 另外,我人在上海,忘各位帮帮帮,要是在上海的帮解决了我愿请各位吃个饭什么的都行。外地的实在不行发个红包也行。 这问题真是搞了一个多月了 还不知道怎么弄。 再次谢过!
nodejs 哪的阻塞
@chita nodejs的机制不就是这样的么0.12以前的版本,一个进程最多支持5个Sockets,如果这5个都没返回结果的时候,第六个请求就会排队。
mysql查询平均每句耗时多少?
会mysql有启用连接池吗 自豪地采用 CNodeJS ionic
@klesh 有启用连接池。
@idreamshen 没有做统计,但是都是毫秒级别的吧,因为用了第三方的后台对mysql的查询做了监控,没有发现有慢查询的。
不要用nginx做node的代理。nginx的作用是静态文件代理
第二点,检查pool的 connnect.release();如果不release()很快就会满
@MiguelValentine 那用什么做代理呢?
@MiguelValentine 有release()的
@imhered 裸node端口不代理。这样看起来是你的代码问题。
把数据库调用和 release 的相关代码贴出来看下,这种情况很像是连接池满了。
@klesh 我在底层用了2种连接池,一个是mysql中间件,这个我好像没有看到哪里可以设置连接池大小,还有一个是generic-pool,这个max我设置的是60。但是当出现连接不上服务器的时候,我在mysql里面show processlist,当前连接都还没达到60啊,而且我个人理解连接池就算占满了,当有新的连接进来的时候,会从新从数据库里初始化一个连接,网上查了这个初始化有点耗时和耗资源,但是也不应该出现连接不上的情况啊。
@klesh 这是创建连接池的代码 创建连接对象 这个是具体的调用,这里是select,其他的update什么的都一样,最后少了几个括号,截图截不了了
@MiguelValentine 应该是代码问题,和nginx应该没关系,现在就不知道怎么查个问题。
怎么会用到2种连接池?mysql中间件是怎么说?没道理mysql还要挂载到 app 上面去啊?是指连接库吧?你要确认连接池一个就够了!如果是2个池,下面的池假定是5,上面的池是60,当在外面取第6个时,上面的池就会去问下面的池要,下面的池没有了就会一直卡住。池是进去了连接就被存在池里面不会释放,有人要的时候直接返回连接。总之不能搞2个池,只会将情况复杂化!
池的意思是达到上限了就排队,不是不够用了还会新建连接,你的理解完全错误,那样叫溢出了,真正是错误的行为!
@klesh 我说错了,mysql这个是连接库。还有一个是generic-pool,这个也是一个连接库。那这里我有一个疑问:假如我数据库允许的最大连接数(A)是100,连接池的最大数量是B,那我是不是应该让B=A,如果B<A的,假如B=90,那是不是就会有10个连接永远都用不到呢。 还有,池的作用不应该是连接用完就放回池里,连接在池里闲置是有时间限制的,超过这个时间,这个连接就会被数据库回收掉。当一个新的连接上了的时候,先从池里拿,如果有那么就直接拿来用,如果池里没有,那么才在数据库里去拿。 不知道我理解的对不对,因为我这也是在网上查的。
@imhered 没错,你这次讲得对,但是占满了是不会再建新的链接的,要等池里某个链接释放了!你仔细看你这段话,跟你之前讲的占满了就建新的连接是没有冲突的。两回事。
dbConfigArray 是什么样的?console.log 输出一下?
话说你这字体太难看了,换 Lucida Console 吧!
@klesh 就是数据库连接字符串 ’host’: ‘xxxxx’, ‘user’: ‘root’, ‘password’: ‘password’, ‘database’: ‘database’, ‘charset’: ‘utf8’
@imhered 写的太java化了,具体哪里有问题我暂时没看出来。 但是 先把你所有的callback前的return去掉。
@MiguelValentine 和return应该没关系吧,我写return是因为 我在if里面callback之后,后面没有写else,所有在这个callback的时候加了return 不让走后面的代码
@imhered 最好是先cb再一行return。
@MiguelValentine 哦。我先改改
@MiguelValentine 这个有区别吗? @imhered 看看 createPool
@imhered 如果我没看错,你的 return callback 是在 if(error)之外吧?也就是说这一行无论如何都是会被执行的!而这一行之后的代码无论如何是不会被执行的。
@klesh 细节和习惯,会导致不可知错误。
@klesh createPool是mysql库封装好的函数,不是我写的。
@MiguelValentine Holy xxxx! 咱别泛酸,你说说:
return callback(err, results);
和
callback(err, results);
return;
这两句,除开返回结果不说,在 执行 顺序上会有任何不同吗?然而第一种不是更简洁明了吗?
@imhered 你用的哪个包?
@klesh 对,是这样的。因为这里是最终操作数据库里嘛,所有不管它是有没有error都给返回,所以return callback写在了if(error)的外面,而里面只是做一个错误记录,而return callback后面没有代码了,就只剩下几个括号了。
一个进程最多支持5个Sockets?听起来更像是浏览器。然后应该是代码问题,先别测试太过具体的业务代码,直接弄几个比较简单例子来测试,比如插入数据库或查询,mysql我之前有测试过,用node.js连接操作,并发50每秒执行200-400才比较正常
@klesh 就是mysql,require(‘mysql’); 这个。
@wldlzt 对,因为我查了下文档,nodejs 0.12之前的版本,默认就是5个,就是http请求。 http.globalAgent.maxSockets 就是这个限制了的,好像从0.12以后的版本这个值就是无穷大了。
@wldlzt 请教下,因为我现在不知道怎么测。我用微软的web application stress tool 这个工具,请求了某几个select请求,完全正常啊,
照你说的,createPool都没指定池大小啊?connectionLimit 就是池大小,你试下改这个参数,看看情况是不是有所改变,若是的话说明有哪处地方没有 release connection 了。
@klesh 确实,用mysql这个包,没有指定连接池大小。我改下试试。先查查,非常感谢啊!
@klesh 非常感谢,好像找到问题了,查了下mysql包官方文档,connectionLimit 默认是10,多了就会排队,我的问题应该就是这个了。我还在测试中!感谢!
@klesh 我觉得我没有什么必要教不文明的小孩子。
@imhered 我出5毛不是这个问题。
@MiguelValentine 和谐和谐嘛,都是为了帮我,谢谢了。 应该是这个问题了,因为我没配置connectionLimit 这个值,查了下官方文档默认是10. 连接超过这个值,多余的就会排队等待到有空闲的连接出来。
@imhered 每次排队空库查询假设5ms,你是有多强的iops。。
@MiguelValentine 你说的也不是没有道理,我的服务端这块是手游服务端,虽然现在测试阶段,人少。但我目前觉得connectionLimit 的可能性是最大的,正在测试中。
@imhered 问题的根源应该还不是这里,你这玩意貌似还在开发中吧,照理不应该有那么长时间的数据库操作。应该还是哪里没有 release connection,这个必须排查清楚,否则即使你把它设到10000000还是有用完的时候,connection 不被 release 会一直占着池而且不会关闭,池满了你的程序也就到头了。
@MiguelValentine 我觉得你真是奇怪,为什么会突然觉得你是传道者而我就成了小孩了。顾左右而言它,视问题而不答你不去搞政治实在太可惜了。程序执行是很简单的东西,是按什么顺序这个更是基础中的基本,莫说你年纪不太可能大过于我,就这种程度的讨论最多只能说是切磋,尚且不至于由你来教我。
@klesh 所以我为什么要跟一个holy xxxx讲话?在瞎定位错误?连接池的connnet-limit能影响到4/5人的阻塞?你水准不够走开。
@klesh 这个倒也有可能,但是我操作数据库的底层函数就那么几个,全都release了的,还有就是放个周末什么的时候,也就是过几天没人连接数据库的时候,我show processlist命令的时候,是没有连接的,那说明连接都是release了的。 我再仔细查查。
@imhered release()不会断开当前链接。它是释放node中的管道锁定。使其链接可被其他代码调用。只要进程不死,连接不掉。
@MiguelValentine 对,release就是把当前这个连接放回连接池,但是这个连接在连接池中的生命周期也是有时间限制的,过了这个时间,这个连接就会被数据库回收掉吧。
@imhered 最新的我不知道。反正很久以前mysql这个库就有8小时被数据库回收报错的bug。我不知道现在是按需重连还是会定时重连。
@MiguelValentine 你说的8小时是wait_timeout这个值。 什么重连?连接过了wait_timeout这个值就给回收掉了,和重连什么关系?没懂!
@klesh 找了半天,确实有一个地方没有release,但是我这里用的事物,请教下我是应该在AB位置分别release(感觉有点不对),还是在C里面rollback或者commint后面release呢。 代码截图,其中118行的conn就是从连接池中获取的。
@imhered 应该在C的地方 release。应该是这里了, rollback 或者 commit 之后就要 release。
@klesh 嗯。问题总算解决了,感谢!