问题描述
我正在建立一个人们可以一起玩棋盘游戏的网站。他们的动作通过一个简单的网络套接字传递,该网络套接字仅将消息中继到其他客户端。我曾经在节点中实现websocket并从AWS EC实例为其提供服务,但我决定尝试移至无服务器Websocket API。
我遵循了this tutorial,该描述几乎与我的用例相同。
更改为无服务器后,延迟显着增加(从
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();
let active_connnections = null;
const get_active_connections = async () => {
const data = await dynamodb.scan({ TableName: process.env.TABLE_NAME }).promise();
active_connnections = data.Items.map(id => id.id.S);
};
let endpoint = null;
const connect_endpoint = async () => {
endpoint = new AWS.ApiGatewayManagementApi({endpoint: process.env.ENDPOINT});
};
const init = async (myConnectionId) => {
var promisesToRun = [];
if ((!active_connnections) || !active_connnections.includes(myConnectionId)) {
promisesToRun.push(get_active_connections());
}
if (!endpoint) {
promisesToRun.push(connect_endpoint());
}
await Promise.all(promisesToRun);
};
const send_message = async (connectionId,message) => {
try {
await endpoint.postToConnection({ ConnectionId: connectionId,Data: JSON.stringify(message)}).promise();
} catch (e) {
if (e.statusCode == 410) {
await dynamodb.deleteItem({ TableName: process.env.TABLE_NAME,Key: { id: {S: connectionId } } } ).promise();
} else {
throw e;
}
}
};
exports.handler = async (event,context) => {
await init(event.requestContext.connectionId);
const postCalls = items.map(async (id) => send_message(id,JSON.parse(event.body)));
await Promise.all(postCalls);
在我的lambda不能冷启动到可接受水平的情况下,这减少了延迟。但是,lambda的破坏速度相对较快(打开连接后的1-2秒)。
还有其他技巧或解决方案可以使我将等待时间保持在较低水平吗?
解决方法
我可以看到您正在使用DynamoDB扫描,这肯定会影响应用程序的性能。
DynamoDB在尝试任何读取操作时会使用RCU(读取容量单位),为了达到最终的一致性,将为2个4KB项消耗1个RCU,而对于强一致性则将消耗1个RCU。
重要的是要了解,当您执行扫描时,DynamoDB的后端会获取表中的每个项目,然后再应用过滤器。这将消耗整个表大小的RCU。
要解决这个问题,人们可以构建其DynamoDB表,以按分区和可选的排序键来检索项目。相反,使用GetItem函数将仅将RCU用于返回的项目。
性能问题很可能是由于您可用的RCU总量已耗尽,您可以通过查看相关DynamoDB的读取限制来在CloudWatch中进行验证。