K
K
Konstantin2018-07-16 22:49:31
MongoDB
Konstantin, 2018-07-16 22:49:31

What approach to messenger architecture is optimal?

We are writing a messenger for private use in our application. The planned load of the current version is hundreds of users, maybe a thousand or two.
1. I use Mongo as a database. Messages are written to messages (linked via chats_id to user_chats and uid to an external table in the users database). The arrival of a message on the client creates a flurry of events in response (marking as read). It is clear that you need to queue. How to do it better? Is there a way to prioritize queues?
2. How many users should the spherical process of a node in a vacuum withstand? How much memory does it consume? I use pm2 for process management and node-ipc for broadcast.
3. Where to turn, whom to ask to optimize queries to the database. Now there are hastily written constructions of the form:

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());
  });
};

This example queries all chats, for each selects the last message, the number of unread messages and the last seen users. In Musa, I would do it with one horse request. What is the best way to do this in Mongo? My level with Mongo so far is about average.
4. The architecture itself. Now the action from the client comes and gets into the handler, which understands what to do with it and who needs to be notified about this action. Usually, the handler notifies the appropriate manager, who already writes to the database and, if necessary, notifies other processes.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question