posts - 315, comments - 268, trackbacks - 15

My Links

News

View Pietro Libro's profile on LinkedIn

DomusDotNet
   DomusDotNet

Pietro Libro

Tag Cloud

Article Categories

Archives

Post Categories

Blogs amici

Links

Modi diversi di recuperare il numero di messaggi in una coda MSMQ

Ultimamente mi trovo a lavorare su di un progetto che utilizza WCF e MSMQ. Una delle classiche operazioni quando si lavora con queste tecnologie è sicuramente recuperare il numero di messaggi presenti in una coda. Tra documentazione e ricerche su internet, alla fine si “scopre” che ci sono diversi metodi per risolvere lo stesso problema:

  1. Cursori di MSMQ
  2. Utilizzo di GetAllMessages
  3. Utilizzo di GetEnumerator2
  4. PowerShell
  5. Performance Counter

Traducendo il tutto in righe di codice, per il punto 1) abbiamo:

public int CountByCursor()
{
    int count = 0;
    Cursor cursor = _messageQueue.CreateCursor();
    Message m = CursorPeekWithoutTimeout(cursor, PeekAction.Current);
    if (m != null)
    {
        count = 1;
        while ((m = CursorPeekWithoutTimeout(cursor, PeekAction.Next)) != null)
        {
            count++;
        }
        if (m != null) m.Dispose();
    }
    cursor.Dispose();
    return count;
}

private Message CursorPeekWithoutTimeout(Cursor cursor, PeekAction action)
{
    Message ret = null;

    try
    {
        ret = _messageQueue.Peek(new TimeSpan(1), cursor, action);
    }
    catch (MessageQueueException mqe)
    {
        if (mqe.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
        {
            throw;
        }
    }
    return ret;
}

Sinceramente questo è il metodo che più non mi piace, sarà per la parola “Cursore”, sarà per la gestione dell’eccezione, sarà perchè la vedo poco pulita.

Passiamo al punto 2):

 public int CountByGetAllMessages()
{
    return _messageQueue.GetAllMessages().Length;
}

Semplice e pulita, ma come vedremo a breve, le prestazioni scendono con l’aumentare dei messaggi in coda.

Punto 3), “GetMessageEnumerator2”:

var x = _messageQueue.GetMessageEnumerator2();
int counter = 0;
while (x.MoveNext())
{
    counter++;
}
return counter;

Sfruttiamo il MessageEnumerator ritornato dal metodo GetEnumerator2 ed iteriamo per spostare il cursore fino alla fine della coda.

Punto 4), “PowerShell” (in questo caso mi sono limitato a copiare del codice trovato in rete):

var path = string.Format(@"\\{0}\root\CIMv2", machine);

ManagementScope scope;

if (string.IsNullOrEmpty(username))
{
    scope = new ManagementScope(path);
}
else
{
    var options = new ConnectionOptions { Username = username, Password = password };
    scope = new ManagementScope(path, options);
}

scope.Connect();

if (queuePath.StartsWith(".\\")) queuePath = queuePath.Replace(".\\", string.Format("{0}\\", machine));

string queryString = String.Format("SELECT * FROM Win32_PerfFormattedData_msmq_MSMQQueue");
var query = new ObjectQuery(queryString);
var searcher = new ManagementObjectSearcher(scope, query);
IEnumerable<int> messageCountEnumerable =
    from ManagementObject queue in searcher.Get()
    select (int)(UInt64)queue.GetPropertyValue("MessagesInQueue");
var x = messageCountEnumerable.First();

return x;

ed infine il punto 5) “Performance Counter”:

System.Diagnostics.PerformanceCounter backupQueueCounter = new System.Diagnostics.PerformanceCounter(
    "MSMQ Queue", "Messages in Queue", "queue_path");

return backupQueueCounter.NextValue();

Bene, ora quale usare ? Proviamo con un piccolo test: ad una coda privata aggiungiamo 10.000 messaggi per volta (all’interno di un ciclo) e proviamo ad utilizzare i metodi su descritti per recuperare il numero di messaggi presenti in coda (si suppone che tra un conteggio e l’altro nella coda non vengano aggiunti altri messaggi). Iteriamo il procedimento per tre volte.

Di seguito i risultati ottenuti (espressi in millisecondi, per le misure del tempo di esecuzione è stata utilizzata la classe System.Diagnostics.Stopwatcher):

Prima Iterazione

#Msgs MSMQ Cursor GetAllMessages GetEnumerator2 PowerShell Performance C.
10.000 449,816 580,703 36,37 78,543 351,86
20.000 928,18 1.297,72 78,16 9,888 0,462
30.000 1.340,44 1.854,52 137,82 10,563 1,121
40.000 1.769,73 2.656,28 194,652 12,061 3,187
50.000 2.188,74 3.427,84 190,672 10,739 0,452
60.000 2.631,29 3.909,71 231,995 10,219 0,364
70.000 3.006,52 4.771,09 264,112 5.802,42 0,462
80.000 3.469,49 6.116,47 309,691 10,075 0,545
90.000 4.000,00 6.134,66 372,885 9,876 0,435
100.000 4.544,33 6.932,08 424,196 9,024 0,41
image

Seconda Iterazione

#Msgs MSMQ Cursor GetAllMessages GetEnumerator2 PowerShell Performance C.
10.000 475,357 609,866 38,022 285,978 351,955
20.000 912,591 1.315,49 76,912 10,453 0,502
30.000 1.417,26 2.066,92 122,745 11,156 0,366
40.000 1.901,66 2.718,64 153,373 9,947 0,349
50.000 2.393,97 3.386,43 203,553 10,962 0,358
60.000 2.659,28 4.546,84 280,257 9,832 0,413
70.000 3.246,77 4.938,01 278,404 11,664 0,517
80.000 3.718,89 5.881,67 330,857 13,688 0,506
90.000 4.230,99 6.677,00 362,374 10,155 0,508
100.000 4.832,89 7.585,19 464,216 16,495 0,681
image

Terza Iterazione

#Msgs MSMQ Cursor GetAllMessages GetEnumerator2 PowerShell Performance C.
10.000 533,294 621,392 41,496 79,286 376,431
20.000 911,513 1.338,41 79,827 9,354 0,38
30.000 1.339,34 2.123,46 120,693 12,969 0,414
40.000 1.799,28 2.658,01 158,606 9,423 0,374
50.000 2.196,96 3.221,87 199,273 10,413 0,426
60.000 2.562,49 4.140,15 257,22 8,81 0,411
70.000 3.358,83 4.715,56 327,474 14,808 0,53
80.000 4.417,58 6.690,44 316,044 17,334 0,825
90.000 4.185,52 6.229,67 340,457 11,773 0,396
100.000 4.407,13 6.658,46 390,498 12,944 0,589
image

Dai risultati ottenuti si ottiene che l’utilizzo del “Performance Counter”, in caso di letture successive, sembrerebbe essere quello più efficiente.

In attesa di altri giudizi ed approfondimenti :-).

Print | posted on lunedì 28 gennaio 2013 14:13 | Filed Under [ Varie ed eventuali C# .Net Framework 4.0 WCF .Net Framework 4.5 ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET