升级Knex后出现 "获取连接超时 "的情况。

问题描述 投票:3回答:1

在我的公司里,我们的应用程序在多个EC2实例和一个RDS数据库上运行NodeJS。

我们的应用程序需要一些升级,因为一些依赖已经很旧了,我们做的升级之一引起了我们的注意,就是更新我们的数据库库:mysql(从2.16.0到2.17.0),knex(从0.12.2到0.19.1)和bookshelf(从0.10.2到0.15.1)。

在检查了变更日志后,不需要修改代码,所以我们很快就把它上传到了我们的暂存服务器上。

突然,我们的应用程序变得太慢了。所有的数据都需要几秒钟的时间来加载,而我们的主用户的仪表盘,在同一台服务器上只需要几毫秒的时间就可以加载,却需要30秒左右。几分钟后,整个应用程序完全没有反应。

为了检查问题是否只涉及到依赖升级,我们已经设法将这些降级到工作版本,应用程序恢复到正常速度。再次升级,又慢了。

我们已经开始通过New Relic分析是不是RDS那边出了问题。完全没有。没有出现峰值,没有出现CPU使用率高的情况,也没有出现查询慢的情况,也没有出现其他情况。然后我们来检查连接池,发现我们用的knex版本用的是 "generic-pool",而新版本用的是 "tarn"。

于是我们开始调试池子,发现池子被指定的查询填满,完全冻结一段时间,然后开始抛出 "TimeoutError: Knex: 超时获取连接。The pool is probably full "错误。

但是,最有趣的是,填满所有池子然后冻结的查询,根本就不应该生成(使用过时的版本不面临这个问题时,也不会生成)。

enter image description here

在我们的应用中,我们只在两种情况下对联系人表进行SELECT请求。

首先,很明显,当用户想列出他们的联系人时,我们才会对联系人表进行SELECT请求。

let contacts = await Contacts.forge({ 'list_owner': udata.id }).fetchAll()

第二,当检查联系人匹配时,根据信息所有者的隐私设置,来判断某些信息是否应该对特定用户可见。

let checkContact = await Contacts.where({
        list_owner: target_user,
        contact: udata.id
}).fetch()

经过多次grepping,我可以保证,在我们的代码库中,没有其他地方可以从联系人表中选择。在我们的调试中,我们没有发现未定义的值,我们的调查显示,查询运行时,前者的代码运行。但是从截图中可以看到,knex运行的查询没有条件。

select `contacts`.* from `contacts`

我们相信这就是为什么它能填满池子的原因(因为请求每个用户的联系人是一项相当大的工作),但同时,我们也不明白为什么knex会运行这样的查询,因为:

  • 在knex升级后没有做任何代码修改
  • 当使用旧版knex时,问题就不存在了(我们的生产服务器是用过时的knex版本运行的)。
  • 我们使用Redis做了大量的缓存(但不管怎样,DB没有过载,老版的Knex也能用)。
  • 如果问题真的是条件缺失,我们之前就可以发现,因为每个用户都会看到相同的联系人列表。

是什么原因导致了这样的问题?

mysql node.js amazon-rds knex.js bookshelf.js
1个回答
0
投票

对于有些人来说,可能属于这里!

如果没有意义,你最近把nodejs升级到了v14! 可能是这个原因!

我有这个问题,并拉我的头发安静的时间最后一次!和我使用的是nvm,所以不知何故后,试图跟踪我做了什么不同的! 因为它之前是工作的! 它来到我的脑海里,并用v13测试它! 然后它又工作了!

所以要注意!可能就是这个东西,这可能会节省你巨大的时间和压力!


0
投票

你必须摧毁连接,一旦查询执行。

 var knex = new Knex(config)
  knex(table)
    .where({ id: 1 })
    .then((result) => {
      callback(output)
    })
    .catch((err) => {
      err.error = true
      callback(err)
    })
    .finally(() => {
      knex.destroy()
    })
})
© www.soinside.com 2019 - 2024. All rights reserved.