As the title suggests, this tutorial series teaches you how to handlift a Mongo agent. Tutorial is divided into two parts, copy set construction and capture package and code combat.

Q: What’s the use of this program?


A: The main purpose of the Mongo agent is to add A layer of protection to the back-end Mongo database, and prevent the database from being overwhelmed by too many requests.

In order to be closer to the actual production environment, I will explain the three parts in detail from the database replication set construction, Wireshark capture and parse mongo package and actual GO logic writing. The ultimate goal is to achieve a slightly stronger Mongo agent with read/write separation and automatic master/slave switchover.

The article may be a bit long, so please be patient.

Replication set construction

Copy set architecture I choose one (Primary), one (Secondary), one (Arbiter):

  • Primary node: there can be only one Primary node. The Primary node receives all write operations and synchronizes the data to other backup nodes
  • Secondary nodes: There can be multiple nodes to back up the data of the primary node and participate in the replication set election
  • Arbiter node (Arbiter): does not participate in the election, does not synchronize the data of the primary node, when the primary node fails, automatically elects one of the backup nodes as the primary node

Without further ado, let’s go straight to the config file:

## mgo_conf1.yaml
processManagement:
   fork: true  # Mongod is executed in the background as a daemon
net:
   bindIp: 127.0.0.1
   port: 21000
storage:
   dbPath: /data/db1 #mongo data file storage address
systemLog:
   destination: file
   path: "/data/db1/log/mongo.log" Path for storing system logs
   logAppend: true The log is appended to the file
storage:
   journal:
      enabled: true # log first
replication:
   replSetName: mongo_dal # Copy set name
#security:
# keyFile: / Users/geemo/etc/mongo/keyFile # used to replicate set between members of the security authentication, specify this field is equal to the authentication at the same time open the database
Copy the code

Net. port, storage.dbPath, systemlog. path.

Next, start the Mongod daemon based on the three configurations you have created:

$ mongod -f mgo_conf1.yaml
Copy the code

If the startup fails, check whether the port is occupied, or whether the specified storage path is not created at all.

After all the startup is successful, connect the first node with mongo Client.

$mongo 127.0.0.1:21000Copy the code

Next we need to initialize the replica set:

> rs. Initiate ({_id: 'mongo_dal', / / copy set of members: [{_id: 0, host: '127.0.0.1:21000}]})Copy the code

Add a backup node and a redundancy node:

> rs. Add (127.0.0.1: '22000') > rs. AddArb (127.0.0.1: '23000')Copy the code

Mongo_dal :PRIMARY> : mongo_dal:PRIMARY> : mongo_dal:PRIMARY> : mongo_dal:PRIMARY> At this point we can use rs.status() to check the replication set status.

From there, a simple replica set is set up.

The Wireshark captured and parsed the Mongo protocol package

A proxy can communicate with a client, encrypted or not, as long as it transparently transmits the data the client sends and the server responds to. Why bother to parse the Mongo protocol package?

At the beginning of this article, we said that I need to implement a Mongo agent with read/write separation and automatic master/slave switchover. The mongo agent realized by the simple pass-through mode only connects to the Primary node, and all read/write operations depend on the Primary node. Therefore, when the master node is suspended, our agent program cannot know who is the new master node, and still sends the client operation to the master node that has been suspended, which eventually leads to the client operation timeout and disconnection. Therefore, it is necessary to parse the Mongo protocol package.

Wireshark supports parsing the Mongo protocol.

The above screenshots are the packet capture results obtained by directly connecting the nodes of the replication set through mongo client. We found that only query (Opcode 2004) and Reply (Opcode 1) were completely parsed. No matter whether I conduct query, insert or delete operations later, Results are Unknown (Opcode 2010 or 2011 operations) and cannot be parsed.

This is totally different from so many opcodes introduced on the official website. At this time, I believe you have one MMP sentence that I do not know whether to say it or not. However, if you think carefully, we operate through the command line of mongo Client, and it is normal for it to encapsulate our operation and return result into Opcode 2010 (Command) and Opcode 2011 (Command Reply) packets, as shown in the following figure:

But even knowing this, not being able to parse it intuitively is a pain in the ass. Isn’t there any way to directly parse the data pointed out in the official protocol? No, we haven’t tried to see if the package sent by the Mongo driver will parse.

Using the Mongo node driver as an example, quickly write a test case:

'use strict'
const MongoClient = require('mongodb').MongoClient;

(async (a) = > {
  let db = await MongoClient.connect('mongo: / / 127.0.0.1:21000 / test');
  let coll = db.collection('cats');

  await coll.insert({name: 'yuyuan'});
  let res = await coll.find({}).toArray(a)
  console.log("res: ". res);
  await coll.remove({})
}) ();
Copy the code

The result is as follows:

According to the packet capture screenshot above, whether mongo client is directly connected or Mongo Node driver is connected, the first packet sent after the handshake is successful is isMaster packet. This request packet is used for the first connection to obtain replication set status information. The reason why isMaster packet is not the first packet captured in the screenshot above and the first packet captured is Unknown is that a large part of those Unknown packets are heartbeat packets that communicate among members of the replication set.

Secondly, after connecting through node driver mode, we open the connection continuously, and the driver will send an ISMaster heartbeat packet every once in a while to keep the connection alive. Note that this isMaster heartbeat packet, unlike the first isMaster heartbeat packet, does not carry client meta information.


Since then, the tutorial of replication set setup and package capture has been completed. In the next installment, I will introduce how to implement mongo agent with Golang. Please stay on track!