【问题标题】:Powershell Runspaces Parallel script execution: Is Set-AzureRmSqlDatabaseTransparentDataEncryption commandlet threadsafe?Powershell Runspaces 并行脚本执行:Set-AzureRmSqlDatabaseTransparentDataEncryption commandlet 线程安全吗?
【发布时间】:2016-07-13 20:14:28
【问题描述】:

运行 powershell commandlet 时: Set-AzureRmSqlDatabaseTransparentDataEncryption

在并行和独立的运行空间中,我们看到下面的堆栈跟踪出现瞬态/间歇性故障。但是,当我们串行运行相同的命令行开关时,我没有看到这个问题发生。

到目前为止我想出的可能原因:

  • 是否知道此命令行开关不是线程安全的? (故意还是错误?)
  • 文件{ReleaseUser}\AppData\Roaming\Windows Azure Powershell\ErrorRecords\Set-AzureRmSqlDatabaseTransparentDataEncryption_YYYY-MM-DD-THH-MM-SS-PPP.log 上的争用/锁定,其中命令行开关似乎记录了与解析令牌相关的信息(此文件中没有实际错误)。

运行此命令的脚本之一的堆栈跟踪:

[异常:System.NullReferenceException:对象引用未设置为对象的实例。\r\n
在 System.Collections.Specialized.OrderedDictionary.OrderedDictionaryEnumerator.get_Value()\r\n
在 Microsoft.Azure.Commands.Common.Authentication.Factories.ClientFactory.GetCustomHandlers()\r\n
在 Microsoft.Azure.Commands.Common.Authentication.Factories.ClientFactory.CreateClient[TClient](AzureContext 上下文,终结点终结点)\r\n
在 Microsoft.Azure.Commands.Sql.TransparentDataEncryption.Services.AzureSqlDatabaseTransparentDataEncryptionCommunicator.GetCurrentSqlClient(String clientRequestId)\r\n
在 Microsoft.Azure.Commands.Sql.TransparentDataEncryption.Adapter.AzureSqlDatabaseTransparentDataEncryptionAdapter.GetTransparentDataEncryption(String resourceGroupName, String serverName, String databaseName)\r\n
在 Microsoft.Azure.Commands.Sql.TransparentDataEncryption.Cmdlet.SetAzureSqlDatabaseTransparentDataEncryption.GetEntity()\r\n
在 Microsoft.Azure.Commands.Sql.Common.AzureSqlCmdletBase'2.ExecuteCmdlet()\r\n
在 Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePSCmdlet.ProcessRecord()]\

堆栈跟踪对于运行相同命令行开关的第二个线程:

消息:“对象引用未设置为对象的实例。”,来源:“System”,StackTrace:“在 System.Collections.Specialized.OrderedDictionary.IndexOfKey(Object key)\r\n 在 System.Collections .Specialized.OrderedDictionary.set_Item(对象键,对象值)\r\n 在 Microsoft.Azure.Commands.Common.Authentication.Factories.ClientFactory.AddHandler[T](T 处理程序)\r\n 在 Microsoft.WindowsAzure.Commands .Utilities.Common.AzurePSCmdlet.BeginProcessing()\r\n 在 System.Management.Automation.Cmdlet.DoBeginProcessing()\r\n 在 System.Management.Automation.CommandProcessorBase.DoBegin()"`

可疑:根据堆栈跟踪,在枚举/访问 System.Collections.Specialized.OrderedDictionary 时,这两个命令都会崩溃。

意义:命令的两个实例是否访问SAME字典?

【问题讨论】:

  • 我也将这个问题提交给了微软的 Powershell Azure GitHub 账户:github.com/Azure/azure-powershell/issues/2580
  • 请注意,Get-AzureRmSqlDatabase/New-AzureRmSqlDatabase 似乎与并发执行有相同的问题。他们似乎在幕后编辑 ArrayList 的同一个实例。此信息是逐字提供的 - 我没有通过查看这些命令行开关的源代码来确认此行为,我只是根据收到的异常进行假设。

标签: .net powershell azure


【解决方案1】:

Will 的回答似乎支持了我们的怀疑,即这个(和其他)命令行开关不是线程安全的。为了解决这个问题,我们使用互斥锁作为协调机制来“锁定”调用此类命令行开关。

以这个线程为灵感,在powershell中构建了一个进程锁定/协调机制(使用互斥体)的简单实现:

function Wait-OnMutex
{
    param(
    [parameter(Mandatory = $true)][string] $MutexId
    )

    try
    {
        $MutexInstance = New-Object System.Threading.Mutex -ArgumentList 'false', $MutexId

        while (-not $MutexInstance.WaitOne(1000))
        {
            Start-Sleep -m 500;
        }

        return $MutexInstance
    } 
    catch [System.Threading.AbandonedMutexException] 
    {
        $MutexInstance = New-Object System.Threading.Mutex -ArgumentList 'false', $MutexId
        return Wait-OnMutex -MutexId $MutexId
    }

}

##
## example script calling unsafe commandlet
##

$MutexInstance = Wait-OnMutex -MutexId 'SomeMutexId12345'

## this is where you do work inside the "lock"
## call the commandlet needing to be single-threaded
Set-AzureRmSqlDatabaseTransparentDataEncryption -arg1 value

$MutexInstance.ReleaseMutex()

希望这对某人有所帮助。

【讨论】:

    【解决方案2】:

    @MSC,

    是否知道这个命令行开关不是线程安全的? (故意还是错误?)

    原因: 据我所知,它取决于类库是否是线程安全的。从源代码(http://referencesource.microsoft.com/#System/compmod/system/collections/specialized/ordereddictionary.cs,d02ab0d292f01b57)中,我们可以看到函数(IndexOfKey(key))。它与objectsArray 更相关。我们可以看到这个目标代码如下:

       private ArrayList objectsArray {
                get {
                    if (_objectsArray == null) {
                        _objectsArray = new ArrayList(_initialCapacity);
                    }
                    return _objectsArray;
                }
            }
    

    看来如果我们使用并行线程来调用这个函数,它会抛出异常。它没有被锁定。

    操作方法:

    1. 在powershell中使用锁机制锁定'objectArray'

    2. 使用单线程调用该函数。

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 2022-10-12
      • 1970-01-01
      • 2012-07-23
      • 1970-01-01
      相关资源
      最近更新 更多