Powershell Runspaces并行脚本执行:Set-AzureRmSqlDatabaseTransparentDataEncryption命令行程序线程安全吗?

时间:2016-07-07 16:17:20

标签: .net powershell azure

运行powershell命令行开关时: Set-AzureRmSqlDatabaseTransparentDataEncryption

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

到目前为止,我提出了可能的原因:

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

运行此命令的其中一个脚本的堆栈跟踪:

  

[例外:System.NullReferenceException:对象引用未设置为对象的实例。\ r \ n \

  at System.Collections.Specialized.OrderedDictionary.OrderedDictionaryEnumerator.get_Value()\ r \ n

  在Microsoft.Azure.Commands.Common.Authentication.Factories.ClientFactory.GetCustomHandlers()\ r \ n \ n   在Microsoft.Azure.Commands.Common.Authentication.Factories.ClientFactory.CreateClient [TClient](AzureContext context,Endpoint endpoint)\ 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()] \

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

  

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

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

重要性:该命令的两个实例是否正在访问 SAME 字典?

2 个答案:

答案 0 :(得分:3)

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

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

function thisFunctionIsCalledFromTheHtml() {
    // Get the JSON data by using a XML http request
    var listData;
    var xhr = new XMLHttpRequest();
    // The request needs to be synchronous for now because on slow connections the DOM is ready
    // before it fetches everything from the json file
    xhr.open('GET', 'records.json', false);
    xhr.addEventListener("load", function() {
      if (xhr.readyState === 4) {
          if (xhr.status === 200) {
              listData = JSON.parse(xhr.responseText);
          } else {
              console.error('Error: ' + xhr.status + ' ' + xhr.statusText);
          }
      }
    });
    xhr.addEventListener("error", function() {
      console.error('Error: ' + xhr.status + ' ' + xhr.statusText);
    });
    xhr.send(null);

    document.addEventListener("DOMContentLoaded", function() {
        var placeholderKeys = [];
        for (var key in listData) {
            var value = listData[key];
            placeholderKeys = placeholderKeys.concat(value.title, value.abbr, value.keywords);
        }

        var filterInput = document.getElementById('input-id');
        filterInput.placeholder = placeholderKeys[
            Math.floor(Math.random() * placeholderKeys.length)
        ];
    });
}

希望这有助于某人。

答案 1 :(得分: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;
            }
        }

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

<强> HOWTO:

  1. 使用锁定机制锁定powershell中的“objectArray

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

  3. 希望有所帮助。