Achieving High Performance Queue's with Symfony Messenger

Achieving High Performance Queue's with Symfony Messenger

Introduction

Symfony’s Messenger component is a powerful tool for adding message queuing to your application. It allows you to send messages asynchronously, which can help with issues such as scalability and performance. In this blog post, we’ll be looking at how well different transports perform in the case of high volumes of messages.

Environment setup

For this test, we used an identical version of the project, with the only difference being the transport being used. The following transport setups were used:

MySQL Setup

MySQL 5.7 (docker image: mysql:5.7)
MySQL 8.0 (docker image: mysql:8.0)

MariaDB Setup

MariaDB 10.10.2 (docker image: mariadb:10.10.2)

RabbitMQ Setup

RabbitMQ 3.11 (docker image: rabbitmq:3.11.7)

Note: For RabbitMQ, we also had to install the amqp php lib.

Test setup

In order to test the performance of creating and consuming messages, we used the following methods:

Creation of messages

To test the performance of creating messages, we used a full import of data. Each entry generated a single message, for a total of 977,107 messages.

Consuming Messages

To test the performance of consuming messages, we used several scenarios. For message consumption, we used several cases:

  • a single consumer, consuming 1000 messages
  • 2 consumers running concurrently, consuming 1000 messages each
  • 5 consumers running concurrently, consuming 1000 messages each
  • a single consumer, consuming 10.000 messages
  • 2 consumers running concurrently, consuming 10.000 messages each A message consumption includes taking the message payload, transforming it to an entity, and saving it to the database.

Results

Let’s check the results!

Creation of message

  MySQL 5.7 MySQL 8.0 RabbitMQ MariaDB
Run #1 56:30.29 total 1:12:49.59 total 7:32.67 total 46:21.73 total
Run #2 51:59.19 total 1:13:37.70 total cpu 8:06.91 total 44:12.87 total
         
CPU Usage (idle / processing) 1% / 30% 3% / 42% 1% / 10% 1% / 22%
Conclusion ~ 288 /second ~ 224 /second ~ 2090 /second ~ 362 /second

As we can see from the table above, RabbitMQ was easily the fastest transport for creating messages, followed by MariaDB and then MySQL 5.7 and MySQL 8.0.

Consuming messages

1000 Messages, single consumer

  MySQL 5.7 MySQL 8.0 RabbitMQ MariaDB
Run #1 cpu 1:02.28 total cpu 51.510 total cpu 36.683 total 41.547 total
Run #2 cpu 1:01.67 total cpu 53.803 total cpu 34.752 total 50.640 total
         
Conclusion ~ 16,5 / second ~ 19,2 / second ~ 28,5 / second ~ 22 / second

1000 Messages, double consumer

  MySQL 5.7 MySQL 8.0 RabbitMQ MariaDB
Run #1 1:16.38 total 1:27.26 total 39.514 total 1:04.17 total
Run #2 1:16.47 total 1:27.45 total 35.016 total 55.424 total
         
CPU Usage (idle / processing) 1% / 45% 2% / 60% 1% / 3% 1% / 20%
Conclusion ~ 13 / second / consumer ~ 11,5 / second / consumer ~ 27 / second / consumer ~ 16 / second / consumer
  ~ 26 / second ~ 23 / second ~ 54 / second ~ 33 / second
💡 We can note that MySQL 8 starts to see a heavy degradation in performance when running multiple runners.

1000 Messages, 5 consumers

  MySQL 5.7 MySQL 8.0 RabbitMQ MariaDB
Run #1 1:46.86 total 2:29.61 total 1:01.47 total 1:35.31 total
Run #2 1:44.89 total 2:11.17 total 1:05.53 total 1:40.15 total
         
CPU Usage (idle / processing) 1% / 100% 2% / 100 % 1% / 4% 1% / 30 %
Conclusion ~ 9.5 /second/consumer ~ 6.8 /second/consumer ~ 16 /second/consumer ~ 10,3 /second/consumer
  ~ 47,7 /second ~ 34 /second ~ 82 /second ~ 51,5 /second
💡 Running 2 consumers on a RabbitMQ queue, has the same performance as running 5 consumers on a MySQL queue.

10.000 Messages, single consumer

  MySQL 5.7 MySQL 8.0 RabbitMQ MariaDB
Run #1 10:23.81 11:01.54 7:05.40 7:24.25
         
Conclusion ~ 16 / second ~ 15 / second ~ 23,5 / second ~ 22,5 / second

10.000 Messages, double consumer

  MySQL MySQL 8.0 RabbitMQ MariaDB
Run #1 11:18.40 15:20.12 7:15.59 10:48.25
         
Conclusion ~ 14,7 / second / consumer ~ 11 / second / consumer ~ 23 / second / consumer ~ 15,5 / second / consumer
  ~ 29,4 / second ~ 22 / second ~ 46 / second ~ 31 / second

Conclusion

From our benchmark, we can see that RabbitMQ was the fastest transport for both creating and consuming messages. It had the best performance in all the scenarios we tested, followed by MariaDB, MySQL 5.7 and MySQL 8.0.

It’s important to note that the results of this benchmark may vary depending on the specific use case and configuration of your application.

it’s also important to consider the infrastructure and resources available for your application. If your application is running on a cloud-based infrastructure, for example, you may find it easier to scale up RabbitMQ instances than to scale up a database.

In conclusion, this benchmark showed that RabbitMQ is the best transport for high volumes of messages, but the decision on which transport to use should be based on the specific needs of your application and the resources available. It’s important to weigh the benefits and limitations of each transport before making a final decision.

Sources