如何针对存储帐户 运行 多本 child 运行 本书
How to run multiple child runbooks against storage account
我有一个 powershell azure 运行book,它遍历一个大型存储帐户并对帐户内的 blob 执行文件年龄策略。这 运行 没问题,但 运行 违反了 3 小时的公平共享政策。我可以使用混合工作者,但我更愿意 运行 多本 child 运行 并行使用第一个字母前缀处理 blob 帐户的不同部分。
示例:
第一本child运行本书运行第A-M
第二个:N-Z
第三:a-m
第四:m-z
我正在考虑在将在字母之间迭代的循环中使用前缀变量。
## Declaring the variables
$number_of_days_bak_threshold = 15
$number_of_days_trn_threshold = 2
$current_date = get-date
$date_before_blobs_to_be_deleted_bak = $current_date.AddDays(-$number_of_days_bak_threshold)
$date_before_blobs_to_be_deleted_trn = $current_date.AddDays(-$number_of_days_trn_threshold)
# Number of blobs deleted
$blob_count_deleted = 0
# Storage account details
$storage_account_name = <Account Name>
$storage_account_key = <Account Key>
$container = <Container>
## Creating Storage context for Source, destination and log storage accounts
$context = New-AzureStorageContext -StorageAccountName $storage_account_name -StorageAccountKey $storage_account_key
$blob_list = Get-AzureStorageBlob -Context $context -Container $container
## Creating log file
$log_file = "log-"+(get-date).ToString().Replace('/','-').Replace(' ','-').Replace(':','-') + ".txt"
$local_log_file_path = $env:temp + "\" + "log-"+(get-date).ToString().Replace('/','-').Replace(' ','-').Replace(':','-') + ".txt"
write-host "Log file saved as: " $local_log_file_path -ForegroundColor Green
## Iterate through each blob
foreach($blob_iterator in $blob_list){
$blob_date = [datetime]$blob_iterator.LastModified.UtcDateTime
# Check if the blob's last modified date is less than the threshold date for deletion for trn files:
if($blob_iterator.Name -Match ".trn") {
if($blob_date -le $date_before_blobs_to_be_deleted_trn) {
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
write-output "Purging blob from Storage: " $blob_iterator.name | Out-File $local_log_file_path -Append
write-output " " | Out-File $local_log_file_path -Append
write-output "Last Modified Date of the Blob: " $blob_date | Out-File $local_log_file_path -Append
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
# Cmdle to delete the blob
Remove-AzureStorageBlob -Container $container -Blob $blob_iterator.Name -Context $context
$blob_count_deleted += 1
Write-Output "Deleted "$extn
}
}
Elseif($blob_iterator.Name -Match ".bak") {
if($blob_date -le $date_before_blobs_to_be_deleted_bak) {
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
write-output "Purging blob from Storage: " $blob_iterator.name | Out-File $local_log_file_path -Append
write-output " " | Out-File $local_log_file_path -Append
write-output "Last Modified Date of the Blob: " $blob_date | Out-File $local_log_file_path -Append
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
# Cmdle to delete the blob
Remove-AzureStorageBlob -Container $container -Blob $blob_iterator.Name -Context $context
$blob_count_deleted += 1
Write-Output "Deleted "$extn
}
}
Else{
Write-Error "Unable to determine file type." $blob_iterator.Name
}
}
Write-Output "Blobs deleted: " $blob_count_deleted | Out-File $local_log_file_path -Append
我希望能够 运行 通过帐户并行。
所以,我同意@4c74356b41 的观点,分解工作量是最好的方法。然而,这本身并不总是像听起来那么简单。下面我将描述公平共享的各种解决方法以及我能立即想到的潜在问题。它的信息量很大,所以这里是重点:
- 创建完成部分工作的作业,然后开始序列中的下一个作业。
- 创建所有 运行 部分序列并行的作业。
- 创建一本 运行 可以并行完成工作但也可以在单个作业中完成的书。
- 使用带有检查点的 PowerShell 工作流,这样您的工作就不会受到公平共享的影响。
- 迁移工作负载以使用 Azure Functions,例如Azure PowerShell functions.
TL;DR
无论如何,有一些方法可以将顺序工作负载分解为顺序执行的作业,例如每个作业在一个段上工作,然后开始下一个作业,因为它是最后一个操作。 (就像一种递归。)但是,管理顺序方法以正确处理间歇性故障会增加 很多 的复杂性。
如果可以将工作量分解为不占用大量资源的较小作业,那么您可以并行完成这些工作。换句话说,如果每个段所需的内存和套接字资源量较低,并且只要没有重叠或争用,这种方法应该 运行 并行快得多。我还怀疑,在并行的情况下,合并的工作分钟数仍将少于顺序方法所需的分钟数。
有一个 gotcha 并行处理段...
当属于同一个帐户的一堆 AA 作业一起启动时,它们都 运行 在同一个沙箱实例中的趋势会显着增加。沙箱从不与 un-related 帐户共享,但由于作业启动性能的改进,首选在同一帐户内为作业共享沙盒。当所有这些作业同时 运行 时,会增加沙箱总资源配额被达到的可能性,然后沙箱将立即执行硬退出。
因为这个问题,如果你的工作量是内存或套接字密集型的,你可能希望有一个父运行book 控制子 运行books 的生命周期(即开始率)。这具有扭曲的效果,即父书 运行 现在可以达到公平份额限制。
下一个解决方法是实施 运行 书籍,这些书籍在完成后会为下一个处理段启动作业。最好的方法是将下一个片段存储在作业可以检索它的地方,例如变量或斑点。这样,如果作业的段失败,只要有某种方法确保作业 运行 直到整个工作负载完成,一切最终都会完成。您可能希望使用观察程序任务来验证最终完成并处理重试。一旦达到这种复杂程度,您就可以通过实验来发现在不达到资源限制的情况下可以引入多少并行性。
- 作业无法监控可用资源并自行调节。
- 无法强制每个作业 运行 在其自己的沙箱中。
- 同一个沙箱中的作业 运行 是否非常 non-deterministic,这会导致难以追踪间歇性故障的问题。
如果您不担心达到资源限制,您可以考虑使用ThreadJob module on the PowerShell Gallery。使用这种方法,您仍然会有一本 运行 书,但知道您将能够并行化该 运行 书中的工作负载并在达到公平共享限制之前完成工作负载。如果单个任务快速且轻量级,这将非常有效。否则,这种方法可能会奏效一段时间,但如果工作量增加所需的时间或资源,就会开始失败。
不要在 AA 作业中使用 PowerShell 作业来实现并行性。这包括 not 使用像 Parallel-ForEach
这样的命令。 VM-Start/Stop
运行书籍中有很多使用 PowerShell 工作的示例; 这不是推荐的方法。 PowerShell Jobs 需要大量资源才能执行,因此使用 PowerShell Jobs 会显着增加 AA Job 使用的资源和达到内存配额的几率。
您可以通过 re-implementing 编码为 Power Shell 工作流并执行频繁的检查点来绕过公平共享限制。 当工作流作业达到fairshare 限制,如果它一直在执行检查点,它将在另一个沙箱上重新启动,从上一个检查点恢复。
我的回忆是你的obs 需要至少每 30 分钟执行一次检查点。如果他们这样做,那将从公平份额中恢复而不会受到任何惩罚,永远。 (以大量工作时间为代价。)
即使没有检查点,工作流也会在到达检查点后获得 re-tried 2 次。因此,如果您的工作流代码是幂等的,并且会很快跳过之前完成的工作,那么通过使用工作流,即使没有检查点,您的工作也可能会完成(在 9 小时内)。
但是,工作流不仅仅是包装在 workflow {}
脚本块中的 Power Shell 脚本:
- 与脚本相比,工作流的运行方式有很多细微差别。掌握这些微妙之处充其量是困难的。
- 工作流不会在作业执行期间检查所有状态。例如,最重要的是您需要编写工作流,以便它在每个检查点后 re-authenticate 与 Azure 一起使用,因为凭据不会被检查点捕获。
- 我认为没有人会声称调试 AA 作业是一件容易的事。对于工作流来说,这个任务就更难了。即使具有所有正确的依赖关系,工作流 运行s 在本地执行时与在云中执行时的方式也有所不同。
- 脚本 运行 明显比工作流快。
将工作迁移到 Azure Functions。随着最近发布的 PowerShell 功能,这可能相对容易。功能将具有与自动化不同的限制。这种差异可能适合您的工作负载,也可能更差。我还没有尝试过函数方法,所以我真的不能说。
您会立即注意到的最明显的区别是 Functions 比 Automation 更像是一种原始的、面向 DevOps 的服务。这部分是因为自动化是一个更成熟的产品。 (自动化可能是第一个广泛使用的无服务器服务,大约比 Lambda 早一年推出。)自动化是专门为云资源管理自动化而构建的,自动化是功能选择的驱动因素。而函数是一种更通用的无服务器操作方法。无论如何,目前一个明显的区别是 Functions 没有任何 built-in 对 RunAs 帐户或变量之类的支持。我希望 Functions 会随着时间的推移在这个特定方面有所改进,但现在它对于自动化任务来说是非常基础的。
我有一个 powershell azure 运行book,它遍历一个大型存储帐户并对帐户内的 blob 执行文件年龄策略。这 运行 没问题,但 运行 违反了 3 小时的公平共享政策。我可以使用混合工作者,但我更愿意 运行 多本 child 运行 并行使用第一个字母前缀处理 blob 帐户的不同部分。
示例:
第一本child运行本书运行第A-M 第二个:N-Z 第三:a-m 第四:m-z
我正在考虑在将在字母之间迭代的循环中使用前缀变量。
## Declaring the variables
$number_of_days_bak_threshold = 15
$number_of_days_trn_threshold = 2
$current_date = get-date
$date_before_blobs_to_be_deleted_bak = $current_date.AddDays(-$number_of_days_bak_threshold)
$date_before_blobs_to_be_deleted_trn = $current_date.AddDays(-$number_of_days_trn_threshold)
# Number of blobs deleted
$blob_count_deleted = 0
# Storage account details
$storage_account_name = <Account Name>
$storage_account_key = <Account Key>
$container = <Container>
## Creating Storage context for Source, destination and log storage accounts
$context = New-AzureStorageContext -StorageAccountName $storage_account_name -StorageAccountKey $storage_account_key
$blob_list = Get-AzureStorageBlob -Context $context -Container $container
## Creating log file
$log_file = "log-"+(get-date).ToString().Replace('/','-').Replace(' ','-').Replace(':','-') + ".txt"
$local_log_file_path = $env:temp + "\" + "log-"+(get-date).ToString().Replace('/','-').Replace(' ','-').Replace(':','-') + ".txt"
write-host "Log file saved as: " $local_log_file_path -ForegroundColor Green
## Iterate through each blob
foreach($blob_iterator in $blob_list){
$blob_date = [datetime]$blob_iterator.LastModified.UtcDateTime
# Check if the blob's last modified date is less than the threshold date for deletion for trn files:
if($blob_iterator.Name -Match ".trn") {
if($blob_date -le $date_before_blobs_to_be_deleted_trn) {
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
write-output "Purging blob from Storage: " $blob_iterator.name | Out-File $local_log_file_path -Append
write-output " " | Out-File $local_log_file_path -Append
write-output "Last Modified Date of the Blob: " $blob_date | Out-File $local_log_file_path -Append
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
# Cmdle to delete the blob
Remove-AzureStorageBlob -Container $container -Blob $blob_iterator.Name -Context $context
$blob_count_deleted += 1
Write-Output "Deleted "$extn
}
}
Elseif($blob_iterator.Name -Match ".bak") {
if($blob_date -le $date_before_blobs_to_be_deleted_bak) {
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
write-output "Purging blob from Storage: " $blob_iterator.name | Out-File $local_log_file_path -Append
write-output " " | Out-File $local_log_file_path -Append
write-output "Last Modified Date of the Blob: " $blob_date | Out-File $local_log_file_path -Append
Write-Output "-----------------------------------" | Out-File $local_log_file_path -Append
# Cmdle to delete the blob
Remove-AzureStorageBlob -Container $container -Blob $blob_iterator.Name -Context $context
$blob_count_deleted += 1
Write-Output "Deleted "$extn
}
}
Else{
Write-Error "Unable to determine file type." $blob_iterator.Name
}
}
Write-Output "Blobs deleted: " $blob_count_deleted | Out-File $local_log_file_path -Append
我希望能够 运行 通过帐户并行。
所以,我同意@4c74356b41 的观点,分解工作量是最好的方法。然而,这本身并不总是像听起来那么简单。下面我将描述公平共享的各种解决方法以及我能立即想到的潜在问题。它的信息量很大,所以这里是重点:
- 创建完成部分工作的作业,然后开始序列中的下一个作业。
- 创建所有 运行 部分序列并行的作业。
- 创建一本 运行 可以并行完成工作但也可以在单个作业中完成的书。
- 使用带有检查点的 PowerShell 工作流,这样您的工作就不会受到公平共享的影响。
- 迁移工作负载以使用 Azure Functions,例如Azure PowerShell functions.
TL;DR
无论如何,有一些方法可以将顺序工作负载分解为顺序执行的作业,例如每个作业在一个段上工作,然后开始下一个作业,因为它是最后一个操作。 (就像一种递归。)但是,管理顺序方法以正确处理间歇性故障会增加 很多 的复杂性。
如果可以将工作量分解为不占用大量资源的较小作业,那么您可以并行完成这些工作。换句话说,如果每个段所需的内存和套接字资源量较低,并且只要没有重叠或争用,这种方法应该 运行 并行快得多。我还怀疑,在并行的情况下,合并的工作分钟数仍将少于顺序方法所需的分钟数。
有一个 gotcha 并行处理段...
当属于同一个帐户的一堆 AA 作业一起启动时,它们都 运行 在同一个沙箱实例中的趋势会显着增加。沙箱从不与 un-related 帐户共享,但由于作业启动性能的改进,首选在同一帐户内为作业共享沙盒。当所有这些作业同时 运行 时,会增加沙箱总资源配额被达到的可能性,然后沙箱将立即执行硬退出。
因为这个问题,如果你的工作量是内存或套接字密集型的,你可能希望有一个父运行book 控制子 运行books 的生命周期(即开始率)。这具有扭曲的效果,即父书 运行 现在可以达到公平份额限制。
下一个解决方法是实施 运行 书籍,这些书籍在完成后会为下一个处理段启动作业。最好的方法是将下一个片段存储在作业可以检索它的地方,例如变量或斑点。这样,如果作业的段失败,只要有某种方法确保作业 运行 直到整个工作负载完成,一切最终都会完成。您可能希望使用观察程序任务来验证最终完成并处理重试。一旦达到这种复杂程度,您就可以通过实验来发现在不达到资源限制的情况下可以引入多少并行性。
- 作业无法监控可用资源并自行调节。
- 无法强制每个作业 运行 在其自己的沙箱中。
- 同一个沙箱中的作业 运行 是否非常 non-deterministic,这会导致难以追踪间歇性故障的问题。
如果您不担心达到资源限制,您可以考虑使用ThreadJob module on the PowerShell Gallery。使用这种方法,您仍然会有一本 运行 书,但知道您将能够并行化该 运行 书中的工作负载并在达到公平共享限制之前完成工作负载。如果单个任务快速且轻量级,这将非常有效。否则,这种方法可能会奏效一段时间,但如果工作量增加所需的时间或资源,就会开始失败。
不要在 AA 作业中使用 PowerShell 作业来实现并行性。这包括 not 使用像 Parallel-ForEach
这样的命令。 VM-Start/Stop
运行书籍中有很多使用 PowerShell 工作的示例; 这不是推荐的方法。 PowerShell Jobs 需要大量资源才能执行,因此使用 PowerShell Jobs 会显着增加 AA Job 使用的资源和达到内存配额的几率。
您可以通过 re-implementing 编码为 Power Shell 工作流并执行频繁的检查点来绕过公平共享限制。 当工作流作业达到fairshare 限制,如果它一直在执行检查点,它将在另一个沙箱上重新启动,从上一个检查点恢复。
我的回忆是你的obs 需要至少每 30 分钟执行一次检查点。如果他们这样做,那将从公平份额中恢复而不会受到任何惩罚,永远。 (以大量工作时间为代价。)
即使没有检查点,工作流也会在到达检查点后获得 re-tried 2 次。因此,如果您的工作流代码是幂等的,并且会很快跳过之前完成的工作,那么通过使用工作流,即使没有检查点,您的工作也可能会完成(在 9 小时内)。
但是,工作流不仅仅是包装在 workflow {}
脚本块中的 Power Shell 脚本:
- 与脚本相比,工作流的运行方式有很多细微差别。掌握这些微妙之处充其量是困难的。
- 工作流不会在作业执行期间检查所有状态。例如,最重要的是您需要编写工作流,以便它在每个检查点后 re-authenticate 与 Azure 一起使用,因为凭据不会被检查点捕获。
- 我认为没有人会声称调试 AA 作业是一件容易的事。对于工作流来说,这个任务就更难了。即使具有所有正确的依赖关系,工作流 运行s 在本地执行时与在云中执行时的方式也有所不同。
- 脚本 运行 明显比工作流快。
将工作迁移到 Azure Functions。随着最近发布的 PowerShell 功能,这可能相对容易。功能将具有与自动化不同的限制。这种差异可能适合您的工作负载,也可能更差。我还没有尝试过函数方法,所以我真的不能说。
您会立即注意到的最明显的区别是 Functions 比 Automation 更像是一种原始的、面向 DevOps 的服务。这部分是因为自动化是一个更成熟的产品。 (自动化可能是第一个广泛使用的无服务器服务,大约比 Lambda 早一年推出。)自动化是专门为云资源管理自动化而构建的,自动化是功能选择的驱动因素。而函数是一种更通用的无服务器操作方法。无论如何,目前一个明显的区别是 Functions 没有任何 built-in 对 RunAs 帐户或变量之类的支持。我希望 Functions 会随着时间的推移在这个特定方面有所改进,但现在它对于自动化任务来说是非常基础的。