Node.js 获取连接超时。游泳池可能已经满了。更新10000行时出错
当我尝试使用knexjs更新5000行时,获取连接时会出现错误超时。游泳池可能已经满了。” 当我查看CPU使用率时,我发现postgres pids总是占用90-98%的CPU使用率,这是不正常的,我在每个kenx上都尝试了destroy(),但它破坏了连接,没有解决问题 这是我正在使用的代码Node.js 获取连接超时。游泳池可能已经满了。更新10000行时出错,node.js,postgresql,knex.js,Node.js,Postgresql,Knex.js,当我尝试使用knexjs更新5000行时,获取连接时会出现错误超时。游泳池可能已经满了。” 当我查看CPU使用率时,我发现postgres pids总是占用90-98%的CPU使用率,这是不正常的,我在每个kenx上都尝试了destroy(),但它破坏了连接,没有解决问题 这是我正在使用的代码 const knexDb = knex({ client: 'pg', connection: { host : '127.0.0.1', user : process.env.DB_US
const knexDb = knex({ client: 'pg', connection: {
host : '127.0.0.1',
user : process.env.DB_USER,
password : process.env.DB_PASSWORD,
database : process.env.DB_DATABASE,
port: process.env.DB_PORT
}});
arrayWith5ThousandObj.map(data => {
knexDb('users').where({
user: data.user,
})
.update({
product: data.product
})
.catch(err => console.error('update user products', err))
})
这是一个每1分钟重复一次的循环函数,我也尝试了.finally->knexDb.destroy()
,但它破坏了连接,我得到的错误是无法获得连接
我想使用knexjs不断更新5000行或更多行,比如10000+行,我认为PostgreSQL可以处理这个每分钟10秒数千次查询的大型网站,而不会出现问题。问题不在服务器上,因为服务器有10个CPU和16gb的RAM,所以资源不是问题,我停止运行pro除此应用程序外,服务器上的访问。postgres pid几乎完全不使用CPU。因此,出现了大量查询中的问题。是否有批量更新,我可以使用knexjs一次性更新所有10000+行
我最近尝试过这个解决方案
return knexDb.transaction(trx => {
const queries = [];
arrayWith5ThousandObj.forEach(data => {
const query = knexDb('users')
.where({
user: data.user,
})
.update({
product: data.product,
})
.transacting(trx); // This makes every update be in the same transaction
queries.push(query);
});
Promise.all(queries) // Once every query is written
.then(trx.commit) // We try to execute all of them
.catch(trx.rollback); // And rollback in case any of them goes wrong
});
但我得到了这个错误:
{ error: deadlock detected
at Connection.parseE (/*********/connection.js:601:11)
at Connection.parseMessage (/*********/connection.js:398:19)
at Socket.<anonymous> (/**********/connection.js:120:22)
at Socket.emit (events.js:189:13)
at addChunk (_stream_readable.js:284:12)
at readableAddChunk (_stream_readable.js:265:11)
at Socket.Readable.push (_stream_readable.js:220:10)
at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
name: 'error',
length: 340,
severity: 'ERROR',
code: '40P01',
detail:
'Process 9811 waits for ShareLock on transaction 443279355; blocked by process 9808.\nProcess 9808 waits for ShareLock on transaction 443279612; blocked by process 9811.',
hint: 'See server log for query details.',
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: 'while locking tuple (1799,4) in relation "users"',
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'deadlock.c',
line: '1140',
routine: 'DeadLockReport' }
{错误:检测到死锁
在Connection.parseE(/*********/Connection.js:601:11)
在Connection.parseMessage(/*********/Connection.js:398:19)
在套接字上。(/*********/connection.js:120:22)
在Socket.emit(events.js:189:13)
在addChunk(_stream_readable.js:284:12)
在readableAddChunk(_stream_readable.js:265:11)
在Socket.Readable.push(_stream_Readable.js:220:10)
在TCP.onStreamRead[as onread](internal/stream_base_commons.js:94:17)
名称:“错误”,
长度:340,
严重性:“错误”,
代码:“40P01”,
详情:
'进程9811等待事务443279355上的ShareLock;被进程9808阻止。\n进程9808等待事务443279612上的ShareLock;被进程9811阻止。',
提示:“有关查询详细信息,请参阅服务器日志。”,
位置:未定义,
内部位置:未定义,
internalQuery:未定义,
其中:'在锁定与“用户”相关的元组(1799,4)时,
模式:未定义,
表:未定义,
列:未定义,
数据类型:未定义,
约束:未定义,
文件:“deadlock.c”,
行:“1140”,
例程:“死锁报告”}
用于控制并发:
knex.transaction((trx) => {
Bluebird.map(arrayWith5ThousandObj, (data) => {
return trx('users')
.where({
user: data.user,
})
.update({
product: data.product,
}))
}, { concurrency: 5 })
.then(trx.commit);
})
.then(() => console.log('all done'));
在初始解决方案中,您一次生成5000个承诺,所有这些承诺都尝试一次连接到数据库。此解决方案将确保最多有X个并发承诺,并且不会使用延迟,您可以微调解决方案的数量。Knex默认为连接。Knex对于此类大型bat来说并不是一个正确的工具h更新。特别是在你使用它的方式上,它是特别无性能的 在初始化5k查询生成器时,所有生成器都是同时创建、编译和执行的,但在使用事务时,所有查询都是通过单个连接发送的 因此,所有更新都以串行方式发送到DB服务器,并且这些更新的并发性为0 因此,有5000个knex对象被编译,5000个SQL查询(带有绑定)被发送到DB驱动程序,然后它们被驱动程序缓冲并逐个发送到服务器 但这不应该导致死锁……所以您的代码中可能还有其他一些问题 如果在查询中出现一个错误时,所有数据都不会被还原,那么您可以尝试在多个事务中使用较小的批处理。实际上,我不明白,如果可以重新发送/记录单行数据(如果这些行有问题),为什么需要在事务中进行此类数据更新 我最好的建议是从数据库服务器设置批处理大小、连接池大小和连接限制,以匹配您推送到服务器的工作负载 请随时查看postgreSQL pids CPU使用率98% 如果您通过单个事务执行大量更新,那么很可能导致CPU使用率过高。您应该登录到该SQL server,查看它在该工作负载期间执行的查询类型…可能您是在不同的Transacti中意外地多次并行运行同一更新代码这也可以解释僵局问题 由于单个update语句只能更新一行,因此SQL中的批更新问题非常严重。在单个查询中运行多个更新的一种方法是使用CTE查询
通过这种方式,您可以构建一批更新查询,并将它们作为主查询的预查询添加到数据库中,然后所有这些查询都作为原子操作运行,因此不需要事务来确保整个批处理或什么都没有进入。听起来好像Node.js或Knex为每一行打开了一个新连接。@a_horse_与_no_name一起运行,那么怎么办您建议解决此问题Bluebird map series以限制并发承诺。您目前基本上同时启动了数千个连接。@Gangstead能否给我一个示例。使用代码above@Gangstead我曾经承诺在1秒后解决每一个更新问题,但这不起作用,好像我要更新10秒的t数小时的数据,这将永远需要,是否有人在没有承诺的情况下做任何事情。因此,它在不到一秒内更新了所有行。我检测到了这个错误死锁,过了一段时间,我发现池可能已满。你能向我解释并发:5意味着什么,它是什么吗?我已经尝试过你的解决方案,它是有效的,但我看到了postgreSQL pids CPU使用率现在一直是98%,特别是这个函数每2分钟循环一次,服务器CPU是10-20%,这是正常的,但是使用这种方法postgreSQL CPU总是很高。每2分钟有一万多个单独的更新,将会有一些高CPU使用率。正如MikaS所说,你将