📜 ⬆️ ⬇️

Introduction to EagleMQ

EagleMQ is a new high-performance queue manager. The main tasks to be solved are the effective distribution of messages between processes, interprocessor communication and real-time notifications.

image


')
To solve the main problems there are 3 main primitives: queues (queues), routes (routes) and channels (channels).

Queues
Queues are the most important primitive. Queues allow you to store messages and issue them to the client in the same order in which they came (the FIFO principle).

Each queue must be declared before use. If the queue is not declared then the whole set of commands will not be available when working with it. Declaring allows you to track the use of the queue by customers and automatically delete it if it is not used by anyone and the AUTODELETE flag has been specified when creating the queue.

Messages may have a guaranteed delivery. To use guaranteed delivery, you need to specify the timeout of a nonzero return (in milliseconds) when retrieving a message from a queue with the .queue_pop command. Then, upon receipt of the message, confirm the delivery with the .queue_confirm command (using the unique message identifier). If the delivery is not confirmed at the specified time, the message will be returned to the queue as the oldest and issued to the next client as soon as possible.

Also messages can be with a limited shelf life (expiration time) and will be automatically deleted in case of expiration. The retention period is an attribute of the message being sent to the queue.

Queues have support for asynchronous delivery of incoming messages to clients. To use asynchronous delivery, you need to subscribe to the queue with the .queue_subscribe command, specifying the subscription mode in the flags. Queues have 2 subscription modes: message and notification.
In message mode, an event is sent to clients that contains the name of the queue to which the message arrived and the message itself. The message in the queue in this case does not fall, because it has already been sent to customers. If the queue is created with the ROUND_ROBIN flag, then the message will be sent to only one client each time, not all. The round-robin algorithm is used to distribute message sending to clients.
In the notification mode, all clients subscribed to the queue using this mode send a message containing only the queue name. This event will be sent to all subscribers of the queue with this mode, even if the message was sent to someone and did not get into the queue.
You can unsubscribe from asynchronous message delivery using the .queue_unsubscribe command.

When creating a queue, the name of the queue itself is indicated, the maximum number of messages that can be stored, the maximum message size and flags.
The maximum number of messages allows you to stop receiving new messages in the queue when the limit is reached.
The maximum message size allows you to disable sending messages with a large size. This parameter cannot have a value greater than 2147483647.

The queue supports 4 flags: AUTODELETE, FORCE_PUSH, ROUND_ROBIN, DURABLE.

The AUTODELETE flag is used to automatically delete a queue if it is not declared by anyone and has no subscribers.

The FORCE_PUSH flag allows you to send messages to the queue when the maximum number of messages is reached. This is achieved by deleting the older message to keep the new one.

The ROUND_ROBIN flag allows you to send a message to only one subscriber each time (see description above).

The DURABLE flag indicates that the queue is persistent and can be saved along with all messages in the repository.

List of commands for working with queues:



Routes
Routes are a secondary primitive for using queues. Routes allow you to associate queues with a specific key and organize fast and efficient message delivery.

To bind a queue with a key, use the .route_bind command. The command .route_push is responsible for sending the message to the route.

If when sending a message to a route, several queues were connected via a key, then the message is not copied (references counter), which allows speeding up the execution of the command and reducing memory consumption by the server.

The route supports 3 flags: AUTODELETE, ROUND_ROBIN, DURABLE.

The AUTODELETE flag is used to automatically delete a route if it does not have queue connections by key.

The ROUND_ROBIN flag allows, upon receipt of a message by a route, to send a message to only one queue connected by key. Round-robin is used to distribute messages across queues.

The DURABLE flag indicates that the route is persistent and can be saved with all keys in the repository.

List of commands for working with routes:


Channels
Channels are a primitive for convenient delivery of messages to customers in real time.

The principle of operation is that the client can subscribe to a specific topic with the .channel_subscribe command. When a message is sent to a channel by another client by the command .channel_publish, an event with a message will be sent to this topic to the client who subscribed to this topic.

