简体   繁体   English

异步在.NET ActiveMQ中发送

[英]Async sends in .NET ActiveMQ

I'm looking to increase the performance of a high-throughput producer that I'm writing against ActiveMQ, and according to this useAsyncSend will: 我希望提高针对ActiveMQ编写的高吞吐量生产者的性能,根据 useAsyncSend将:

Forces the use of Async Sends which adds a massive performance boost; 强制使用异步发送,从而大大提高了性能; but means that the send() method will return immediately whether the message has been sent or not which could lead to message loss. 但是意味着send()方法将立即返回是否已发送消息,这可能导致消息丢失。

However I can't see it making any difference to my simple test case. 但是我看不到它对我的简单测试用例有什么影响。

Using this very basic application: 使用这个非常基本的应用程序:

const string QueueName = "....";
const string Uri = "....";

static readonly Stopwatch TotalRuntime = new Stopwatch();

static void Main(string[] args)
{
    TotalRuntime.Start();
    SendMessage();
    Console.ReadLine();
}

static void SendMessage()
{
    var session = CreateSession();
    var destination = session.GetQueue(QueueName);
    var producer = session.CreateProducer(destination);

    Console.WriteLine("Ready to send 700 messages");
    Console.ReadLine();

    var body = new byte[600*1024];

    Parallel.For(0, 700, i => SendMessage(producer, i, body, session));         
}

static void SendMessage(IMessageProducer producer, int i, byte[] body, ISession session)
{
     var message = session.CreateBytesMessage(body);

     var sw = new Stopwatch();
     sw.Start();
     producer.Send(message);
     sw.Stop();

     Console.WriteLine("Running for {0}ms: Sent message {1} blocked for {2}ms", 
            TotalRuntime.ElapsedMilliseconds, 
            i, 
            sw.ElapsedMilliseconds);
}       

static ISession CreateSession()
{
     var connectionFactory = new ConnectionFactory(Uri)
                                    {
                                        AsyncSend = true,
                                        CopyMessageOnSend = false
                                    };
     var connection = connectionFactory.CreateConnection();
     connection.Start();
     var session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
     return session;
}

I get the following output: 我得到以下输出:

Ready to send 700 messages

Running for 2430ms: Sent message 696 blocked for 12ms
Running for 4275ms: Sent message 348 blocked for 1858ms
Running for 5106ms: Sent message 609 blocked for 2689ms
Running for 5924ms: Sent message 1 blocked for 2535ms
Running for 6749ms: Sent message 88 blocked for 1860ms
Running for 7537ms: Sent message 610 blocked for 2429ms
Running for 8340ms: Sent message 175 blocked for 2451ms
Running for 9163ms: Sent message 89 blocked for 2413ms
.....

Which shows that each message takes about 800ms to send and the call to session.Send() blocks for about two and a half seconds. 这表明每条消息的发送时间约为800毫秒,对session.Send()的调用将阻塞大约两分半秒。 Even though the documentation says that 即使文档说

"send() method will return immediately" “ send()方法将立即返回”

Also these number are basically the same if I either change the parallel for to a normal for loop or change the AsyncSend = true to AlwaysSyncSend = true so I don't believe that the async switch is working at all... 如果我将并行更改为普通的for循环或将AsyncSend = true更改为AsyncSend = trueAlwaysSyncSend = true这些数字也基本相同,因此我完全不相信异步开关可以正常工作...

Can anyone see what I'm missing here to make the send asynchronous? 谁能看到我在这里缺少的内容来使发送异步?


After further testing: 经过进一步测试:

According to ANTS performance profiler that vast majority of the runtime is being spent waiting for synchronization. 根据ANTS性能分析器的说法,绝大多数运行时都在等待同步上。 It appears that the issue is that the various transport classes block internally through monitors. 看来问题在于各种传输类都通过监视器在内部进行阻止。 In particular I seem to get hung up on the MutexTransport 's OneWay method which only allows one thread to access it at a time. 特别是,我似乎迷上MutexTransport的OneWay方法,该方法一次只允许一个线程访问它。

It looks as though the call to Send will block until the previous message has completed, this explains why my output shows that the first message blocked for 12ms, while the next took 1858ms. 似乎对Send的调用将阻塞,直到上一条消息完成为止,这解释了为什么我的输出显示第一条消息阻塞了12ms,而下一条消息占用了1858ms。 I can have multiple transports by implementing a connection-per-message pattern which improves matters and makes the message sends work in parallel, but greatly increases the time to send a single message, and uses up so many resources that it doesn't seem like the right solution. 通过实现每个消息的连接模式,我可以进行多种传输,这种模式可以改善事务并使消息并行发送,但是大大增加了发送单个消息的时间,并且占用了太多资源,看起来好像不一样正确的解决方案。

I've retested all of this with 1.5.6 and haven't seen any difference. 我已经用1.5.6重新测试了所有这些,并且没有发现任何区别。

As always the best thing to do is update to the latest version (1.5.6 at the time of this writing). 与往常一样,最好的办法是更新到最新版本(在撰写本文时为1.5.6)。 A send can block if the broker has producer flow control enabled and you've reached a queue size limit although with async send this shouldn't happen unless you are sending with a producerWindowSize set. 如果代理启用了生产者流控制并且您已经达到队列大小限制,则发送可能会阻塞,尽管使用异步发送不会发生这种情况,除非您设置了producerWindowSize集。 One good way to get help is to create a test case and submit it via a Jira issue to the NMS.ActiveMQ site so that we can look into it using your test code. 获得帮助的一种好方法是创建一个测试用例,并通过Jira问题将其提交到NMS.ActiveMQ站点,以便我们可以使用您的测试代码对其进行调查。 There have been many fixes since 1.5.1 so I'd recommend giving that new version a try as it could already be a non-issue. 自1.5.1以来,已经进行了许多修复,因此,我建议您尝试一下该新版本,因为它可能已经不是问题了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM