Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Server

BizTalk 2009 : Ready-to-Bake BizTalk Performance Plan (part 4)

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
7/13/2011 9:11:20 AM

5. What to Keep in Mind About Your Code

A few simple things to keep in mind before jumping into tuning your BizTalk solution as well are your current coding practices. Coding is a constant improvement process. While coding and performing code reviews, since the Assembly/C/C++ days, we have constantly written and seen comments like "// —TBD: refactor or rewrite in next rev." This is an obvious sign that no matter what stage you are in, there is always some code in your application or library that, given the time, you would revisit, rewrite, or repackage.

Some of the BizTalk coding caveats that tend to apply to most BizTalk developers, and that generally represent quick performance wins, are as follows:

  • Move your message transformations to the ports: This minimizes the number of message copies created in your orchestration.

  • Avoid using XmlDoc objects in your orchestration and use distinguished fields on a message: XmlDoc objects load the full message into a DOM and consume a considerable amount of memory resources. Each transformation from an XmlDoc to a message object and back results in copies of these objects being created in memory. Using distinguished fields simply references the existing message and minimizes memory churn.

  • Move data validation to the pipeline or schema: If you are performing any data validation on your input messages, for example, validating that an order number is numeric and within a prespecified range, you are better off specifying this form of validation when defining the data types in the schema. If you require other forms of contextual validation, you are better off doing that in a pipeline. It is better to do this before persisting the message to the Messagebox, running the routing logic to find the proper schedule subscribed to the message instance, and then spawning an orchestration instance and allocating the required resources for it to run, only to realize that the data was not good enough to start with and issues an exception or sends back an error. You can save a lot of system resources and processing time by handling this in the pipeline and generating an error message there that you can then route back to the sender using content-based routing.

  • Avoid using orchestrations for routing: If all your orchestration is doing is checking message fields to route the message to the proper handler or another worker orchestration to perform a particular task, strongly consider redesigning that piece of your application as a set of port filters. Leverage receive ports with multiple receive locations and send groups to route messages coming in from multiple sources and send messages to multiple destinations instead of relying on orchestrations to achieve that.

  • Avoid calls to external assemblies that perform extensive processing, especially if they call web services or make calls to a database: Avoid calling slow external assemblies from within your orchestrations.[] This holds the processing host resources and valuable host threads from servicing other orchestration instances while waiting for that external logic to terminate and return. If these calls stall or take a considerable amount of time, there is no way for the BizTalk engine to dehydrate that orchestration instance and use the resources assigned to it to service another one, because the engine sees the instance's state as running while in fact the external code that it called is idle. Leverage the messaging infrastructure to issue such calls that span multiple processes boundaries.

    [] Ensure that all external assemblies being called are not making calls to web services or communicating with external systems or backend databases that might hold the calling thread until they complete. Also, ensure that all external assemblies adhere to the .NET development guideline and best practices.

  • Do not wrap calls to .NET objects in atomic transactions because they are nonserializable: Do not create transaction scopes around an expression to simply get around the shortcoming of an external object that you are using. If it makes sense, make this object serializable, or if it is simply a utility, use static methods instead of instantiating an object. Change the class's implementation or implement a façade that provides you with the required interface[] if needed.

    [] For more details on implementing a façade, refer to Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1995). The definition of the Façade pattern can be found at Wikipedia: en.wikipedia.org/wiki/Facade_pattern.

  • Use Parallel shapes carefully: As illustrated in Figure 9, Parallel shapes should be used to parallelize receives if the order of incoming messages is unknown. The cost of persistence points associated with Parallel shapes is high.

  • Differentiate between scopes and transactions: Transaction scopes affect persistence points. Atomic transactions batch state persistence points and write them to the database in a single call. Long-running transactions, on the other hand, persist state at different points along the process. If you are not really running a transaction, do not assign a transaction type to your scope.

    Figure 9. The proper use of Parallel shapes in an orchestration
  • Use pass-through pipelines where possible: The XMLSend or XMLReceive pipelines do a fair amount of work to validate and assemble the data going through them. If you are sure that outgoing and incoming messages are in a valid XML form, use a pass-through pipeline to eliminate this unneeded overhead.

    NOTE

    The pass-through pipeline does not promote any message properties. You might still want to use the XMLReceive pipeline if you want to access promoted properties.

  • Clean up suspended messages: Suspended messages are held in the suspended queue and thus retain an entry in the Messagebox spool table. An unexpected growth in the spool table affects overall performance, because all instances added to, changed, or removed from the system touch the spool table. It is therefore wise to help maintain as small a size as possible for the spool table. Suspended-resumable instances have a worse impact on the system because they are considered by the engine to be dehydrated messages on a server recovery from an unexpected failure and are rehydrated back to memory, consuming valuable threads and resources. Leverage exception handlers in orchestrations and subscribe to negative acknowledgments or use a cleanup script to clear your system from suspended instances regularly only after verifying that the data is nonrepairable or unnecessary in the target system.[]

    [] Although you should not be seeing suspended instances in your system, because they are signs of an error and you should be handling all errors, sometimes the occurrence of suspended instances is out of your hands. For example, you may be making a request-response call to a web service that was unavailable or issuing a query to a database that was taken offline during a valid change window for maintenance. Such actions, though valid, will result in suspended instances on the host instance running those adapters. The recommended approach to handle these suspended instances is to handle error reports or to create a context-sensitive orchestration that subscribes to NACK, inspects the instances' details and archives them, and then cleans them up.

