65.9K
CodeProject 正在变化。 阅读更多。
Home

BizTalk 环境的评估与改进

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2016 年 3 月 28 日

CPOL

4分钟阅读

viewsIcon

13849

downloadIcon

48

在我最近一次对 BizTalk 客户端环境的评估中,我们遇到了一些环境问题,例如速度慢、超时等。 我们对设置进行了一些更改,之后性能有所提高,故障/超时减少。 在这里,我们将看到所做的更改。

引言

本文讨论了最近在 BizTalk 客户端环境中进行的一次评估,以及为提高服务器性能而应用的一些技巧。

背景

这是一个 BizTalk Server 2010 服务器,带有 SQL Server 2008 数据库。 BizTalk 服务器使用业务流程和发送端口与多个外部系统交互。 业务流程作为 Web 服务公开,并由外部系统调用。 业务流程调用外部系统/Web 服务,然后将响应返回给调用系统。 业务流程将请求和响应文件存储在文件夹中,并将事务记录在 SQL Server 日志表中。

面临的主要问题是生产环境中的总体速度慢,以及某些 Web 服务调用中的应用程序超时,从而导致事务失败。

评估策略和改进步骤

为了对生产系统进行评估,第一步是使用 Message Box Viewer 进行分析。 我们在生产环境中运行该工具并分析了它生成的报告。 来自 Message Box Viewer 的一些主要发现

  1. DTA 跟踪数据库的存档和清除作业未成功运行,跟踪数据库的大小不断增加。
  2. 在生产环境中发现了大量挂起消息 (60K+),导致性能下降
  3. 在多个发送端口和业务流程中启用了跟踪,导致性能降低
  4. 在接收位置使用了 XML 接收和 XML 传输管道
  5. 接收位置使用 SOAP 协议,而不是 WCF-* 协议
  6. 只有一个主机实例 BizTalkServerApplication 用于执行业务流程、执行跟踪的发送端口等。

解决发现的问题

我们进行了以下更新以解决这些发现。

终止挂起消息的脚本:https://dl.dropboxusercontent.com/u/23405583/terminate.vbs
' terminate.vbs
' Enter terminate.vbs with no arguments from a command prompt for usage
' This script needs to be run under a user account that is a member of the BizTalk Administrators 
' group. This script needs to be run on a machine that is configured with BizTalk administration
' tools.

dim objBtsWmiNS, objMsg, svcinsts, inst, msg, ndx, size, savemessages

Dim aryClassIDs()
Dim aryTypeIDs()
Dim aryInstanceIDs()
Dim aryHostNames()
Dim aryObjQueues()
Dim aryHostBatchSize()

Dim strKey2Instance
Dim strQuery2Msg
Dim daysOld

maxBatchSize = 200 'Terminate in batches. Max supported batch size is 2K-1 (2047)

On Error Resume Next

Dim objNamedArgs: Set objNamedArgs = WScript.Arguments.Named

If objNamedArgs.Count = 0 OR objNamedArgs.Count > 3 Then
     PrintUsage()
     wscript.quit 0
End If

If Not objNamedArgs.Exists("Operation") Then
    printUsage()
    wscript.quit 0
End If

wmiQuery = ""

'ServiceStatus = 16 - 'Completed With Discarded Messages' in BizTalk Server 2004
'ServiceStatus = 32 - 'Suspended (not resumable)'
'ServiceStatus = 4 - 'Suspended (resumable)'
'ServiceClass = 64 - 'Routing Failure Report'
'ErrorId = "0xC0C01B4C" - is how 'Completed With Discarded Messages' are exposed in BizTalk Server 2009

If UCase(objNamedArgs("Operation")) = "Z" Then
     wmiQuery = "select * from MSBTS_serviceinstance where ServiceStatus=16"
End If

If UCase(objNamedArgs("Operation")) = "A" Then
     wmiQuery = "select * from MSBTS_serviceinstance where ServiceStatus=4 _
     OR ServiceStatus=32 OR ServiceStatus=16 OR ErrorId='0xC0C01B4C' OR ServiceClass=64"
End If

If UCase(objNamedArgs("Operation")) = "SR" Then
     wmiQuery = "select * from MSBTS_serviceinstance where ServiceStatus=4"
End If

If UCase(objNamedArgs("Operation")) = "SNR" Then
     wmiQuery = "select * from MSBTS_serviceinstance where ServiceStatus=32"
End If

If UCase(objNamedArgs("Operation")) = "DIS" Then
     wmiQuery = "select * from MSBTS_serviceinstance where ServiceClass=32 AND ServiceStatus=8"
'ServiceClass = 32 'Isolated Adapter
'ServiceStatus = 8 'Dehydrated
End If

If(wmiQuery = "") Then
     PrintUsage()
     wscript.quit 0
End If

argCount = 1

saveMessagesBeforeTermination = True
If objNamedArgs.Exists("NoSave") Then
     If UCase(objNamedArgs("NoSave")) = "TRUE" Then
          saveMessagesBeforeTermination = False
     ElseIf UCase(objNamedArgs("NoSave")) <> "FALSE" Then
          PrintUsage()
          wscript.quit 0
     End If
     argCount = argCount + 1
End If

daysOld = 0
If objNamedArgs.Exists("DaysOld") Then
    If IsNumeric(objNamedArgs.Item("DaysOld")) Then
        If CLng(objNamedArgs.Item("DaysOld")) = CDbl(objNamedArgs.Item("DaysOld")) Then
            daysOld = CLng(objNamedArgs.Item("DaysOld"))
        Else
            PrintUsage()
            wscript.quit 0
        End If
    Else
        PrintUsage()
        wscript.quit 0
    End If
    argCount = argCount + 1
End If

If objNamedArgs.Count <> argCount Then
    PrintUsage()
    wscript.quit 0
End If

wscript.echo "-->Connecting to BizTalk WMI namespace"
Set objBtsWmiNS = GetObject("WinMgmts:{impersonationLevel=impersonate, _
(security)}\\.\root\MicrosoftBizTalkServer") 
If Err <> 0 Then
     CheckWMIError
     wscript.quit 0
End If        

wscript.echo "-->Getting BizTalk host collection"
Set hosts = objBtsWmiNS.ExecQuery("select * from MSBTS_HostSetting")
If Err <> 0 Then
     CheckWMIError
     wscript.quit 0
End If        

hostCount = hosts.count

ReDim aryHostNames(hostCount - 1)
ReDim aryObjQueues(hostCount - 1)
ReDim aryHostBatchSize(hostCount - 1)

