Мы пишем мессенджер для закрытого использования в нашем приложении. Плановая нагрузка текущей версии сотни пользователей, может тысяча-две.
1. В качестве БД я использую Монго. Сообщения пишутся в messages (связаны через chats_id с user_chats и uid c внешней таблицой в БД users). Приход сообщения на клиент создает шквал событий в ответ (пометка прочитанным). Понятно что нужно делать очереди. Как лучше сделать? Есть ли методы расставить очередям приоритеты?
2. Сколько вообще юзеров должен выдерживать сферический процесс ноды в вакууме? Сколько памяти при этом отжирать? Я использую pm2 для менеджинга процессов и node-ipc для броадкаста.
3. Куда обратиться, кого попросить оптимизировать запросы к БД. Сейчас там на скорую рукую написанные конструкции вида:
const loadUserChatsStatistic = async (chatIds, userId) => {
const startExecTime = new Date();
const userChats = await db().collection('user_chats').aggregate([
{ $match: { uid: userId, chats_id: { $in: chatIds.map(ObjectID) } } },
{ $lookup: { from: 'chats', localField: 'chats_id', foreignField: '_id', as: 'chat' } },
{ $unwind: '$chat' },
{ $lookup: { from: 'user_last_seen', localField: 'chats_id', foreignField: 'chats_id', as: 'last_seens' } },
]).toArray();
const chats = await Promise.all(userChats.map(async (userChat) => {
const usersCount = await db().collection('user_chats')
.find({ chats_id: userChat.chats_id }).count();
let unreadCountQuery = {};
if (userChat.last_read) {
unreadCountQuery = { _id: { $gt: userChat.last_read } };
} else {
unreadCountQuery = { _id: { $gt: userChat._id } };
}
const unreadCount = await db().collection('messages')
.find({ ...unreadCountQuery, chats_id: userChat.chats_id }).count();
const message = await db().collection('messages')
.findOne({ chats_id: userChat.chats_id }, { sort: { _id: -1 } }) || {};
return { ...userChat, usersCount, unreadCount, message };
}));
console.log('Execution time for loadUserChatsStatistic', new Date() - startExecTime);
return chats.sort((a, b) => {
if (!a.message._id) {
return true;
}
if (!b.message._id) {
return false;
}
return new Date(ObjectID(a.message._id).getTimestamp()) < new Date(ObjectID(b.message._id).getTimestamp());
});
};
Данный пример запрашивает все чаты, для каждого выбирает последнее сообщение, количество непрочитанных сообщений и последних замеченных пользователей. В мусе я бы это сделал одним конским запросом. Как лучше это сделать в Монго? Мой уровень с Монго пока что в районе среднего.
4. Сама архитектура. Сейчас действие с клиента приходит и попадает в хендлер, который разбирается что с ним делать и кого нужно известить об этом действии. Обычно хенлдер уведомляет соответствующий менеджер, а тот уже пишет в БД и при надобности уведомляет остальные процессы.