Optimizing Notification Distribution


This section describes various settings you can use to improve the performance of the distributor. In many applications, notification distribution can be the bottleneck in the SQL-NS pipeline, so optimizing the distributor's performance is important.

Almost all the settings described in this section affect the performance of a single distributor. Even with these settings tuned optimally, a single distributor may not provide the required level of performance in applications that generate extremely large volumes of notifications or that use slow delivery protocols. In these cases, employing additional distributors on separate machines to share the workload can improve distribution performance. Chapter 13 describes configuring multiple distributors in SQL-NS applications. If you use more than one distributor, you can apply the settings described in this section to each one individually.

Notification Batch Size

Normally, the notifications resulting from a single invocation of a match rule form a single notification batch. The batch size (number of notifications it contains) depends on the number of matches produced by the match rule.

You can override this behavior using settings in the ADF to control the notification batch size. With these settings, you can force the generator to break the results of a single match rule invocation into several small batches instead of one large batch. This can help distributor performance because it provides an opportunity for increased parallelism.

Note

Setting the notification batch size is supported only on SQL-NS Enterprise Edition. In Standard Edition, the notification batch size cannot be explicitly set.


The "Notification Batches and Distributor Work Items" section (p. 355) in Chapter 10 describes how the distributor breaks a notification batch into distributor work items. The work item is the smallest independent unit of processing in the distributor. The distributor processes multiple work items in parallel, to the extent possible.

To understand the performance impact of reducing the batch size, picture a single notification batch of 1,000 notifications, spread evenly across two target delivery channels. This batch would be broken up into two distributor work items (one for each delivery channel), each with 500 notifications. The distributor can process the two work items in parallel, but within each work item, the 500 notifications are processed serially.

Now imagine that instead of producing a single notification batch of 1,000 notifications, the generator is constrained to a maximum batch size of 200 notifications. With this setting, what was previously one notification batch would now form five notification batches, each with 200 notifications. These batches would each be broken into two distributor work items of 100 notifications. Figure 12.7 shows how the breakup into work items is affected by batch size.

Figure 12.7. The effect of batch size on the number of distributor work items produced.


With the batch size constraint in place, the same workload, 1,000 notifications, is broken into 10 independent units of work for the distributor, instead of just 2. The distributor can parallelize these units of work and thereby achieve better performance. Within each unit, there are only 100 notifications to be processed serially, rather than 500.

Note

The extent to which the distributor can parallelize its work depends on the number of threads it has at its disposal. The number of threads is limited by system resources and can also be controlled via ADF settings, as described in the "Thread Pool Size" section (p. 444), later in this chapter.


To specify a notification batch size in the ADF, you use the <NotificationBatchSize> element in the <NotificationClass> declaration, as shown in Listing 12.5.

Listing 12.5. Specifying the Notification Batch Size in the ADF

 <Application>   ...   <NotificationClasses>     <NotificationClass>     ...     <NotificationBatchSize>100</NotificationBatchSize>     </NotificationClass>   </NotificationClasses>   ... </Application> 

This example specifies a notification batch size of 100. Because <NotificationBatchSize> is a subelement of the notification class declaration, you can specify a different value for each notification class in your application. If you specify a value of zero for the <NotificationBatchSize> element, or if you omit the element entirely, no batch size limitation is imposed. All the notifications generated from a single rule invocation are treated as a single batch.

Note

Because the setting of the notification batch size is not supported on SQL-NS Standard Edition, if you include the <NotificationBatchSize> element in your ADF when using Standard Edition, you must supply a value of zero. Any other value will cause a compile error on SQL-NS Standard Edition.


The way SQL-NS interprets the value of the <NotificationBatchSize> element depends on whether digest delivery is used. If digest delivery is not used, the <NotificationBatchSize> element specifies the maximum number of notifications that a single batch can contain (as you might expect).