Regular code reviews during the development cycle should ensure that these guidelines are being followed and save the development team valuable time spent in performance testing and bug fixing to meet performance requirements.

SUSPENDED INSTANCES CLEANUP SCRIPT

The following script can be used to periodically clean up suspended messages. Add it to your task scheduler on the server to run periodically—every day or couple of days—and clean up suspended messages. The script needs to be configured with the different hosts to inspect and clean up. The approved way of cleaning up suspended messages programmatically is using the WMI APIs exposed by BizTalk, which is unfortunately a resource-intensive way to perform this task. To avoid locking up the server, the script cleans up instances in batches. The number of instances in a batch—nMaxInstancesToClean—as well as the hosts—aryHostNames—to clean up suspended instances for and the log file location—strDirectory and strFile—can be easily modified. The script also generates and appends data to the same log file with each run for administrators to track its progress and keep track of cleaned-up messages. Enter your host names in order of priority, such that the one that needs to be cleaned first will run first.

dim objServices, objMsg, svcinsts, inst, msg, ndx, size, nHostCount

Dim aryClassIDs()
Dim aryTypeIDs()
Dim aryInstanceIDs()

Dim aryClassIDsTemp()
Dim aryTypeIDsTemp()
Dim aryInstanceIDsTemp()
'-----------------------------------------------
Dim strKey2Instance
Dim strQuery2Msg
Dim objQueue

'-----------------------------------------------
'-- Creating and opening log file to append info
'-----------------------------------------------
Dim strDirectory, strFile, objFSO, objTextFile
'Create the File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject")

'Check that the folder and file exists
If objFSO.FileExists(strDirectory & strFile) Then
'OpenTextFile Method needs a Const value
'ForAppending = 8 ForReading = 1, ForWriting = 2
Const ForAppending = 8
Set objTextFile = objFSO.OpenTextFile(strDirectory & strFile,
ForAppending, True)
Else
Set objTextFile = objFSO.CreateTextFile(strDirectory & strFile)
End If

'---------------------------
'-- Set the object reference
'---------------------------
set objServices = GetObject("winmgmts:\\.\root\MicrosoftBizTalkServer")

'--------------------------------------------------------------------
'-- Create array of hostnames to loop over hosts
'-- increase the array's size,
'-- add as many hostnames as required to the array,
'-- and initialize the corresponding aryHostSuspendedMessages entries
'--------------------------------------------------------------------
'--------------------------------------------------------------------------
'-- The maximum number of suspended instances to clean up in a single batch
'--------------------------------------------------------------------------

Dim strHost
nHostCount = 0

objTextFile.WriteLine("------- SCRIPT EXECUTION STARTED -------")