You can also subscribe to a group of topics using a template with the .channel_psubscribe command. The format of the pattern is the glob-style pattern.

The channel supports 3 flags: AUTODELETE, ROUND_ROBIN, DURABLE.

The AUTODELETE flag is used to automatically delete a channel if it has no subscribers.

The ROUND_ROBIN flag allows you to send a message to only one of the many subscribers. To distribute messages between subscribers, the round-robin algorithm is used.

The DURABLE flag indicates that the channel is persistent and can be stored in the repository.

List of commands for working with channels:



Users
Each EagleMQ client must be authenticated in order to have command permissions. Without authentication, only one command is available - .disconnect.

EagleMQ can have multiple users, and each user can have their own set of permissions.

User rights have greater flexibility in customization. You can disable any command (except .disconnect) and therefore any primitive.

This can be useful in many cases. For example, you use the server as a task queue and you have many clients who create tasks, as well as many clients who process them. In this case, clients who create tasks are encouraged to allow the use of the .queue_push command only. Clients handlers will have enough rights only to the command .queue_pop. This will help to save data and clearly set the role of the client in the system.
It can also be useful if you set up a server on an external network (for example, public real-time distribution of earthquake alerts) and allow any user to connect directly (in this case, the user has sufficient rights to .channel_subscribe and .channel_psubscribe).

The list of commands for working with users:


EagleMQ currently has 44 teams in total. A list of all commands is in the documentation.

Performance
EagleMQ has a fairly high performance. Strict comprehensive measurements and comparative tests have not yet been carried out. This is largely due to the fact that some such systems have the ability to fine-tune the task (for example, RabbitMQ) and my experience in these systems does not allow to evaluate objectively.

Unlike other systems, EagleMQ almost does not need additional configuration affecting performance. It is also very unlikely to make a mistake when choosing a primitive or to use it incorrectly.

For testing, the test benchmark utility from libemq was used.

The essence of testing is to send messages to the queue with the command .queue_push. The application uses 50 threads. Local TCP sockets were used to connect to the server.

Intel Core (TM) i5-2450M CPU @ 2.50GHz
ClientsTotal MessagesMessage sizeTime, secondsReq / Sec
501,000,00010009.20108283.71
501,000,0001008.07123931.09
501,000,000ten8.05124300.80
50100,00010000.95105596.62
50100,0001000.85117096.02
50100,000ten0.81123304.56


Intel Core (TM) i5-3470 CPU @ 3.20GHz
ClientsTotal MessagesMessage sizeTime, secondsReq / Sec
501,000,00010005.19192566.92
501,000,0001004.47223613.59
501,000,000ten4.40227169.47
50100,00010000.53189393.94
50100,0001000.46219298.25
50100,000ten0.45220750.55


Persistence
Each EagleMQ primitive is persistent. Usually, to support this functionality, a primitive must be created with the DURABLE flag. Also in the configuration file must be specified the path to the repository and the save interval.

All data is permanently stored in RAM.

The principle of operation of the mechanism of preservation consists in cloning a process (fork) at a given interval and writing all the necessary data to a file. To save data at the request of the client there is a command .save.

All stored data is compressed by the liblzf library whenever possible.

Protocol
EagleMQ has its own binary protocol.

Binary protocols are almost always used in similar systems (AMQP, ZMQ) and help to achieve high performance when processing a request.

There are of course also disadvantages:
  1. Binary protocol is not human-readable.
  2. There may be difficulties in implementing client libraries in scripting programming languages.
  3. The need to use a compatible client binary protocol may change.


The EagleMQ protocol can be changed only in major releases.

Roadmap
  1. Improved support for packet aggregation to send multiple commands at once. Now such support is already available, but with packet loss.
  2. Documenting the binary protocol.
  3. Writing CLI to control EagleMQ using the command line.
  4. Development and maintenance of the site www.eaglemq.com .
  5. Support for little and big engian architectures.
  6. Coverage of all functionality tests.


Anyone can ask me your question in the comments or by mail. I will be glad to answer.

Project repository: GitHub

Source: https://habr.com/ru/post/185422/


All Articles