Node.js & the event loop :
To prevent flooding the action queue by multiple users playing the same game, I would divide the MMO into game rooms or game regions / zones.
Dividing the game server into independent threads that could even run on independent machines.
A login socket server
for handling new incoming clients
with a db reader & writer process
for db queries & updates
For each game room available a zone socket server
(for communicating with clients that are interacting in that specific zone : action requests & action result emission)
with a corresponding forked zone manager process
(for validating requests & result generation)
Maybe you like some personal notes...
(maybe a chance for this model to be reviewed & evaluated by the opinions of other devs)
<client> Socket.emit('login_request', {credentials})
<server> Receive login request [send to db_rwp]
<db_rwp> Validate login_request {credentials} :: if valid fetch client (user) data & insert entry in active_sessions db table
<server> Evaluate user.region : prepare region for client (ipc between procs with the folowwing data) {user:'{userData}', secret:'%ha$h%', csid:'login_handshake'}
<region> Store @ incomingClients['%ha$h%'] ) = '{userData}'
Inform to login.server {action:'prepared', region:'region_id', csid:'login_handshake'}
<server> Inform Database then client
<db_rwp> UPDATE sessions WHERE socket_id = login_handshake
<server> Now inform the client :: io.to(data.csid).emit('valid_login', user:'{userData}', region:{id:'region_id', port:'region_port', secret:'%ha$h%'})
<client> Load region splash screen while socket disconnects from <server> and connects to <region> (server:region.port)
<region> On client connect, return a client probe (requesting the secret hash)
<client> Client is probed, return a Socket.emit('region_snapshot_request', '%hash%');
<region> if incomingClients['%ha$h%'] is found valid
return the snapshot to the incomingClient
notify the incomingClient to the activeClient[]
activeClient['region_handshake'] = incomingClients['%ha$h%']
then destroy the incomingClients['%ha$h%']
Inform to login.server {action:'completed', region:'region_id', old_csid:'login_handshake', csid:'region_handshake'}
<server> Inform handshake changes to Database
<db_rwp> UPDATE sessions SET socket_id=csid WHERE socket_id=old_csid
Here I gave an answer that contains a client model that will only render what the server emits.
https://gamedev.stackexchange.com/a/116531/52482