'--------------------------------------------------------------------
'-- Terminate instance in each suspended Queue for the selected hosts
'--------------------------------------------------------------------
for each strHost in aryHostNames

'wscript.echo "Host: " & strHost
objTextFile.WriteLine("----------------------------------------")
objTextFile.WriteLine(Now() & " : Host: " & strHost)

'--------------------------------
'-- Query for Suspended instances
'--------------------------------
wbemFlagReturnImmediately = 16
wbemFlagForwardOnly = 32
IFlags = wbemFlagReturnImmediately + wbemFlagForwardOnly
set svcinsts = objServices.ExecQuery(
"select * from MSBTS_serviceinstance
where (servicestatus=32 or servicestatus=4)
and HostName="""&strHost&"""",, IFlags)

'Using a semi-synchronous therefore the count property doesn't
'work with wbemFlagForwardOnly
'size = svcinsts.Count
'wscript.echo "Suspended Message: " & size

strKey2Instance = "MSBTS_HostQueue.HostName=""" & strHost & """"

set objQueue = objServices.Get(strKey2Instance)

If Err <> 0 Then

wscript.echo Now() & " : Failed to get MSBTS_HostQueue instance"
wscript.echo Now() & " : " & Err.Description & Err.Number
objTextFile.WriteLine(Now() & " :
Failed to get MSBTS_HostQueue instance")
objTextFile.WriteLine(Now() & " : " + Err.Description & Err.Number)

Else

ndx = 0

redim aryClassIDs(nMaxInstancesToClean)
redim aryTypeIDs(nMaxInstancesToClean)
redim aryInstanceIDs(nMaxInstancesToClean)

'Loop through all instances and terminate nMaxInstancesToClean at a
'time.
'This number was choosen for optimization, so it can be changed if
'desired.
for each inst in svcinsts

If ndx > nMaxInstancesToClean Then
'Currently 500 entries are ready to be terminated

'wscript.echo "Attempting to terminate "
'& ndx & " suspended instances in host"
objTextFile.WriteLine(Now() &
" : Attempting to terminate "
& ndx & " suspended instances in host")

objQueue.TerminateServiceInstancesByID aryClassIDs,
aryTypeIDs, aryInstanceIDs

If Err <> 0 Then
wscript.echo Now() & " : Terminate failed"
wscript.echo Now() & " : " & Err.Description
& Err.Number
objTextFile.WriteLine(Now() & " : Terminate failed")
objTextFile.WriteLine(Now() & " : " + Err.Description
& Err.Number)
Else
'wscript.echo "SUCCESS> " & ndx &
'" Service instance terminated"
objTextFile.WriteLine(Now() &
" : SUCCESS> " & ndx &
" Service instance terminated")
End If

'Reinitialize the arrays and counter
'to ensure we store non-terminated
'Entries for the next round of termination
ndx = 0
redim aryClassIDs(nMaxInstancesToClean)
redim aryTypeIDs(nMaxInstancesToClean)
redim aryInstanceIDs(nMaxInstancesToClean)

'Suspends script execution for 30 seconds,
'then continues execution
'wscript.echo "Suspending script execution for 30 seconds"
objTextFile.WriteLine(Now() &
" : Suspending script execution for 30 seconds")
Wscript.Sleep 30000

End If

aryClassIDs(ndx) = inst.Properties_("ServiceClassId")
aryTypeIDs(ndx) = inst.Properties_("ServiceTypeId")
aryInstanceIDs(ndx) = inst.Properties_("InstanceId")

ndx = ndx + 1

next

'If count <> zero then the arrays are still populated
'and the messages need to be terminated one last time.
If ( ndx > 0 ) then

redim aryClassIDsTemp(ndx-1)
redim aryTypeIDsTemp(ndx-1)
redim aryInstanceIDsTemp(ndx-1)

for i=1 to ndx
aryClassIDsTemp(i-1) = aryClassIDs(i-1)
aryTypeIDsTemp(i-1) = aryTypeIDs(i-1)
aryInstanceIDsTemp(i-1) = aryInstanceIDs(i-1)
aryHostSuspsendedMessages(nHostCount) =
aryHostSuspsendedMessages(nHostCount) + 1
next

'wscript.echo "Attempting to terminate " &
'ndx & " suspended instances in host"
objTextFile.WriteLine(Now() &
" : Attempting to terminate " & ndx &
" suspended instances in host")

objQueue.TerminateServiceInstancesByID aryClassIDsTemp,
aryTypeIDsTemp, aryInstanceIDsTemp

If Err <> 0 Then
wscript.echo Now() & " : Terminate failed"
wscript.echo Now() & " : " & Err.Description & Err.Number
objTextFile.WriteLine(Now() & " : Terminate failed")
objTextFile.WriteLine(Now() &
" : " + Err.Description & Err.Number)
Else
'wscript.echo "SUCCESS> " & ndx &
'" Service instance terminated"
objTextFile.WriteLine(Now() &
" : SUCCESS " & ndx & " Service instance terminated")
End If
Else
'wscript.echo "No suspended instances in this host"
objTextFile.WriteLine(Now() &
" : No suspended instances in this host")
End If
End If

nHostCount = nHostCount + 1

Next

objTextFile.WriteLine("")
objTextFile.WriteLine("------- SUMMARY START -------")

nHostCount = 0
for each strHost in aryHostNames
wscript.echo Now() & " : Total of " &
aryHostSuspsendedMessages(nHostCount) &
" suspended messages were terminated in " &
strHost & " host"
objTextFile.WriteLine(Now() & " : Total of " &
aryHostSuspsendedMessages(nHostCount) &
" suspended messages were terminated in " &
strHost & " host")
nHostCount = nHostCount + 1
Next
objTextFile.WriteLine("------- SUMMARY END -------")
objTextFile.WriteLine("")


wscript.echo Now() & " :    Script Execution Completed"
objTextFile.WriteLine(Now() & " : Script Execution Completed")
objTextFile.WriteLine("------- SCRIPT EXECUTION ENDED -------")
objTextFile.Close
Set objTextFile = nothing

A sample log file output with multiple batch runs to clean the hosts:

------- SCRIPT EXECUTION STARTED -------
----------------------------------------
08/11/2009 3:42:31 PM : Host: BizTalkServerApplication
08/11/2009 3:42:37 PM : Attempting to terminate 500 suspended instances in
host
08/11/2009 3:42:43 PM : SUCCESS> 500 Service instance terminated
08/11/2009 3:42:43 PM : Suspending script execution for 30 seconds
08/11/2009 3:43:13 PM : Attempting to terminate 162 suspended instances in
host
08/11/2009 3:43:14 PM : SUCCESS> 162 Service instance terminated
----------------------------------------
08/11/2009 3:43:14 PM : Host: BizTalkServerIsolatedHost
08/11/2009 3:43:15 PM : No suspended instances in this host

------- SUMMARY START -------
08/11/2009 3:43:25 PM : Total of 662 suspended messages were terminated in
BizTalkServerApplication host
08/11/2009 3:43:30 PM : Total of 0 suspended messages were terminated in
BizTalkServerIsolatedHost host
------- SUMMARY END -------

08/11/2009 3:43:32 PM : Script Execution Completed
------- SCRIPT EXECUTION ENDED -------
Other -----------------
- Windows Small Business Server 2011 : Planning the Network Infrastructure (part 2)
- Windows Small Business Server 2011 : Planning the Network Infrastructure (part 1)
- Introducing Windows Small Business Server 2011
- Microsoft Dynamics GP 2010 : Streamlining payables processing by prioritizing vendors
- Microsoft Dynamics GP 2010 : Gaining visibility with Horizontal Scroll Arrows
- Microsoft Dynamics GP 2010 : Speeding up account entry with Account Aliases
- SharePoint 2010 Search : Search Extensions - Visualization
- SharePoint 2010 Search : Search Extensions - Commercial Solutions
- SharePoint 2010 Search : Search Extensions - CodePlex and Open Source
- Windows Server 2008 R2 : Implement the Distributed File System (part 2)
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server