Jef*_*tos 7 mysql amazon-rds node.js bookshelf.js knex.js
在我的公司,我们的应用程序在 NodeJS 上运行,并通过多个 EC2 实例和一个 RDS 数据库运行。
我们的应用程序需要一些升级,因为一些依赖项已经很旧了,我们所做的引起我们注意的升级之一是更新我们的数据库库:mysql(从 2.16.0 到 2.17.0)、knex(从 0.12.2 到 0.19 .1) 和书架(0.10.2 至 0.15.1)。
检查更改日志后,不需要更改代码,因此我们很快设法将其上传到我们的临时服务器。
突然,我们的应用程序变得太慢了。加载所有数据需要几秒钟,而我们的主要用户的仪表板在几毫秒内加载到同一台服务器上,需要大约 30 秒。几分钟后,整个应用程序完全没有响应。
为了检查问题是否仅与依赖项升级有关,我们设法将这些降级到工作版本,并且应用程序恢复到正常速度。又升级了,又慢了。
我们已经开始通过 New Relic 分析 RDS 方面是否有问题。什么都没有。没有高峰,没有高 CPU 使用率,没有慢查询或其他任何事情。然后我们来检查连接池,发现适合我们的knex版本使用“generic-pool”,而新版本使用“tarn”。
所以我们开始调试池,发现它被一个指定的查询填满,完全冻结了一段时间,然后开始抛出“TimeoutError: Knex: 获取连接超时。池可能已满”错误。
但是关于填充所有池并冻结的查询最有趣的是它根本不应该生成(并且在使用不存在此问题的过时版本时不会生成)。
在我们的应用程序中,我们只在两种情况下对联系人表执行 SELECT 请求:
首先,很明显,当用户想要列出他们的联系人时:
let contacts = await Contacts.forge({ 'list_owner': udata.id }).fetchAll()
Run Code Online (Sandbox Code Playgroud)
其次,在检查联系人匹配以判断某些信息是否应该对指定用户可见时,取决于信息所有者的隐私设置:
let checkContact = await Contacts.where({
list_owner: target_user,
contact: udata.id
}).fetch()
Run Code Online (Sandbox Code Playgroud)
经过几次 grepping,我可以保证我们的代码库中没有其他地方可以从联系人表中进行 SELECTS。在我们的调试中,我们没有发现未定义的值,并且我们的调查显示查询在之前的代码运行时运行。但是正如您在屏幕截图中看到的,查询 knex 运行没有条件:
select `contacts`.* from `contacts`
Run Code Online (Sandbox Code Playgroud)
我们相信这就是它填满池的原因(因为请求每个用户的联系人是一项相当大的工作),但与此同时,我们看不出为什么 knex 运行这样的查询,如:
什么可能导致这样的问题?
对于一些可能会跌倒在这里的人!
\n如果这没有意义,并且您最近将 Nodejs 升级到了 v14!这可能是原因!
\n上次我遇到了这个问题,把头发拉了一会儿!\n而且我正在使用 nvm,所以在尝试跟踪我所做的不同之后!因为它之前工作过!我想到了并用v13测试了它!它又起作用了!
\n所以要注意!这可能会为您节省大量时间和压力!
\nNodejs v14 做出了重大更改!并且pg模块受到影响!pg 开始让进程退出connect() call!
如果您正在使用postgres!使用nodejs v14及以上版本!确保使用pg版本的驱动程序模块>=8.0.3!并更好地升级到最新
npm install pg@latest --save\nRun Code Online (Sandbox Code Playgroud)\n如果您不使用postgres!尝试更新您的数据库驱动程序!可能是一样的吧!也尝试使用nodejs V13。确认是同样的问题!
如果像我一样你想知道细节以及发生了什么!?
\n使用节点 V14!API 发生了一些重大变化!还有很多东西都改变了!包括Openssl版本!
\n对于postgres!还有pg模块!问题如该线程的评论中所述:
\n\n初始的readyState(一个私有/未记录的API,
\n在 Node 14 中,net.Socket 的 pg 使用)似乎已从“封闭”更改为“开放”。
\n它\xe2\x80\x99s 很难修复并具有完美的向后兼容性,但我想\n我有一个\xe2\x80\x99s 足够接近的补丁。
\n
根据此PR!
\n你可以看到这个差异的变化
\n简而言之,如上所述!onReady 的 api 发生了变化net.Socket!\n并且实现的解决方案是根本不使用 onReady!
并且根据这个
\n\n\n现在,当在其上调用 connect 时,Connection 始终会在其流上调用 connect。
\n
在旧版本中,仅当套接字处于打开closed状态时才调用 connect!readyState使用被消除!
检查这一行
\n你能明白!
\n取决于实施!许多事情可能会或不会受到这些核心变化的影响!
\n因为我想看看变化发生在哪里!干得好
\nhttps://github.com/nodejs/node/pull/32272
\n人们也可以检查更改日志:
\nhttps://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.md
\n还要提一下重大变化!使pg进程在 处退出connect() call。这就是它退出的原因!并且可以看到日志记录!\n对此有更多详细信息!这是怎么发生的!Sequelize 有 postgres 方言实现!哪个用pg!还有pg客户端!创建连接!连接有一个connect事件!当它连接时它会发出它!而且因为节点 v14 将流的行为更改为以 open 开头!流连接被跳过!因为readyState检查(预计是关闭的,但它变成了开放!)!并且流被视为已连接(否则为块)!哪里不是!并且connect事件是直接发出的!当这种情况发生时!客户端要么调用连接对象的方法requestSsl(),要么调用startup()连接对象的方法!两者都会调用this._stream.write。因为流没有连接!发生错误!这个错误没有被catch!那么续集驱动程序中的承诺!将一直悬而未决!然后事件循环变空!Nodejs 默认行为只是退出!
您可以通过代码行看到该步骤:
\nconnect()调用并发出connect!认为流已连接是因为 V14 更改connect事件被捕获并回调运行!requestSsl()或startup()将运行stream.write将被运行并被调用(requestSsl()、startup())https://github.com/nodejs/node/issues/22088
\n\n\n| 归档时间: |
|
| 查看次数: |
641 次 |
| 最近记录: |