Какой подход к архитектуре мессенджера является оптимальным?

Мы пишем мессенджер для закрытого использования в нашем приложении. Плановая нагрузка текущей версии сотни пользователей, может тысяча-две.

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. Сама архитектура. Сейчас действие с клиента приходит и попадает в хендлер, который разбирается что с ним делать и кого нужно известить об этом действии. Обычно хенлдер уведомляет соответствующий менеджер, а тот уже пишет в БД и при надобности уведомляет остальные процессы.
  • Вопрос задан
  • 549 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы