
When working on one of the projects, we were faced with the task of implementing correspondence between registered users. At its core - it should be a chat, but at the same time you can communicate with it only with one person.
The potential load that such a chat should handle is about 10,000 simultaneous keep-alive connections. Each new message should be recorded in the main database, as well as in the "fast", the task of which is to keep only the actual part of correspondence between users, that is, to serve as a kind of "temporary" repository from which messages will be immediately delivered to the addressee.
MongoDB is well suited for this task. Since the replication process is well established in it, we can periodically poll the local.oplog. $ Main table with a separate daemon for the presence of new messages in it, and, if any, immediately deliver them to the address in JSON format. For steady work under load, there will be several such demons, several thousand copyists will be connected to each of them.
And here we faced the choice of what to use as a “fast server” on which the demons will be placed? For this, we tested two solutions: based on
phpDaemon and based on
Node.JS.
')
So, for starters, the complete chat architecture:
Fig. 1. Full chat structure
- Each new client entering into correspondence establishes a connection with one of the “fast” servers ( phpDaemon or Node.js ) and will receive messages from it.
- When sending a new message to the main server, it is recorded in a permanent database ( MySQL ), as well as in a kind of “fast” database (in this case MongoDB ), where only current correspondence will be stored, for example, in the last 24 hours.
- Master MongoDB writes changes to the local.oplog. $ Main collection for replication.
- The “fast servers” at this time are polling the “fast” database for new messages in it, and, if they exist, send them to the client to whom they are addressed.
In our test version there will be no permanent database, as well as user authorization. There will be only one “fast server” that will pick up new messages from the collection and send to all active clients at the moment (Figure 2).
Fig. 2. Simplified chat structure
The composition of the teams playing today:
Node.js command
- Node.js ( http://nodejs.org )
- The Socket.IO library for establishing connections between the client and Node.js ( http://socket.io )
- The christkv Node-mongo-native library for working with MongoDB from Node.js ( https://github.com/christkv/node-mongodb-native )
- Well, the oplog.js file from the same library for polling MongoDB for new messages ( https://github.com/christkv/node-mongodb-native/blob/master/examples/oplog.js )
PhpDaemon command
- phpDaemon ( http://phpdaemon.net )
- PhpDaemon scripts to establish a connection between the client and the server ( https://github.com/kakserpom/phpdaemon/tree/master/clientside-connectors/websocket )
- To work with MongoDB we will also use the built-in features of phpDaemon
- To poll the database, we will use the MongoNode application that we modified a little ( https://github.com/kakserpom/phpdaemon/blob/master/app-servers/MongoNode.php ), which does not write changes to Memcache, but sends them to all connected users.
Apache Benchmark meeting judge.
So, we launch one of the demons that polling MongoDB is running, and also “communicates” with incoming customers. Using the Apache Benchmark utility from another machine, we connect several
keep-alive clients (testing time is 20 seconds). At this time, a third-party form is starting to write messages to MongoDB. For each daemon and each number of keep-alive connections, we do
5 iterations , then we average the data and see the result.
Demon
| Complete requests
| Requests per second
| Time per request, ms
(across all concurrent requests)
| Min
request, ms
| Max Request, ms
|
---|
10 keep-alive connections
|
---|
phpDaemon
| 1147
| 54.36
| 18.440
| 21
| 7116
|
Node.JS
| 1285
| 64
| 15.618
| sixteen
| 9064
|
100 keep-alive connections
|
---|
phpDaemon
| 1543
| 75.15
| 13.313
| 22
| 12889
|
Node.JS
| 1284
| 64.12
| 15.765
| 17
| 13347
|
500 keep-alive connections
|
---|
phpDaemon
| 1365
| 67.73
| 14.824
| 15
| 15174
|
Node.JS
| 1236
| 61.71
| 16.611
| 23
| 16078
|
1000 keep-alive connections
|
---|
phpDaemon
| 1159
| 56.99
| 17.680
| nineteen
| 13103
|
Node.JS
| 1528
| 75.02
| 13.354
| 17
| 16785
|
Red marks “best performance”
As we can see, on a small number of simultaneous connections (10), Node.JS based chat works better. A larger number of requests are processed, respectively, the time for processing one request is reduced. True, phpDaemon has a shorter duration of the longest request, which, however, is not very important.
With an increase in the number of compounds to 100, and then 500, the picture changed. PhpDaemon has already come forward in terms of performance.
And with 1000 keep-alive connections, phpDaemona's indicators dropped, and Node.JS, on the contrary, increased, which resulted in a rather strong gap.