CNode

【求帮忙】关于阻塞问题,或者说是压力测试(真不知道叫个什么标题好)

问答
Iim-here发布于11 年前最后回复11 年前54 回复6613 浏览0 收藏

现在的项目是用nodejs开发了手游的服务端,数据库用的是mysql,目前还在开发阶段,访问量很少,就自己人测试访问下。 但是发现问题是有时候就4-5个人或者更多一点的访问的时候会出现等待,基本上就要等到nginx断开再重连了,或者这个时候重启一下nodejs,再连马上就能连上。我开始怀疑是nodejs阻塞造成的,于是我在服务器上用PM2多开了几个进程,maxSockets也设置到100了,但是发现还是会出现这种问题,我现在就不知道是什么原因造成了的,这问题也不知道怎么查?从哪下手查,刚接触nodejs没多久。 PS:开始以为是数据库的问题,但是我测试了当我服务器连不上的时候,我马上运行我本地代码,连接数据库又是正常的,就不知道什么原因了。 刚接触nodejs不久,还望给位帮忙分析分析,该怎么处理。 另外,我人在上海,忘各位帮帮帮,要是在上海的帮解决了我愿请各位吃个饭什么的都行。外地的实在不行发个红包也行。 这问题真是搞了一个多月了 还不知道怎么弄。 再次谢过!

查看回复

回复 (54)

K
klesh#1·11 年前

怎么会用到2种连接池?mysql中间件是怎么说?没道理mysql还要挂载到 app 上面去啊?是指连接库吧?你要确认连接池一个就够了!如果是2个池,下面的池假定是5,上面的池是60,当在外面取第6个时,上面的池就会去问下面的池要,下面的池没有了就会一直卡住。池是进去了连接就被存在池里面不会释放,有人要的时候直接返回连接。总之不能搞2个池,只会将情况复杂化!

池的意思是达到上限了就排队,不是不够用了还会新建连接,你的理解完全错误,那样叫溢出了,真正是错误的行为!

I
im-here#2·11 年前
引用 klesh怎么会用到2种连接池?mysql中间件是怎么说?没道理mysql还要挂载到 app 上面去啊?是指连接库吧?你要确认连接池一个就够了!如果是2个池,下面的池假定是5,上面的池是60,当在外面取...

@klesh 我说错了,mysql这个是连接库。还有一个是generic-pool,这个也是一个连接库。那这里我有一个疑问:假如我数据库允许的最大连接数(A)是100,连接池的最大数量是B,那我是不是应该让B=A,如果B<A的,假如B=90,那是不是就会有10个连接永远都用不到呢。 还有,池的作用不应该是连接用完就放回池里,连接在池里闲置是有时间限制的,超过这个时间,这个连接就会被数据库回收掉。当一个新的连接上了的时候,先从池里拿,如果有那么就直接拿来用,如果池里没有,那么才在数据库里去拿。 不知道我理解的对不对,因为我这也是在网上查的。

K
klesh#3·11 年前
引用 im-here@klesh 我说错了,mysql这个是连接库。还有一个是generic pool,这个也是一个连接库。那这里我有一个疑问:假如我数据库允许的最大连接数(A)是100,连接池的最大数量是B,那...

@imhered 没错,你这次讲得对,但是占满了是不会再建新的链接的,要等池里某个链接释放了!你仔细看你这段话,跟你之前讲的占满了就建新的连接是没有冲突的。两回事。

dbConfigArray 是什么样的?console.log 输出一下?

K
klesh#4·11 年前

话说你这字体太难看了,换 Lucida Console 吧!

I
im-here#5·11 年前
引用 klesh话说你这字体太难看了,换 Lucida Console 吧!

@klesh 就是数据库连接字符串 'host': 'xxxxx', 'user': 'root', 'password': 'password', 'database': 'database', 'charset': 'utf8'

I
im-here#7·11 年前
引用 MiguelValentine@imhered 写的太java化了,具体哪里有问题我暂时没看出来。 但是 先把你所有的callback前的return去掉。

@MiguelValentine 和return应该没关系吧,我写return是因为 我在if里面callback之后,后面没有写else,所有在这个callback的时候加了return 不让走后面的代码

I
im-here#9·11 年前
引用 MiguelValentine@imhered 最好是先cb再一行return。

@MiguelValentine 哦。我先改改

K
klesh#10·11 年前
引用 MiguelValentine@imhered 最好是先cb再一行return。

@MiguelValentine 这个有区别吗? @imhered 看看 createPool

K
klesh#11·11 年前
引用 im-here@MiguelValentine 哦。我先改改

@imhered 如果我没看错,你的 return callback 是在 if(error)之外吧?也就是说这一行无论如何都是会被执行的!而这一行之后的代码无论如何是不会被执行的。

I
im-here#12·11 年前
引用 klesh@imhered 如果我没看错,你的 return callback 是在 if(error)之外吧?也就是说这一行无论如何都是会被执行的!而这一行之后的代码无论如何是不会被执行的。