If digest delivery is used, the value of the <NotificationBatchSize> element specifies the number of notification batches to create for each rule invocation. If you specify a value of 5 for <NotificationBatchSize> when digest delivery is used, the generator will create five empty notification batches before invoking a match rule and then assign notifications to those batches in a round-robin fashion. As it does the assignment, it keeps notifications going to the same subscriber together in the same notification batch. The number of notifications in each batch depends on the number of matches produced by the rule and the extent to which multiple notifications are generated for the same subscriber.

Keeping notifications going to the same subscriber together in the same notification batch facilitates digest grouping later on (because digest grouping works only within each batch). If the generator interpreted the <NotificationBatchSize> value as it does when digesting is not used, the notifications going to a single subscriber may be split across two or more batches, and digesting would not be possible.

Caution

The different treatment of the <NotificationBatchSize> value, based on whether digesting is used, is often a source of confusion. When digesting is used, <NotificationBatchSize> does not specify a size at all, but rather a number of notification batches.


Using Multicast Delivery

Although multicast delivery has already been covered in previous chapters, its effect on distributor performance is worth revisiting. Multicast delivery reduces the workload placed on the application's content formatter by reusing the same formatted notification body for multiple recipients of the same notification data. The actual cost of formatting depends on the particular content formatter implementation, but the fewer times the content formatter has to be invoked, the more efficient the whole distribution pipeline will be.

Note

Multicast delivery is supported only by the Enterprise Edition of SQL-NS.


If an application sends the same notification data to many recipients, using multicast can significantly improve distributor performance. For detailed information on multicast delivery, see the "Aggregation Options: Digest and Multicast" section (p. 147) in Chapter 5.

Delivery Protocol Performance

The performance of delivery protocols can have a major impact on the overall distributor performance of a SQL-NS application. Notification delivery often involves communication with an endpoint over a network, and such communication may involve latency if the network (or endpoint) is slow. If the delivery protocol blocks distributor threads while waiting for network communication to complete, it can hold up the processing of subsequent notifications unnecessarily.

If you are implementing a custom delivery protocol, you can mitigate the effect of network latency by implementing asynchronous delivery. In the asynchronous model, the delivery protocol does not block the distributor while delivering each individual notification. Instead, the delivery protocol receives the notification data, places it on a queue for delivery, and then returns control to the distributor. The distributor can then proceed with the processing of subsequent notifications. The delivery protocol uses a worker thread (or a pool of worker threads) to asynchronously deliver the queued notifications. These worker threads incur the delivery delays but allow other work to continue in parallel. For more information on how to implement asynchronous delivery, see the discussion of the IDeliveryProtocol methods in the section "The Custom Delivery Protocol Interface" (p. 373) in Chapter 10.

Distributor Options

This section looks at a number of distributor-specific ADF settings that can affect distribution performance. As with all other settings described in this chapter, the particular values appropriate for a given application depend largely on that application's unique characteristics. It's difficult to give general recommendations on how to use these settings, but this section lays out some guidelines for choosing appropriate values.

Distributor Quantum

When it is not actively processing notifications and no new notification batches are ready for distribution, the distributor enters an idle state. In this state, it periodically looks for new notification batches to process and, if it does not find any, goes to sleep. After a time interval passes, the distributor awakens and again checks for new notification batches. The interval on which the distributor wakes up from the idle state to check for new notification batches is called the distributor quantum.

Note

It's unfortunate that the term quantum is reused in this context because the distributor quantum is really just a polling interval. The distributor quantum does not have any of the semantics of the generator quantum. There is no distributor quantum clock, the quantum does not act as a scoping mechanism, and there is no notion of falling behind or quantum limits.


The default distributor quantum is 1 minute. As you've already seen, the duration of the distributor quantum can be set in the ADF. In the applications we've tested so far, we've used a distributor quantum of 15 seconds, instead of the default. The shorter the distributor quantum, the more responsive the distributor will be to new notification batches that arrive while it is idle. However, as with the generator quantum, a shorter distributor quantum increases overhead because the distributor checks for work more often. Checking for work involves running a set of database queries, which can put a load on the SQL Server and consume resources in the SQL-NS engine.

