CPU spikes on insert/update when there's 'relatively large' number of documents in db


#1

Hi, everyone. Apologies in advance for my poor English.
I’m new to both Meteor and MongoDB. Any help would be greatly appreciated.

I am trying to implement a chat application.
First when the page is loaded, subscribe the latest 20 messages. Then every time when a user scrolls up, load 20 more older messages.
----- Problem -----
lies when a new message is added(inserted).
The CPU spikes up, and if the insertion occurs several times in a row within a short period of time, the CPU usage reaches almost full percentage. (without multi-core enabling in a multi core instance, ie. single-core, it reaches almost 50 percent, when using meteorhacks:cluster packages, it reaches almost 99 percent.)
This didn’t happen when there are only about 4,000 documents in Chats collection.
With only about 20,000 docs, the webserver CPU struggles a lot. MongoDB CPU is calm like a sleeping baby.

----- What I tried or looked into -----

  1. Created MongoDB index (boardId, chatRoomId, createdAt) and added ‘$hint’ to publication query for find: no noticeable difference
  2. Tried adding ‘{validate: false}’ to the insert query since I am using SimpleSchema: no noticeable difference. not sure if this is applied, despite no error or exception.
  3. Tried adding ‘{w: 0}’ to the insert query and also added &w=0 in the MONGO_URL variable: no noticeable difference. not sure meteor 1.1.0.3 even supports this. I searched for {w: 1} literal, a lot of meteor packages define DB writeConcern {w: 1} internally.
  4. ‘Chat messages’ have to be served in different ways: In the main chat room, as described above, there will be the latest 20 messages, and scroll back for more. There is a ‘Files’ tab and Searched Messages tab, these tabs serve all messages with the matching keywords. These are from the same collection with Chat messages, albeit separate pub/subs. I checked the CPU with all the other pub/subs commented out, but no improvement in CPU.

Any idea, please?

  • specifications and code snippets are as follows:
    ----- Specifications and code snippets -----
  • Webserver: AWS EC2 m4.large

  • MongoDB Server: AWS EC2 m4.large

  • Meteor version: 1.3.x(updated from 1.1.0.3 as of June 18th, 2016, still the same)

  • Collection name: ‘Chats’ defined using SimpleSchema/attachSchema

  • Subscription: Using SubsManager

  • Subscription.get(‘chat’).subscribe(‘chats’, boardId, currentMsgCount, chatRoomId);

  • Publication:
    Meteor.publish(‘chats’, function (boardId, currentCount, chatRoomId) {
    check(boardId, String);

    if (!this.userId) {
    return this.stop();
    }

    var self = this;
    var ready = false;
    var cursor;

    if (!chatRoomId) {
    var chatRoom = ChatRooms.findOne({‘boardId’: boardId});
    chatRoomId = chatRoom ? chatRoom._id : ‘’;
    }

    if (currentCount == null) {
    cursor = Chats.find({$query: { boardId: boardId, chatRoomId: chatRoomId }, $hint: {boardId: 1, chatRoomId: 1, createdAt: -1}/, $orderBy: {createdAt: -1}/},
    {limit: 20 });
    } else {
    var count = 20;
    if (0 >= currentCount)
    currentCount = count;

      cursor = Chats.find({$query: { boardId: boardId, chatRoomId: chatRoomId }, $hint: {boardId: 1, chatRoomId: 1, createdAt: -1}/*, $orderBy: {createdAt: -1}*/},
          {skip: currentCount, limit: count });
    

    }

    var cursorHandle = cursor.observe({
    added: function (doc) {
    self.added(’_chats’, doc._id, doc);
    },
    removed: function (doc) {
    self.removed(’_chats’, doc._id);
    },
    changed: function (doc) {
    self.changed(’_chats’, doc._id, doc);
    }
    });

    self.onStop(function () {
    cursorHandle.stop();
    });

    ready = true;
    self.ready();
    });

  • Chat message insert:
    Chats.insert({
    localId: localId,
    boardId: chatRoom.boardId,
    contentType: chatContentType,
    message: message,
    userId: userId,
    chatRoomId: chatRoomId});