Reporting Services Staaaarrrrrtttt Up

I hear the complaint a lot that after a time period of no calls to Reporting Services, the first call to the Reporting Services instance is very slow.  This is totally expected because the application pool generally gets spun down and we need to restart everything.

If you wire up some basic web service calls, you can see that (at least in my testing) the RS2005 web service takes approximately 30 seconds to start up.  The only database work done here is the bare minimum necessary to retrieve the encryption keys and configuration settings stored in the catalog database.  There is no access to actual datasources or reports.

First, I wrote a  basic web method that just returns an empty dataset:

Public Function ReturnBlankDataSet() As Data.DataSet

     Dim m_ds As New Data.DataSet
     Return m_ds

End Function

Then, I wrote some code that had the ability to make a call to a web service and timed how long it took to return from the web method call.  I ran the test against each web service five times.  In between each test, I did an IIS reset to ensure a cold start. 

My test harness code looked like this:

        Dim sr As New IO.StreamWriter("c:ReportingServicesMetrics.txt")

        'let's loop through 5 times
        For i As Integer = 0 To 4
            Dim ts As DateTime
            Dim te As DateTime

            'let's reset IIS to make sure everything has to start from scratch
            sr.WriteLine("Doing an IISReset - Loop #" & (i + 1).ToString)
            Dim proc As New Diagnostics.Process
            proc.StartInfo.FileName = "iisreset"
            proc.Start()
            proc.WaitForExit()
            sr.WriteLine("IIS has been reset")

            'RS
            sr.WriteLine("Getting ready to instantiate the RS web service")
            ts = Now()
            Dim rs As New RS2005.ReportingService2005
            Dim creds As New Net.NetworkCredential
            creds = Net.CredentialCache.DefaultCredentials
            rs.Credentials = creds
            rs.Url = "https://servername/reportserver2005/reportservice2005.asmx"
            rs.ListChildren("/", False)
            sr.WriteLine("Instantiated the RS web service")
            te = Now()
            sr.WriteLine("RS took " & te.Subtract(ts).TotalMilliseconds.ToString)

            'dummy web service
            sr.WriteLine("Getting ready to instantiate the dummy web service")
            ts = Now()
            Dim dws As New DummyWebService.Service
            dws.ReturnBlankDataSet()
            sr.WriteLine("Instantiated the dummy web service")
            te = Now()
            sr.WriteLine("The dummy web service took " & te.Subtract(ts).TotalMilliseconds.ToString)

        Next
        sr.Close()

I did a FileMon on the startup for each process.  The dummy web service did about 130 file reads, while Reporting Services did almost 17000 reads.  This is because Reporting Services must load up the traditional ASP.NET assemblies, plus all of the specialized Reporting Services assemblies.  It also loads up all the localization files for all the various supported languages.

Reporting Services does a good bit of logging for both ReportServer, Report Manager, and the Report Server Windows Service.  I did not do test with logging turned off because we ship with a default level of logging, you could save some start up time by turning off all logging.  However, it is  not recommended to turn off logging  because of the value traditionally derived from standard logging.

Other things that cause additional overhead when Reporting Services starts up:

  1. Every time the SRS 2005 web service loads, it also has to read and decrypt the rsreportserver.config file
  2. Since there are no connections in the connection pool, we have to physically open up a socket connection between the two servers, plus log into the database instance
  3. The web service has to make RPC calls into the Windows Service to get the symmetric encryption key

This explanation is to try and provide an overview of some of the things that are going on during Reporting Services initial start up.  Remember, most of these things probably do not happen in traditional web applications. Again, all of this is completely expected behavior.

As discussed earlier, if this behavior causes some business issues, you could consider modifying the recycle options on your IIS process.  You can either increase the recycle time (causing them to be recycled less frequently) or schedule the recycle to occur at a non-peak time.  You could then combine this second option with a "ping" process that hits the process shortly after the recycle.  This will "wake" the ReportServer processes so that your initial customer doesn’t see the initialization time.  If you combine these options with turning off the idle worker process shutdown, you can significantly minimize the instances where a user would run into the startup delay. 

The only downside I can see to not idling the worker process is that the process could consume more resources than necessary.  Recycling from time to time is recommended because it cleans up the worker process if you have any leaked memory or fragmentation but it is not necessary from a technical perspective.

Unfortunately, none of this information is documented in any KB articles.  However, some of it is addressed in www.microsoft.com/technet/prodtechnol/sql/2005/pspsqlrs.mspx.  Beyond the counters in the performance document, you could also track the performance of your Reporting Services instance using some execution log reports (https://msdn2.microsoft.com/en-us/library/ms161561.aspx).

Posted By: Evan Basalik