The particular distributor quantum value appropriate for an application depends on how quickly the distributor should transition out of the idle state when a new notification batch becomes ready to process. Note that the distributor quantum value has an effect only when the distributor is idle (in other words, when it has no work to do and is periodically checking for new notification batches). When the distributor is actively processing distributor work items, it looks for new work at the start and end of each work item's processing and so the distributor quantum is of no consequence. When choosing a distributor quantum value for an application, you have to consider how often you expect the distributor to be idle and what the responsiveness requirements of the application are when the distributor is in this state.

To set the distributor quantum duration, you use the <QuantumDuration> element in the <Distributor> declaration, as shown in Listing 12.6.

Listing 12.6. Setting the Distributor Quantum in the ADF

 <Application>   ...   <Distributors>     <Distributor>       ...       <QuantumDuration>PT15S</QuantumDuration>       ...     </Distributor>   </Distributors>   ... </Application> 

Note

Although the element names are the same, do not confuse the <QuantumDuration> element in the distributor declaration (used to specify the distributor quantum) with the <QuantumDuration> element in the <ApplicationExecutionSettings> element (used to specify the generator quantum). The ADF schema would have been more symmetrical if the generator quantum were specified in the <Generator> element, but this is just an unfortunate inconsistency.


The distributor's <QuantumDuration> element uses the XML duration data type syntax, as does the generator's quantum duration element. The example shown in Listing 12.6 sets a quantum duration of 15 seconds. Because the distributor quantum duration is specified in the <Distributor> element, if you declare multiple distributors, you can provide a different quantum duration value for each one.

Thread Pool Size

When a distributor finds a work item to process, it assigns a worker thread to do the processing. The distributor can process several work items in parallel by using a separate worker thread for each one. You can control the maximum number of threads the distributor uses by specifying a thread pool size in the ADF.

The thread pool size is specified in the <ThreadPoolSize> element within the <Distributor> declaration, as shown in Listing 12.7.

Listing 12.7. Setting the Distributor Thread Pool Size in the ADF

 <Application>   ...   <Distributors>     <Distributor>       ...       <ThreadPoolSize>2</ThreadPoolSize>       ...     </Distributor>   </Distributors>   ... </Application> 

The default value for the <ThreadPoolSize> element is 3. In SQL-NS Standard Edition, you can specify any value between 1 and 3. In Enterprise Edition, there is no restriction on the thread pool size you can specify. Note that the value specified is a maximum. The actual number of threads that the distributor uses depends on the available resources at runtime.

Increasing the distributor thread pool size can improve the degree to which the distributor processes work items in parallel. But this is an important consideration only if the distributor will often have multiple work items to process at the same time. If an application produces notification batches infrequently and has only one or two delivery channels, the distributor thread pool size probably won't have much of an impact on the application's performance because the distributor would rarely have several work items to process in parallel.

Note

The distributor thread pool size does not affect the processing of an individual work item. Each work item is always handled by exactly one thread. The thread pool size affects only the processing of several separate work items in parallel.


Although parallel processing can improve distribution performance, as you might expect, it comes with a trade-off. The threads that the distributor uses come from a common thread pool within the SQL-NS engine's process. Consuming additional threads from this pool for work item processing leaves fewer threads available to other components in the process. This can be an issue, for example, if an asynchronous delivery protocol uses threads from the thread pool to deliver notifications. The distributor and this delivery protocol would be in competition for the same set of threads.

Also, increasing parallelism in the distributor puts more load on the SQL Server. Many distributor operations involve writing data back to the database (to report notification status, for example). Doing more distributor work increases the frequency of these operations. In fact, the SQL Server may eventually become the bottleneck limiting distribution performance. The higher the capacity of your database system, the more opportunity you will have to scale your distributor processing. Chapter 13 describes strategies for configuring a database system for the best performance.

In several deployed SQL-NS applications, the thread pool size setting is in fact used to limit the resources the distributor consumes, rather than increase them. The appropriate setting for any application depends on the degree of parallelism needed in the distributor and the number of other components in the application that utilize the thread pool.

Distributor Logging Options

