Search This Blog

Thursday, November 13, 2008

Performance Characteristics of Windows Workflow Foundation



I would say that everybody who started developing applications using WF has to read that whitepaper to clearly understand the performance implications, associated with the various pieces of WF. And another thing is this document is highly readable one as the content is succinct as well as interesting. Kudos to Microsoft and we expect such documents on other two technologies (WPF and WCF) too.

I consider the following 10 points are significant ones to be noted down, while I certainly don’t ignore other points that are being discussed out in that document, with respect to the development of better performing WF application.

  1. Understand the performance factors of each Out-of-Box runtime services provided in WF.
  2. Understand the way threads are being used when you use DefaultWorkflowScheduler or ManualWorkflowScheduler services.
  3. Understand the performance factors of each Out-of-Box runtime services provided in WF. For example, out of two transaction services such as DefaultWorkflowCommitWorkBatchService and SharedConnectionWorkflowCommitWorkBatchService, it is essential to know that we have to use the later when SQL Server 2000 is being used as backend database for persistence and tracking, as it eliminates the overhead of bringing in MS DTC.
  4. Avoid persistence when it is not required. If it is required, you need to know what are getting persisted and size of the persisted state. At least make sure that unwanted fields/properties are not persisted.
  5. Whenever possible, create custom activity rather than using one from Base Activity Library. While activities from BAL provide more flexibility, that flexibility may also prove to be a overkill.
  6. Customize the transaction through implementation of IPendingWork and IWorkBatch interfaces, instead of using default TransactionScopeActivity and CompensatableTransactionScopeActivity, if possible.
  7. Understand the differences between CompensatableSequenceActivity and CompensatableTransactionScopeActivity and choose the appropriate one depends on the application’s requirement.
  8. Understand the differences between Code conditions and declarative rule condition and choose appropriate one. If you use a declarative ruleset, don’t forget to set the priorities and chaining behavior in a ruleset.
  9. Just think whether you really need dynamic update feature in your workflow and avoid this feature as much as possible.
  10. Please remember to tune a set of performance related settings such as EnablePerformanceCounters, EnableRetries( of Persistence and transaction services), IsTransactional (of SqlTrackingService) etc.And this whitepaper also provides some scenario based test results and case study that comprises of a series of seven tests. In my view, scenario based test results section should have included the comparison of performance of a WF application, hosted in different types of application such as Console, Service, Windows Form and ASP.NET application. This would have addressed the dilemma in choosing an appropriate host, particularly when people are dilly-dallying with Web Server and console host. While this document explained well about the performance factors associated with the two services – DefaultWorkflowScheduler and ManualWorkflowScheduler and suggested tuning the setting such as MaxSimultaneousWorkflows property, some more additional tuning would be definitely necessary. Before going to that detail, let us see the thread implications of using either of those services.
DefaultWorkflowSchedulerService is the default scheduler service of WF runtime. This Scheduler Service takes care of choosing an appropriate thread to instantiate and run the workflow instance. This service runs the workflow instance asynchronously using a worker thread rather than the main thread of the host application. It leaves the main thread to continue with executing some other task in parallel. It is really an appreciable fact particularly when WF application is hosted in WinForm or WPF applications. But we can not say the same when ASP.NET hosts the WF application.

Let us consider a scenario where ASP.NET hosts WF application and a method in code behind file starts a workflow instance and returns the result back. In this case, the thread that is associated with the http request (that invokes that web method) will not be used to create the workflow instance. Instead a new thread will be taken out of default managed CLR thread pool to start and run the workflow instance. Till the execution of instance is done with, the main thread will be in limbo as the result needs to be sent back to the requester. It means, two threads are taken from processor wide managed thread pool for a single http request. While it does not seem to be alarming, it is indeed alarming one if we consider the fact that there are only 25 worker threads per available processor. What is more alarming is that the craving for threads does not end with just 2 if the application contains the complex workflow that may invoke other workflows using InvokeWorkflow activity or consume web services that are hosted in the same/external web server (if web service hosted in the same web server, that would also use the same thread pool) or using the persistence and transaction service. In that case, the number of threads, that are being taken out from managed thread pool is many and it would cause the thread pool to starve and needless to say, would affect the scalability of the application badly.
An alternative service – ManualWorkflowSchedulerService is recommended for WF application that is to be hosted in IIS, to mitigate the above mentioned problem. This service reuses the main thread (associated with the http request) to instantiate and run the workflow instance. However, we have to remember the fact that still a few more threads would be needed as they are required for invoking web service calls and invoking other workflows and for persistence service (Actually when this service tries to complete a persistence transaction, transaction object would requires a thread from thread pool). But side effect of the usage of this service is, the workflow instance will run in synchronous manner, as the main thread is being used to instantiate and run the workflow.

This is however acceptable, as the main thread should normally be kept in wait state till the workflow instance gets executed. Though the excess number of threads is pulled out from thread pool for a complex workflow application, it may or may not warrant the fine tuning of the managed thread pool, depends on the complexity of the workflow application. But in some other case, more than one workflow instance may be created within an ASP.NET web method. This scenario would require more number of threads depends on the complexity of the workflow application. This would definitely require the fine tuning of the CLR thread pool.

Whenever, such tuning related to threads is necessary, the settings to be taken care of , in ASP.NET configuration in Machine.config file (or editing the metabase in the case of IIS 6.0) are
ConnectionManagement element settings
maxConnection – that enables executing more remote web service calls concurrently.
ProcessModel element settings
maxIOThreads – to increase the number of available worker threads;
maxWorkerThreads – to increase the number of IO threads;
HttpRuntime element settings
minFreeThreads – to set aside a number of threads that will not be used for http request handling
minLocalRequestFreeThreads – the number of threads that is to be set aside to process local web service calls.

Microsoft has recommended changing the default values of all of above settings. See the following table that provides the new values.

Configuration setting...............Default value.................... Recommended value
maxConnection .................... ..........  2 ......................................... .....  12 * #CPUs
maxIOThreads ................................ 20 ............................................... 100
maxWorkerThread .........................  20 ............................................... 100
minFreeThreads ..............................  8 .. .............................................. 88 * #CPUs
minLocalRequestFreeThreads .......    4 ................................................. 76 * #CPUs

Having tuned those settings, now we can try increasing the MaxSimultaneousWorkflows (number of workflows that would be allowed concurrently) value of DefaultWorkflowSchedulerService in WF application, from its default value (5). Careful monitoring of certain thread related performance counters are essential to conduct this tuning. Otherwise, it may lead to thread starvation that would impact the scalability.

No comments:

Popular Posts