Я смотрю на поддержку веб-сокетов AWS API Gateway, о которой было объявлено относительно недавно -
https://aws.amazon.com/blogs/compute/announcing-websocket-apis-in-amazon-api-gateway/
У них есть образец сервера чата -
https://github.com/aws-samples/simple-websockets-chat-app/blob/master/sendmessage/app.js
Который у меня работает, очень красиво.
Если вы отправляете сообщение, sendmessage
Lambda передает это сообщение всем подключенным пользователям с помощью следующего:
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0
const AWS = require('aws-sdk');
const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10' });
const { TABLE_NAME } = process.env;
exports.handler = async (event, context) => {
let connectionData;
try {
connectionData = await ddb.scan({ TableName: TABLE_NAME, ProjectionExpression: 'connectionId' }).promise();
} catch (e) {
return { statusCode: 500, body: e.stack };
}
const apigwManagementApi = new AWS.ApiGatewayManagementApi({
apiVersion: '2018-11-29',
endpoint: event.requestContext.domainName + '/' + event.requestContext.stage
});
const postData = JSON.parse(event.body).data;
const postCalls = connectionData.Items.map(async ({ connectionId }) => {
try {
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(`Found stale connection, deleting ${connectionId}`);
await ddb.delete({ TableName: TABLE_NAME, Key: { connectionId } }).promise();
} else {
throw e;
}
}
});
try {
await Promise.all(postCalls);
} catch (e) {
return { statusCode: 500, body: e.stack };
}
return { statusCode: 200, body: 'Data sent.' };
};
Теперь, к сожалению (к счастью ??), у меня есть фон Python / Erlang, а не Javascript / nodejs. Итак, я могу видеть, что некоторые из них делают, а именно перебирают соединения в таблице DynamoDB и отправляют ответ каждому. Он также выглядит так, как будто он работает асинхронно, благодаря использованию ключевых слов async
и await
, которые, как я полагаю, являются обещаниями. Но я не могу быть уверен , что это работает асинхронно, и это меня беспокоит ... если у меня есть одна лямбда, которая выполняет итерацию по большому количеству соединений и выполняет синхронные вызовы, это не сработает. .
Итак - особенно в отношении этой части кода -
const postCalls = connectionData.Items.map(async ({ connectionId }) => {
try {
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(`Found stale connection, deleting ${connectionId}`);
await ddb.delete({ TableName: TABLE_NAME, Key: { connectionId } }).promise();
} else {
throw e;
}
}
});
Могу ли я быть уверен, что это отправляет postData
для всех подключений полностью асинхронным образом? Должен ли я беспокоиться о том, что одна лямбда может отправить сообщения тысячам клиентов?
1 ответ
Это не зря называется простым -websockets-chat-app :)
Читая код, он делает именно то, что вас беспокоит. Только один экземпляр лямбда отправит сообщение для всех подключений.
Но это чат, обычно бывает, что у вас тысячи пользователей?
Также похоже, что он работает асинхронно с использованием ключевых слов async и await, которые, я думаю, являются обещаниями.
Да, он работает асинхронно, но лямбда будет выполняться до тех пор, пока все сообщения не будут отправлены.
Около
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();
Это оказывает очень небольшое давление на саму лямбду, выполняя только удаленный вызов за раз. И будучи асинхронным, он не ждет ответа, а продолжает отправлять все больше и больше.
(примечание: в этом случае я бы использовал forEach
вместо map
)
Решение для чата с абсурдно высоким трафиком:
- В DispatcherLambda разделите сканирование из TABLE_NAME на несколько фрагментов, отправьте их в очередь SQS и подпишите на него Lambda. Таким образом, будет несколько контейнеров, выполняющих этот код (в зависимости от выбранной вами степени детализации).
Похожие вопросы
Новые вопросы
node.js
Node.js - это неблокирующая асинхронная среда ввода-вывода, основанная на событиях, использующая движок Google V8 JavaScript и библиотеку libuv. Он используется для разработки приложений, которые интенсивно используют возможность запуска JavaScript как на клиенте, так и на стороне сервера, и, следовательно, выигрывают от повторного использования кода и отсутствия переключения контекста.