The section "The Notification Distribution Views" (p. 360) in Chapter 10 describes views in the application database that provide information about the delivery attempts the distributor makes. The views are defined over tables in which the distributor logs status information as it processes notifications. This log information can be useful in tracking and debugging delivery problems, but the cost of writing it to the database can reduce distributor performance.

By default, the distributor writes an entry to the log table for each notification it processes, before passing the notification data to the delivery protocol. When the delivery protocol reports the status of the notification, the distributor updates this log entry with the status information. You can use settings in the ADF to change this default logging behavior and control how much information is actually written to the log. Turning off certain logging options can dramatically improve distributor performance.

The distributor logging settings are specified in the <DistributorLogging> element within <ApplicationExecutionSettings>. <DistributorLogging> can have the following subelements (all of which take Boolean values):

  • <LogBeforeDeliveryAttempts> Specifies whether the distributor should write an entry to the log for each notification before invoking the delivery protocol

  • <LogNotificationText> Specifies whether the distributor should log the notification text that the delivery protocol returns when reporting notification status

  • <LogStatusInfo> Specifies whether the distributor should log the extended status information that the delivery protocol returns when reporting notification status

Of these settings, the one that has the most drastic impact on performance is the first one, <LogBeforeDeliveryAttempts>. If you set this element to false, the distributor will write a log entry for a notification only after the delivery protocol reports its status. It will not write a log entry before invoking the delivery protocol, as it does in the default case. This effectively cuts in half the number of write operations (and database round-trips) that the distributor performs. In some cases, the reduction in write operations and database round-trips may be even greater because the distributor may group post-delivery status updates for several notifications and do them all in one operation.

The effect of the other two settings depends on the delivery protocol implementation. When a delivery protocol reports notification status, it calls the notification status call-back and passes a NotificationStatus object for each notification. Among the fields in this object are two that are used for logging purposes: NotificationText and StatusInfo. (See the description of the NotificationStatus object in the section "The Custom Delivery Protocol Interface," p. 373, in Chapter 10, for more information on these fields.) The <LogNotificationText> and <LogStatusInfo> elements control whether the information passed back in these fields is written to the database. Depending on how much information the delivery protocol returns in these fields, this may have a significant impact on performance.

All three elements that control distributor logging are optional; if you don't specify them, they default to true. Listing 12.8 shows the ADF code used to set them all to false.

Listing 12.8. Setting the Distributor Logging Options in the ADF

 <Application>   ...   <ApplicationExecutionSettings>     ...     <DistributorLogging>       <LogBeforeDeliveryAttempts>false</LogBeforeDeliveryAttempts>       <LogStatusInfo>false</LogStatusInfo>       <LogNotificationText>false</LogNotificationText>     </DistributorLogging>   </ApplicationExecutionSettings>   ... </Application> 

Setting all the distributor logging options to false provides the best performance but obviously reduces the amount of logging information made available through the notification distribution views. Note that even with all these options set to false, the distributor does provide some logging information. You must determine how much extra logging information you need in your applications and set these options appropriately. Often, the distributor logging options are set to true during an application's development phase, but then turned off when the application is deployed in production.

Additional Sample Code for this Chapter

If you want to see the code shown in Listings 12.3 through 12.8 in the context of a complete ADF, take a look at the file, C:\SQL-NS\Chapters\12\SupplementaryFiles\ApplicationDefinition-17.xml. This supplementary file adds the code in these listings to the most current music store ADF. You can update the music store instance on your system with the code in this file and see the effects of the adjusted settings.

The only difference between the code in the source file and the code shown in the chapter text is that the <NotificationBatchSize> value differs from the example shown in Listing 12.5. The source file specifies the value as zero because that is the only legal value on SQL-NS Standard Edition. Listing 12.5 shows a value of 100, which is valid only on Enterprise Edition. I want the source files that accompany this book to compile for all readers, regardless of which edition they are using, so I had to use a value that would work in both cases.





Microsoft SQL Server 2005 Notification Services
Microsoft SQL Server 2005 Notification Services
ISBN: 0672327791
EAN: 2147483647
Year: 2006
Pages: 166
Authors: Shyam Pather

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net