3

I have an interesting situation on my hands. For a few years now we've had a WCF service that runs on an IIS box on our network that we use for logging. Applications use basicHttpBinding to send log messages and it logs them to a database. Most of the logging from all other applications is limited to a few dozen logs per operation. Recently we've ported another application to use this logging service. This application logs quite a bit more aggressively than any of the other clients for our logging service. It has an operation that during its course could log over 100,000 messages (this is for importing 100,000 records via CSV file).

In trying to find a way to make this run more efficiently it was suggested that I try MSMQ to queue the log requests and forward them on to the service instead of having the application communicate directly with the logging service (the request was being sent in a separate thread for performance purposes). In this way the application isn't blocked while the log is being written. I have implemented a proof of concept for this MSMQ solution on my local machine but as I have never used MSMQ before, and as I am only now learning what its place is technologically, I'm finding myself with a lot of questions and few answers. I'm hoping someone can point me to some concise information on how MSMQ works so that I can better debug this proof of concept I have written.

What I'm seeing after implementing MSMQ:

  • My application that sends the logs to MSMQ returns almost immediately (rather than waiting for the log to be committed) which is what I want.
  • Even though I sent 1000 logs to the MSMQ application in fewer than 30 seconds, it takes several minutes for all 1000 logs to make it to the database. It appears as though my queue has some sort of throttling enabled where it is holding back the log requests but I don't know how / where to check that.
  • If I use net.tcp on the server receiving the logs from the MSMQ service I get a ton of service timeout errors and only 90% (or so) of the logs make it to the database but if I use basicHttpBinding it works reliably.

Here is the code in my MSMQ service:

public void QueueLog(Log log)
{
    try
    {
        ServiceClient writeLog = getLoggingService();

        string exceptionText = log.Exception == null ? string.Empty : log.Exception.ToString();
        writeLog.WriteCompatibleLog(log.LoggerName, (LoggingService.Logging.LogType)log.LogType, exceptionText, log.Message, log.ApplicationName, Utility.GetAssemblyVersion(Assembly.GetCallingAssembly()),
            Utility.GetFirstIPAddress(), Utility.GetHostName(), log.Category);
    }
    catch (Exception ex)
    {
        Debug.WriteLine("LoggingServiceWrapper.DotNet Error\n\n" + ex.GetBaseException().Message + "\n\n" + ex.GetBaseException().StackTrace);
    }
}

private ServiceClient getLoggingService()
{
    return new ServiceClient(new BasicHttpBinding(), new EndpointAddress("http://MyServer/Service.svc"));

}

Here is the code of me creating the MSMQ service

if (!MessageQueue.Exists(Properties.Settings.Default.QueueName))
{
    MessageQueue.Create(Properties.Settings.Default.QueueName, true);
}

ServiceHost serviceHost = new ServiceHost(typeof(LoggingServiceQueue.LoggingServiceQueue), new Uri(Properties.Settings.Default.Address));
{
    serviceHost.Open();

    Console.ReadLine();

    serviceHost.Close();
}

Here is the code in the application I use to call the MSMQ service:

LoggingServiceQueueClient client = new LoggingServiceQueueClient(new NetMsmqBinding(NetMsmqSecurityMode.None), new EndpointAddress("net.msmq://localhost/private/Logging"));

client.QueueLog(new LoggingServiceQueue.Log
{
    LoggerName = loggerName,
    LogType = (LoggingServiceQueue.LogType)logType,
    ApplicationName = applicationName,
    Category = category,
    Exception = exception,
    Message = message,
    SourceHostName = Utility.GetHostName(),
    SourceIp = Utility.GetFirstIPAddress(),
    Version = Utility.GetAssemblyVersion(callingAssembly)
});

I appreciate any help someone can provide. I'm a little lost on exactly what set of features are available to me using MSMQ. I have done 6 or so hours of research via google. Most docs I have found are pretty old (2007) and are a tough read. Perhaps they are expecting me to have some baser level of knowledge on the subject.

omatase
  • 1,551
  • 1
  • 18
  • 42

1 Answers1

1

What you're seeing (if you're using net.msmq binding on your WCF) is what is designed to happen.

MSMQ, as a store-and-forward facility, will store messages in a queue at the sending client and the receiving server until either network or processing bandwidth is available. What this does is take load off the client (as you've observed) by making the process asynchronous.

You can view the statuses of the queues using Performance Monitor, the number of messages in the outbound queue (at the client) and the server queue are written to performance counters in realtime and can be viewed and/or logged.

If the performance is sub-optimal, you could look to change the WCF throttling settings to allow more concurrent connections in your service behaviour.

e.g.

<serviceThrottling
         maxConcurrentCalls="20"
         maxConcurrentSessions="20"
         maxConcurrentInstances="20"
       />

DaveRead
  • 3,371
  • 1
  • 21
  • 24
  • Do you know what the performance overhead is supposed to be like communicating to a local MSMQ service? I would imagine that since offloading processing is its main purpose it would be fairly quick. The service throttling you put above, are you suggesting that for the web service or the MSMQ service? – omatase May 16 '11 at 23:04
  • For the client the overhead should be in the order of ten of milliseconds, as there is no waiting for a response required. The throttling parameters should be applied at the WCF service endpoint if you're exposing it over MSMQ. – DaveRead May 17 '11 at 07:33
  • Something must be wrong here. 100,000 log requests successfully queued in less than one hour, however the MSMQ app is still sending logs to the WCF service 10 hours later! I know the logs make it to the MSMQ app fast so that's not the problem. For some reason though the MSMQ app doesn't want to push the logs as quickly as is possible. I know the bottleneck isn't the WCF logging service on the other server. 100,000 log entries happen much more quickly than that without the MSMQ go between. – omatase May 17 '11 at 18:02
  • How is your server receiving messages from the queue? Is it running on a timer or it is registered as a delegate on the ReceiveCompleted event? If you are using HTTP binding or Active Directory authentication for your queue this can reduce performance compared to TCP. – DaveRead May 18 '11 at 08:32
  • The server is just listening on an IIS server. The queue simply pushes the log requests to this service as it receives them. The service is a WCF basicHttpBinding service and is much much faster when not going through a queue. It seems like whatever is sitting in between my MSMQ service and the Message Queueing service on the machine is seriously throttling the messages. – omatase May 18 '11 at 16:29
  • I think the topic of this question has veered off the original subject so I'm going to mark this one as the answer and ask a new question with slightly different details. – omatase May 22 '11 at 18:55