@klesh 对,是这样的。因为这里是最终操作数据库里嘛,所有不管它是有没有error都给返回,所以return callback写在了if(error)的外面,而里面只是做一个错误记录,而return callback后面没有代码了,就只剩下几个括号了。

W
wldlzt#13·11 年前

一个进程最多支持5个Sockets?听起来更像是浏览器。然后应该是代码问题,先别测试太过具体的业务代码,直接弄几个比较简单例子来测试,比如插入数据库或查询,mysql我之前有测试过,用node.js连接操作,并发50每秒执行200-400才比较正常

I
im-here#14·11 年前
引用 klesh@imhered 你用的哪个包?

@klesh 就是mysql,require('mysql'); 这个。

I
im-here#15·11 年前
引用 wldlzt一个进程最多支持5个Sockets?听起来更像是浏览器。然后应该是代码问题,先别测试太过具体的业务代码,直接弄几个比较简单例子来测试,比如插入数据库或查询,mysql我之前有测试过,用node...

@wldlzt 对,因为我查了下文档,nodejs 0.12之前的版本,默认就是5个,就是http请求。 http.globalAgent.maxSockets 就是这个限制了的,好像从0.12以后的版本这个值就是无穷大了。

I
im-here#16·11 年前
K
klesh#17·11 年前

照你说的,createPool都没指定池大小啊?connectionLimit 就是池大小,你试下改这个参数,看看情况是不是有所改变,若是的话说明有哪处地方没有 release connection 了。

I
im-here#19·11 年前
引用 klesh照你说的,createPool都没指定池大小啊?connectionLimit 就是池大小,你试下改这个参数,看看情况是不是有所改变,若是的话说明有哪处地方没有 release connect...

@klesh 非常感谢,好像找到问题了,查了下mysql包官方文档,connectionLimit 默认是10,多了就会排队,我的问题应该就是这个了。我还在测试中!感谢!

I
im-here#22·11 年前
引用 MiguelValentine@imhered 我出5毛不是这个问题。

@MiguelValentine 和谐和谐嘛,都是为了帮我,谢谢了。 应该是这个问题了,因为我没配置connectionLimit 这个值,查了下官方文档默认是10. 连接超过这个值,多余的就会排队等待到有空闲的连接出来。

C
chita#23·11 年前

nodejs 哪的阻塞

I
im-here#24·11 年前
引用 chitanodejs 哪的阻塞

@chita nodejs的机制不就是这样的么0.12以前的版本,一个进程最多支持5个Sockets,如果这5个都没返回结果的时候,第六个请求就会排队。

I
idreamshen#25·11 年前

mysql查询平均每句耗时多少?

K
klesh#26·11 年前

会mysql有启用连接池吗 自豪地采用 CNodeJS ionic

M
MiguelValentine#27·11 年前
引用 klesh@MiguelValentine 这个有区别吗? @imhered 看看 createPool

@klesh 细节和习惯,会导致不可知错误。

I
im-here#28·11 年前
引用 klesh@MiguelValentine 这个有区别吗? @imhered 看看 createPool

@klesh createPool是mysql库封装好的函数,不是我写的。

K
klesh#29·11 年前
引用 MiguelValentine@klesh 细节和习惯,会导致不可知错误。

@MiguelValentine Holy xxxx! 咱别泛酸,你说说:

return callback(err, results);

callback(err, results);
return;

这两句,除开返回结果不说,在 执行 顺序上会有任何不同吗?然而第一种不是更简洁明了吗?

I
im-here#30·11 年前
I
im-here#31·11 年前
引用 idreamshenmysql查询平均每句耗时多少?

@idreamshen 没有做统计,但是都是毫秒级别的吧,因为用了第三方的后台对mysql的查询做了监控,没有发现有慢查询的。

K
klesh#32·11 年前

@imhered 看看连接池大小是多少?

来自炫酷的 CNodeMD

M
MiguelValentine#33·11 年前

不要用nginx做node的代理。nginx的作用是静态文件代理

M
MiguelValentine#34·11 年前

第二点,检查pool的 connnect.release();如果不release()很快就会满

I
im-here#35·11 年前
M
MiguelValentine#37·11 年前
引用 im-here@MiguelValentine 那用什么做代理呢?

@imhered 裸node端口不代理。这样看起来是你的代码问题。

K
klesh#38·11 年前

把数据库调用和 release 的相关代码贴出来看下,这种情况很像是连接池满了。

I
im-here#39·11 年前
引用 klesh@imhered 看看连接池大小是多少? 来自炫酷的 CNodeMD

@klesh 我在底层用了2种连接池,一个是mysql中间件,这个我好像没有看到哪里可以设置连接池大小,还有一个是generic-pool,这个max我设置的是60。但是当出现连接不上服务器的时候,我在mysql里面show processlist,当前连接都还没达到60啊,而且我个人理解连接池就算占满了,当有新的连接进来的时候,会从新从数据库里初始化一个连接,网上查了这个初始化有点耗时和耗资源,但是也不应该出现连接不上的情况啊。

I
im-here#40·11 年前
引用 klesh把数据库调用和 release 的相关代码贴出来看下,这种情况很像是连接池满了。

@klesh 11111111.jpg 这是创建连接池的代码 2222222222.jpg 创建连接对象 33333.jpg 这个是具体的调用,这里是select,其他的update什么的都一样,最后少了几个括号,截图截不了了

I
im-here#41·11 年前
引用 MiguelValentine@imhered 裸node端口不代理。这样看起来是你的代码问题。

@MiguelValentine 应该是代码问题,和nginx应该没关系,现在就不知道怎么查个问题。

I
im-here#44·11 年前
引用 MiguelValentine@imhered 每次排队空库查询假设5ms,你是有多强的iops。。

@MiguelValentine 你说的也不是没有道理,我的服务端这块是手游服务端,虽然现在测试阶段,人少。但我目前觉得connectionLimit 的可能性是最大的,正在测试中。

K
klesh#45·11 年前
引用 im-here@MiguelValentine 和谐和谐嘛,都是为了帮我,谢谢了。 应该是这个问题了,因为我没配置connectionLimit 这个值,查了下官方文档默认是10. 连接超过这个值,多余的就...

@imhered 问题的根源应该还不是这里,你这玩意貌似还在开发中吧,照理不应该有那么长时间的数据库操作。应该还是哪里没有 release connection,这个必须排查清楚,否则即使你把它设到10000000还是有用完的时候,connection 不被 release 会一直占着池而且不会关闭,池满了你的程序也就到头了。

@MiguelValentine 我觉得你真是奇怪,为什么会突然觉得你是传道者而我就成了小孩了。顾左右而言它,视问题而不答你不去搞政治实在太可惜了。程序执行是很简单的东西,是按什么顺序这个更是基础中的基本,莫说你年纪不太可能大过于我,就这种程度的讨论最多只能说是切磋,尚且不至于由你来教我。

M
MiguelValentine#46·11 年前
引用 klesh@imhered 问题的根源应该还不是这里,你这玩意貌似还在开发中吧,照理不应该有那么长时间的数据库操作。应该还是哪里没有 release connection,这个必须排查清楚,否则即使你把...

@klesh 所以我为什么要跟一个holy xxxx讲话?在瞎定位错误?连接池的connnet-limit能影响到4/5人的阻塞?你水准不够走开。

I
im-here#47·11 年前
引用 klesh@imhered 问题的根源应该还不是这里,你这玩意貌似还在开发中吧,照理不应该有那么长时间的数据库操作。应该还是哪里没有 release connection,这个必须排查清楚,否则即使你把...

@klesh 这个倒也有可能,但是我操作数据库的底层函数就那么几个,全都release了的,还有就是放个周末什么的时候,也就是过几天没人连接数据库的时候,我show processlist命令的时候,是没有连接的,那说明连接都是release了的。 我再仔细查查。

M
MiguelValentine#48·11 年前
引用 im-here@klesh 这个倒也有可能,但是我操作数据库的底层函数就那么几个,全都release了的,还有就是放个周末什么的时候,也就是过几天没人连接数据库的时候,我show processlist命令...

@imhered release()不会断开当前链接。它是释放node中的管道锁定。使其链接可被其他代码调用。只要进程不死,连接不掉。

I
im-here#49·11 年前
引用 MiguelValentine@imhered release()不会断开当前链接。它是释放node中的管道锁定。使其链接可被其他代码调用。只要进程不死,连接不掉。

@MiguelValentine 对,release就是把当前这个连接放回连接池,但是这个连接在连接池中的生命周期也是有时间限制的,过了这个时间,这个连接就会被数据库回收掉吧。

M
MiguelValentine#50·11 年前
引用 im-here@MiguelValentine 对,release就是把当前这个连接放回连接池,但是这个连接在连接池中的生命周期也是有时间限制的,过了这个时间,这个连接就会被数据库回收掉吧。

@imhered 最新的我不知道。反正很久以前mysql这个库就有8小时被数据库回收报错的bug。我不知道现在是按需重连还是会定时重连。

I
im-here#51·11 年前
引用 MiguelValentine@imhered 最新的我不知道。反正很久以前mysql这个库就有8小时被数据库回收报错的bug。我不知道现在是按需重连还是会定时重连。

@MiguelValentine 你说的8小时是wait_timeout这个值。 什么重连?连接过了wait_timeout这个值就给回收掉了,和重连什么关系?没懂!

I
im-here#52·11 年前
引用 klesh@imhered 问题的根源应该还不是这里,你这玩意貌似还在开发中吧,照理不应该有那么长时间的数据库操作。应该还是哪里没有 release connection,这个必须排查清楚,否则即使你把...

@klesh 找了半天,确实有一个地方没有release,但是我这里用的事物,请教下我是应该在AB位置分别release(感觉有点不对),还是在C里面rollback或者commint后面release呢。 代码截图,其中118行的conn就是从连接池中获取的。 44444444444444.jpg

参与回复
登录后即可参与回复。登录