0

I'm trying out MassTransit and compared to "official" library it's very slow when using publisher confirms. I'm getting around 40 msg/s compared to 18.000 msgs/s for official library. I also tried the MassTransit benchmark and using "dotnet run -f netcoreapp3.1 -c Release -- --count=100000 --prefetch=1000 --clients=100" I get 5284 msg/s, but it is not using publisher confirms. I suspect this is because MassTransit is doing synchronous confirmations. Is there a way to speed up MassTransit? I don't think 40 msg/s is going to be enough throughput for us. My code for MassTransit:

namespace MassTransitTest
{
  class Program
  {
    static async Task Main()
    {
      var busControl = Bus.Factory.CreateUsingRabbitMq();

      var source = new CancellationTokenSource(TimeSpan.FromSeconds(10));

      await busControl.StartAsync(source.Token);
      var sendEndpoint = await busControl.GetSendEndpoint(new Uri("queue:DefaultQueue"));

      try
      {

        Console.WriteLine("Sending value");

        for (int i = 0; i < 10000; i++)
        {
          await sendEndpoint.Send<ValueEntered>(new
          {
            Value = "Test"
          });
        }
      }
      finally
      {
        await busControl.StopAsync();
      }
    }
  }
}

My code for "official" library:

namespace OfficialLibraryTest
{
  class Message
  {
    public string Text { get; set; }
  }
  class Program
  {
    static void Main(string[] args)
    {
      ConcurrentDictionary<ulong, Message> outstandingConfirms = new ConcurrentDictionary<ulong, Message>();
      Serializer serializer = new Serializer(new PropertiesExtractor(), options: GroBufOptions.WriteEmptyObjects);

      ConnectionFactory factory = new ConnectionFactory();
      factory.AutomaticRecoveryEnabled = true;
      factory.HostName = "localhost";

      IConnection publishConnection = factory.CreateConnection();
      IModel channel = publishConnection.CreateModel();
      try
      {
        channel.ConfirmSelect();

        channel.BasicAcks += (sender, ea) =>
        {
          if (ea.Multiple)
          {
            var confirmed = outstandingConfirms.Where(k => k.Key <= ea.DeliveryTag);
            foreach (var entry in confirmed)
            {
              outstandingConfirms.TryRemove(entry.Key, out _);
            }
          }
          else
          {
            outstandingConfirms.TryRemove(ea.DeliveryTag, out _);
          }
        };

        channel.BasicNacks += (sender, ea) =>
        {
          if (ea.Multiple)
          {
            var confirmed = outstandingConfirms.Where(k => k.Key <= ea.DeliveryTag);
            foreach (var entry in confirmed)
            {
              outstandingConfirms.TryRemove(entry.Key, out _);
            }
          }
          else
          {
            outstandingConfirms.TryRemove(ea.DeliveryTag, out _);
          }
        };

        IBasicProperties props = channel.CreateBasicProperties();
        props.DeliveryMode = 2;

        for (int i = 0; i < 1000000; i++)
        {
          Message message = new Message { Text = "Test" };
          ulong nextSeqNumber = channel.NextPublishSeqNo;
          byte[] messageBodyBytes = serializer.Serialize(message);
          outstandingConfirms.TryAdd(nextSeqNumber, message);
          channel.BasicPublish("DefaultExchange", "DefaultQueue", props, messageBodyBytes);
        }
      }
      finally
      {
        channel.Dispose();
        publishConnection.Dispose();
      }
    }
  }
}
TheBlaze
  • 1
  • 2
  • Does this answer your question? [Masstransit use RabbitMQ is very slow performance?](https://stackoverflow.com/questions/29748448/masstransit-use-rabbitmq-is-very-slow-performance) – Alexey Zimarev Apr 28 '21 at 16:03
  • 1
    Even _with_ publisher confirmation (which you can turn on in benchmark using `--confirm=true`), you'll likely get _much_ higher throughput. Your test case is flawed by awaiting each Send. You should add the tasks to a list, similar to how you're adding the outstanding confirms to the collection in your second case and then use `Task.WhenAll`. – Chris Patterson Apr 28 '21 at 16:22
  • Thank you for your suggestion! The use case is sending notifications (SMS). The input comes from users (when they perform a certain action). We need confirms, because SMS-es need to be sent. If I make a list from the tasks, how do I know which task failed (RabbitMQ was not accessible)? In the second example I would retry all outstanding confirms. Do you have an example of such implementation? – TheBlaze Apr 28 '21 at 17:46

0 Answers0