Video Screencast Help
Symantec to Separate Into Two Focused, Industry-Leading Technology Companies. Learn more.
Archiving and eDiscovery Community Blog

Microsoft Message Queuing (MSMQ)

Created: 16 Jun 2009 • Updated: 29 May 2014
Wayne Humphrey's picture
+5 5 Votes
Login to vote

I always get asked about MSMQ, here is a short note on things to look at if you have MSMQ issue's, even if you don't have issues you can always benefit from tweaking MSMQ and enhance Enterprise Vault’s performance.

Microsoft Message Queuing (MSMQ)

The root cause I believe lies in the way MSMQ stores messages. In the Storage directory (normally under windows\system32\msmq) will be a number of 4MB files that will contain the messages. Each file can contain as many messages as will fit which works quite well to start with. If a message cannot fit into one storage file, though, because it is too big for the remaining free space then a fresh file is created. There can only be as many storage files as would fit within the storage quota and when this limit is reached then no more storage files can be created. For example from windows 2003 SP2, a 2GB quota could accommodate 500 4MB storage files. In older versions Microsoft used to have an 8GB quota which would accommodate 2,000 4MB storage files.

Note: MSMQ storage works differently from file storage - there is no linked list stitching together parts of a message. An MSMQ storage file has to have inside it a contiguous block of free space that is large enough to accommodate the whole message. MSMQ messages cannot span storage files either - if the message is greater than 4MB then MSMQ cannot store it.

This problem is made worse because MSMQ uses a pipeline for sending messages. If there is a large message at the front of the queue then it will block all the (possibly smaller) messages behind it until delivery becomes possible.

What can be done about this? Here are a few suggestions:

1. Wait it out - storage space should become available eventually. After the House Keeping has happened six hours by default. (Restarting Tasks however full up the cache locations)
2. Set the House Keeping to run every hour (I would recommend this firstly)
3. Set the size of the Queue higher (I would suggest using 4GB to start off with) See bellow for instructions on MessageCleanupInterval
4. Set a Time To Reach Queue on the messages - the large message will expire and be removed from the outgoing queue, allowing the smaller messages through. (This has been added to Enterprise Vault, as of 2007 SP5)
5. Purge the outgoing queue and resend the smaller messages first (I don’t suggest this)

Set Message Cleanup Interval

The following fix installs a periodic cleanup of empty Message Queuing message files. The default interval for cleanup is six hours. This interval can be modified by a new registry key. To change the default interval, you must add MessageCleanupInterval to the registry.

1. Start Registry Editor (REGEDT32.EXE).
2. Locate and select the following registry subkey:
3. HKEY_LOCAL_MACHINE\Software\Microsoft\MSMQ\Parameters
4. From the Edit menu, click ADD VALUE.
5. In the Value Name Field, type MessageCleanupInterval.
6. In the Data Type Field, select REG_DWORD.
7. For the data value, enter the desired interval in milliseconds (for example, 3600000 (decimal) for one hour).
8. Exit Registry Editor to save the changes.

The next time you restart the Message Queuing service, the new interval will be used to cleanup empty message files.

Microsoft SQL Query to find out archiving rate:

This is a Microsoft SQL script to get a list of archiving rates for the past twenty four hours.

-- Author: Wayne Humphrey
-- Date: 26th March 2009
------------- Notes -------------
-- Work out the hourly archiving rate, for the past 24 hours
-- You need to define all the Vault Stores in this query

USE EnterpriseVaultDirectory

declare @VSName varchar(4000)
declare @sql varchar(4000)
declare TCursor CURSOR READ_ONLY for
select DatabaseDSN from dbo.VaultStoreEntry

OPEN TCursor

FETCH NEXT from TCursor INTO @VSName

WHILE @@fetch_status = 0

select @sql = 'select VSName=''' + @VSName + ''' ,' +
' min(archiveddate) as ArchivedDate, ' +
' count(*) as HourlyRate, ' +
' sum(itemsize)/count(*) as AvSize from ' +
@VSName + '.dbo.saveset s' +
' where archiveddate > dateadd(hh, -24, getutcdate()) ' +
' group by left(convert(varchar, s.archiveddate,20),14) ' +
' order by left(convert(varchar, s.archiveddate,20),14) desc'
exec (@sql)

fetch next from TCursor into @VSName

close TCursor
deallocate TCursor