使用 mysql knex 将所有函数创建为异步是一种不好的做法
To create all function as async is a bad practice with mysql knex
我在节点中使用knex.js(有主从连接)来连接mysql。
我的代码在 150 个用户下工作正常,但是当并发用户增加时,PM2 中的堆使用率也达到 100% 或以上,服务器停止响应或响应非常慢。
AWS CPU(具有 8 核 cpu 和 32GB RAM 的 5x 大型 aws ec2 实例)使用率为 12-20%。
应用程序在毫秒内通过 JWT 身份验证和 pm2 进行响应。
有很多查询依赖于以前的查询结果,所以我将所有函数创建为异步。
问题点:
每小时,所有用户(约 150 000 人)都可以编辑他们的内容(约 3k 并发直播)。
我的临时解决方案:
实施集群解决了我的问题,但在集群上 kill 没有关闭数据库连接。
我的疑惑:
当应用程序与集群一起正常工作时,为什么应用程序在相同配置的集群下无法正常工作?
async function authorize(req, res) {
//decode aes-128 request
let body = await helper.get_decoded_request(req);
if (!body) {
return res.status(200).json(await helper.error("Error occurs while decoding."));
}
const schema = joi.object({
"client_id": joi.string().min(1).required(),
"client_secret": joi.string().min(1).required()
});
try {
await schema.validateAsync(body);
}
catch (err) {
return res.status(200).json(await helper.error("Please send the valid request"));
}
try {
//data base update and add function that writen in other file
await user.update_user(data);
await match.add_transaction(data);
} catch (err) {
return res.status(200).json(await helper.error("Please send the valid request"));
}
return res.status(200).json(await helper.success("Token added successfully.", jsontoken));
}
模型文件代码:
const { read_db, write_db } = require("./database");
async function add_transaction(data) {
return await write_db.insert(data).table("users");
}
数据库文件:
var knex = require("knex");
const read_db = knex({
client: "mysql",
connection: {
database: process.env.SLAVE_MYSQL_DB,
host: process.env.SLAVE_MYSQL_HOST,
port: process.env.SLAVE_MYSQL_PORT,
user: process.env.SLAVE_MYSQL_USER,
password: process.env.MYSQL_PASSWORD
},
pool: { min: 1, max: 10 }
});
const write_db = knex({
client: "mysql",
connection: {
database: process.env.MYSQL_DB,
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD
},
pool: { min: 1, max: 10 }
});
module.exports = { read_db, write_db };
没有足够的信息来给出有关问题根本原因的任何答案,但这些如何开始解决问题的一般步骤可能会有所帮助。
第一个也是最重要的部分是在本地复制减速,运行 您的应用程序在分析器中实际找出代码的哪些部分实际上占用了所有 CPU。 运行 您的应用 node --inspect
允许您 运行 在 Chrome 浏览器分析器中分析应用的执行情况。
也听起来你 运行 只是一个单节点进程,所以很奇怪你如何能够从所有 8 个核心使用 100% CPU 而用户数量非常少(少于 1000?)...我想到的一件事是,如果您检查每个用户请求的密码哈希,它实际上可能会非常快地开始使用大量 CPU。
如果这确实是您可以实施的问题,例如 JSON 对您的应用程序的 Web 令牌支持,其中密码仅用于获取访问令牌,与密码相比,访问令牌的验证速度非常快身份验证。
当您的基本应用程序运行良好时,您应该开始考虑如何在单个实例上 运行 多个服务器进程,以便能够更好地利用所有 CPU 内核。
编辑:
听起来 5 核实例的 12-20% 大约是单核实例的 100%。所以你的应用程序似乎正在饱和 CPU。
关于堆使用情况,如果您分析应用程序,您可以看到是否是垃圾收集开始停止应用程序。
一个原因可能是您实际上制造了太多垃圾,这在某些时候开始损害性能。您也可以尝试将默认堆大小从 1.7GB 增加到 8GB node --max-old-space-size=8092
会有所帮助。
除了垃圾收集之外,例如,如果您从数据库返回数万行,只是将它们解析为 javascript 个对象,就可以使 CPU 饱和。因此,分析仍然是尝试找出正在发生的事情的正确方法。默认情况下,在 knex 中解析尤其是日期真的很慢(当它们被转换为 Date
对象时)。
我在节点中使用knex.js(有主从连接)来连接mysql。
我的代码在 150 个用户下工作正常,但是当并发用户增加时,PM2 中的堆使用率也达到 100% 或以上,服务器停止响应或响应非常慢。
AWS CPU(具有 8 核 cpu 和 32GB RAM 的 5x 大型 aws ec2 实例)使用率为 12-20%。
应用程序在毫秒内通过 JWT 身份验证和 pm2 进行响应。
有很多查询依赖于以前的查询结果,所以我将所有函数创建为异步。
问题点:
每小时,所有用户(约 150 000 人)都可以编辑他们的内容(约 3k 并发直播)。
我的临时解决方案:
实施集群解决了我的问题,但在集群上 kill 没有关闭数据库连接。
我的疑惑:
当应用程序与集群一起正常工作时,为什么应用程序在相同配置的集群下无法正常工作?
async function authorize(req, res) {
//decode aes-128 request
let body = await helper.get_decoded_request(req);
if (!body) {
return res.status(200).json(await helper.error("Error occurs while decoding."));
}
const schema = joi.object({
"client_id": joi.string().min(1).required(),
"client_secret": joi.string().min(1).required()
});
try {
await schema.validateAsync(body);
}
catch (err) {
return res.status(200).json(await helper.error("Please send the valid request"));
}
try {
//data base update and add function that writen in other file
await user.update_user(data);
await match.add_transaction(data);
} catch (err) {
return res.status(200).json(await helper.error("Please send the valid request"));
}
return res.status(200).json(await helper.success("Token added successfully.", jsontoken));
}
模型文件代码:
const { read_db, write_db } = require("./database");
async function add_transaction(data) {
return await write_db.insert(data).table("users");
}
数据库文件:
var knex = require("knex");
const read_db = knex({
client: "mysql",
connection: {
database: process.env.SLAVE_MYSQL_DB,
host: process.env.SLAVE_MYSQL_HOST,
port: process.env.SLAVE_MYSQL_PORT,
user: process.env.SLAVE_MYSQL_USER,
password: process.env.MYSQL_PASSWORD
},
pool: { min: 1, max: 10 }
});
const write_db = knex({
client: "mysql",
connection: {
database: process.env.MYSQL_DB,
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD
},
pool: { min: 1, max: 10 }
});
module.exports = { read_db, write_db };
没有足够的信息来给出有关问题根本原因的任何答案,但这些如何开始解决问题的一般步骤可能会有所帮助。
第一个也是最重要的部分是在本地复制减速,运行 您的应用程序在分析器中实际找出代码的哪些部分实际上占用了所有 CPU。 运行 您的应用 node --inspect
允许您 运行 在 Chrome 浏览器分析器中分析应用的执行情况。
也听起来你 运行 只是一个单节点进程,所以很奇怪你如何能够从所有 8 个核心使用 100% CPU 而用户数量非常少(少于 1000?)...我想到的一件事是,如果您检查每个用户请求的密码哈希,它实际上可能会非常快地开始使用大量 CPU。
如果这确实是您可以实施的问题,例如 JSON 对您的应用程序的 Web 令牌支持,其中密码仅用于获取访问令牌,与密码相比,访问令牌的验证速度非常快身份验证。
当您的基本应用程序运行良好时,您应该开始考虑如何在单个实例上 运行 多个服务器进程,以便能够更好地利用所有 CPU 内核。
编辑:
听起来 5 核实例的 12-20% 大约是单核实例的 100%。所以你的应用程序似乎正在饱和 CPU。
关于堆使用情况,如果您分析应用程序,您可以看到是否是垃圾收集开始停止应用程序。
一个原因可能是您实际上制造了太多垃圾,这在某些时候开始损害性能。您也可以尝试将默认堆大小从 1.7GB 增加到 8GB node --max-old-space-size=8092
会有所帮助。
除了垃圾收集之外,例如,如果您从数据库返回数万行,只是将它们解析为 javascript 个对象,就可以使 CPU 饱和。因此,分析仍然是尝试找出正在发生的事情的正确方法。默认情况下,在 knex 中解析尤其是日期真的很慢(当它们被转换为 Date
对象时)。