wscript.echo "-->Retrieve BizTalk host names and loading host queues"
ndx = 0
For Each host in hosts
     wscript.echo "Found host " & host.Properties_("Name")
     aryHostNames(ndx) = host.Properties_("Name")
     Set aryObjQueues(ndx) = objBtsWmiNS.Get("MSBTS_HostQueue.HostName=""" _
     & aryHostNames(ndx) & """")
     If Err <> 0 Then
          CheckWMIError
          wscript.quit 0
     End If        
     ndx = ndx + 1
Next

wscript.echo "-->Getting collection of service instances"
Set svcinsts = objBtsWmiNS.ExecQuery(wmiQuery)

ReDim aryClassIDs(hostCount, maxBatchSize-1)
ReDim aryTypeIDs(hostCount, maxBatchSize-1)
ReDim aryInstanceIDs(hostCount, maxBatchSize-1)

'Iterate through instances and save them in host-specific arrays.
'Terminate instances from host-specific array when array gets to a maxBatchSize
wscript.echo "-->Start iterating service instances"
totalCount = 0
saveMessages = saveMessagesBeforeTermination
For Each inst in svcinsts
    
    sSuspendDate = inst.Properties_("SuspendTime")
    sSuspendDay = Left(sSuspendDate,4) & "-" & _
    Mid(sSuspendDate, 5, 2) & "-" & Mid(sSuspendDate, 7, 2)
    dtSuspendDate = CDate(sSuspendDay)
    
    If DateDiff("d", dtSuspendDate, Date()) >= daysOld Then 
    
         saveMessagesBeforeTermination = saveMessages
         wscript.echo "Found suspended instance """ & _
         inst.Properties_("ServiceName") & """ _
         on host " & inst.Properties_("HostName")
         'Resolve host index
         For hostIdx = 0 To hostCount-1 
              If aryHostNames(hostIdx) = inst.Properties_("HostName") Then
                   Exit For
              End If
         Next

        '16 is an internal service class that cannot be terminated
         If 16 = inst.Properties_("ServiceClass") Then
              wscript.echo "Skipping BizTalk internal service instances _
              (they cannot be terminated anyway)"
         Else
              '64 is a routing failure report and doesn't have messages that can be saved
              If 64 = inst.Properties_("ServiceClass") _
              Or 16 = inst.Properties_("ServiceClass") Then
                   saveMessagesBeforeTermination = False
              End If

              errorCountSavingMessages = 0
              If saveMessagesBeforeTermination Then
                   strQuery2Msg = "select * from MSBTS_MessageInstance _
                   where ServiceInstanceID=""" & _
                   inst.Properties_("InstanceId") & """"
                   Set msgInsts = objBtsWmiNS.ExecQuery(strQuery2Msg)
                   For Each msg in msgInsts
                        msg.SaveToFile "C:\Temp"
                      If Err <> 0 Then
                             CheckWMIError
                           wscript.echo "Failed to save MSBTS_MessageInstance"
                           wscript.echo Err.Description & Err.Number
                           errorCountSavingMessages = errorCountSavingMessages + 1
                      Else
                             wscript.echo "Saved message " & _
                             msg.Properties_("MessageInstanceID")
                      End If        
                  Next
             End If
                 
             If 0 = errorCountSavingMessages Then 'Only terminate when we had no problems saving messages
                   aryClassIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("ServiceClassId")
                   aryTypeIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("ServiceTypeId")
                   aryInstanceIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("InstanceId")
                   aryHostBatchSize(hostIdx) = aryHostBatchSize(hostIdx) _
                   + 1 'Keep track of newly added instace for that host
              Else
                   wscript.echo "Skipping the instance since couldn't save its messages"
              End If
         
              totalCount = totalCount + 1
              If(aryHostBatchSize(hostIdx) = maxBatchSize) Then
                   TerminateAccumulatedInstacesForHost hostIdx
              End If
         End If
     End If
Next

' Delete whatever is left
For hostIdx = 0 To hostCount-1 
     If aryHostBatchSize(hostIdx) > 0 Then
          TerminateAccumulatedInstacesForHost hostIdx
     End If
Next

wscript.echo "SUCCESS> " & totalCount & _
" instances were found and attempted to be terminated"

Sub     TerminateAccumulatedInstacesForHost(hostIdx)
     wscript.echo "Sending termination request for host " _
     & aryHostNames(hostIdx) & " service instances"
     Dim aryClassIDs4Host()
     Dim aryTypeIDs4Host()
     Dim aryInstanceIDs4Host()
     ReDim aryClassIDs4Host(aryHostBatchSize(hostIdx)-1)
     ReDim aryTypeIDs4Host(aryHostBatchSize(hostIdx)-1)
     ReDim aryInstanceIDs4Host(aryHostBatchSize(hostIdx)-1)
     
     For i = 0 to aryHostBatchSize(hostIdx)-1
          aryClassIDs4Host(i) = aryClassIDs(hostIdx, i)
          aryTypeIDs4Host(i) = aryTypeIDs(hostIdx, i)
          aryInstanceIDs4Host(i) = aryInstanceIDs(hostIdx, i)
     Next
     aryObjQueues(hostIdx).TerminateServiceInstancesByID aryClassIDs4Host, _
     aryTypeIDs4Host, aryInstanceIDs4Host
     CheckWMIError
     aryHostBatchSize(hostIdx) = 0
End Sub

'This subroutine deals with all errors using the WbemScripting object.  
'Error descriptions are returned to the user by printing to the console.
Sub CheckWMIError()

     If Err <> 0 Then
          On Error Resume Next
          Dim strErrDesc: strErrDesc = Err.Description
          Dim ErrNum: ErrNum = Err.Number
          Dim WMIError : Set WMIError = CreateObject("WbemScripting.SwbemLastError")

          If (TypeName(WMIError) = "Empty" ) Then
               wscript.echo strErrDesc & " (HRESULT: " & Hex(ErrNum) & ")."
          Else
               wscript.echo WMIError.Description & "(HRESULT: " & Hex(ErrNum) & ")."
               Set WMIError = nothing
          End If
                    
          'wscript.quit 0
     End If

End Sub 

Sub PrintUsage()
     wscript.echo "Usage:"
     wscript.echo "cscript Terminate.vbs < /Operation:Z | _
     A | DIS | SR | SNR > [/NoSave:true | false] [/DaysOld:n]"
     wscript.echo
     wscript.echo "  Z terminates all ""Zombie"" _
     instances (e.g. completed with discarded messages)"
     wscript.echo "  A terminates all suspended and zombie instances _
			as well as all routing failure reports"
     wscript.echo "  SR terminates suspended resumable instances only"
     wscript.echo "  SNR terminates suspended non-resumable instances only"
     wscript.echo "  DIS terminates all dehydrated 'isolated adapter' instances"
     wscript.echo "  NoSave:true terminates instances without saving messages _
			they reference. Default is false"
     wscript.echo "  DaysOld:n specifies number of days back to terminate. _
     ie: ""/DaysOld:2"" terminates instances suspended more than 2 days ago."
     wscript.echo
     wscript.echo "  Default action is to save instances to the C:\Temp folder on the local computer"
     wscript.echo
     wscript.echo "  Ensure that the C:\Temp folder exists before _
     running terminate if you want to save instances"
     wscript.echo
     wscript.echo "  Example: cscript Terminate.vbs /Operation:z /NoSave:true /DaysOld:7"
     wscript.echo
End Sub
  1. 创建了一个专用的跟踪主机和发送主机。 由于所有应用程序都使用 BizTalkServerApplication,因此建议将一些发送端口移动到 BizTalkSend 主机
  2. 为面临性能问题的应用程序创建和使用 64 位主机和应用程序池,用于某些接收位置
  3. 从生产环境中禁用了业务流程的开始和结束形状以及其他跟踪。 由于我们将事务记录在单独的表和文件中,因此跟踪对我们来说并不重要。
  4. DTA 清除和备份作业已启用以成功运行。 之前,它由于缺少磁盘空间来保存 DTA DB 的备份而失败。 现在我们清理了空间并再次运行它,并且它成功通过了。
  5. 对于系统中存在的众多挂起消息,我们清除了上周左右之前的消息。 找到了以下脚本,该脚本具有通过指定保留消息的天数来清除所有挂起消息的选项。 可以在计划中运行它,以清除早于 7 天左右的消息。
  6. 默认情况下,BizTalk 的最大并发传出连接数为 2。 因此,我们通过更改 BTSNtSvc.exe.config 文件来增加了一些 Web 服务调用的并发连接数(有选择地)。 其余服务器保持在现有的默认 2 个连接。
    <system.net>
            <connectionManagement>
                <add address = "http://<external server>" maxconnection = "12" />
                <add address = "*" maxconnection = "2" />
            </connectionManagement>
        </system.net>

    注意:不要将 maxconnection 设置为非常大的值,而应将其保持在 10-15 左右。 如果使用较大的值,可能会发生以下情况:如果 BizTalk Server 重新启动,则在启动后,BizTalk 将对目标服务器进行并发调用,以处理排队/未决的请求,这可能导致外部服务器关闭或将所有请求排队或导致超时。 因此,为了安全起见,请将其控制在 10-15 范围内。

  7. 更改管道以在某些使用 XML 接收/传输的位置使用 PassThruReceivePassThruTransmit
  8. 计划对安装的产品进行以下更新
    • 服务器上未安装 BizTalk 累积更新 8
    • 服务器上未安装 BizTalk 适配器包 2010 CU3
    • DB 服务器上安装的 SQL Server 2008 R2 低于 SP2 - 要更新到 SP2
  9. SOAP 和 SQL 适配器将被基于 WCF 的适配器替换

诸如 7、8 和 9 之类的一些点尚未完成。 但是在完成前 6 个步骤之后,我们就面临了性能的提高和超时问题的急剧减少。

© . All rights reserved.