自从亚马逊网络服务在2008年首次亮相以来,复杂的工程软件系统的构建者已经有了越来越强大的方法来扩展云中的重计算工作负载。以前需要购买几十台昂贵的服务器的计算,现在可以在AWS中以极低的成本执行。不幸的是,不是所有的工程软件包都是基于服务器的,更不是基于云的。许多工程团队依赖于只在微软Windows上运行的桌面产品。执行光学光线追踪、基因组测序或计算流体力学等任务的桌面工程工具往往将图形用户界面与复杂的算法结合在一起,即使有强大的CPU和大量的RAM,在传统工作站上运行也需要很多时间。直到最近,还没有一种方便的方法可以将复杂的桌面计算工程负载无缝扩展到云端。

      幸运的是,AWS云计算开发工具包(CDK)、AWS弹性容器服务(ECS)和Docker的出现,终于使得用C#和其他语言编写的桌面工程工作负载可以轻松扩展到云端。

      本文介绍了一种用于高性能计算(HPC)的方法,该方法是针对一个假想的用例,需要对大的非常大的整数集进行因子化处理。想象一下,一个工程团队,出于某种疯狂的原因,有一个用C#语言编写的桌面程序,用来寻找一组整数的因子,这些整数都大于五亿。即使有一个强大的处理器,仅一个大于五亿的整数的因数就需要几秒钟。如果用户需要对1000个唯一的整数进行因式分解,例如从1,000,000,000,000,001到1,000,000,000,001,000的所有数字,他们将等待几分钟的结果。

之所以需要这么长时间,是因为对于每个数字,算法都需要进行一大堆除法,并测试除法结果是否有余数。如果我们能将这些计算扩展到云中的弹性计算资源上,同时保留对用C#等语言编写的现有算法的投资,那就非常好了。

       我们将利用AWS CDK、C#、Docker和AWS ECS Fargate来建立一个简单的云解决方案,可以从我们的桌面上进行协调。下图显示了系统的架构:

architecture

桌面组件首先构建并打包一个可以执行工程工作负载的Docker镜像(因子为整数)。在桌面上执行的AWS CDK将Docker镜像部署到AWS,并建立由输入/输出工作者队列和无服务器ECS Fargate集群组成的云基础设施(1)。

一旦云基础设施被配置好,就可以在桌面上执行一个客户端程序,将需要因子的整数发送到云端(2)。整数通过输入队列(3)被发送到云端,结果因子通过输出队列(5)从ECS集群(4)返回到桌面。

该集群开始时只有一个由单个Docker容器组成的ECS任务在运行,随着负载的增加,允许自动扩展到五个ECS任务,每个任务运行自己的Docker容器。当所有的整数都被分解后,桌面客户端报告成功并正常退出。

前提条件


要建立他的系统,需要以下先决条件。为了简洁起见,可以通过下面的链接看到源文件的安装说明。

.NET - 提供编译和打包C#代码的工具
注意:例子中的代码假设你将使用.NET 6.0。
AWS CDK - 实现云基础设施的程序化配置
注意:一定要遵循入门指南中的所有说明,特别是关于CDK先决条件的安装和配置的说明。
Docker Desktop - 允许构建和管理在AWS ECS Fargate上执行所需的Docker容器镜像

构建系统
首先,让我们创建一个新的.NET解决方案,包含三个项目,一个是worker容器镜像,一个是桌面客户端,还有一个是CDK基础设施。我们还将为AWS简单队列系统(SQS)和AWS CDK添加NuGet依赖项。打开一个终端,输入以下.NET命令。

dotnet new sln -o DesktopHPC
cd DesktopHPC
dotnet new console -o Client
dotnet sln DesktopHPC.sln add Client/Client.csproj
dotnet new console -o Worker
dotnet sln DesktopHPC.sln add Worker/Worker.csproj
dotnet new console -o CDK
dotnet sln DesktopHPC.sln add CDK/CDK.csproj
dotnet add Client package AWSSDK.SQS
dotnet add Worker package AWSSDK.SQS
dotnet add CDK package Amazon.CDK
dotnet add CDK package Amazon.CDK.AWS.SQS
dotnet add CDK package Amazon.CDK.AWS.ECS
dotnet add CDK package Amazon.CDK.AWS.ECS.Patterns
现在我们准备添加代码。打开在 "Worker "目录下生成的 "Program.cs "文件,并粘贴以下内容来替换其内容:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

public class Worker
{
   static async Task Main(string[] args)
   {
     var sqs = new AmazonSQSClient();
     var input = await sqs.GetQueueUrlAsync("InputQueue");
     var output = await sqs.GetQueueUrlAsync("OutputQueue");
     Console.WriteLine("waiting for numbers to factor on {0}", input.QueueUrl);
     do
     {
       var msg = await sqs.ReceiveMessageAsync(new ReceiveMessageRequest
       {
         QueueUrl = input.QueueUrl,
         MaxNumberOfMessages = 1,
         WaitTimeSeconds = 3
       });

      if (msg.Messages.Count != 0)
       {
         long n2 = Convert.ToInt64(msg.Messages[0].Body);
         Console.WriteLine("received input: {0}", n2);
         string factorsString = GetFactors(n2);
         Console.WriteLine("factors are: {0}", factorsString);
         await sqs.SendMessageAsync(output.QueueUrl, factorsString);
         await sqs.DeleteMessageAsync(input.QueueUrl, msg.Messages[0].ReceiptHandle);
       }
     } while (true);
   }

  static string GetFactors(long n)
   {
     string s = n.ToString() + " = ";
     List<long> factors = new List<long>();
     while (!(n % 2 > 0))
     {
       n = n / 2;
       factors.Add(2);
     }
     for (long i = 3; i <= (long)Math.Sqrt(n); i += 2)
     {
       while (n % i == 0)
       {
         factors.Add(i);
         n = n / i;
       }
     }
     if (n > 2)
     {
       factors.Add(n);
     }
     return s + string.Join(" x ", factors);
   }

}

Worker的代码将被打包到Docker容器中,并从该容器中运行。Worker监听 "InputQueue "以获取一个新的整数,对其进行因子处理,并将结果因子写入 "OutputQueue"。

为了构建Docker容器镜像,我们需要在同一目录下添加一个 "Dockerfile"。在 "Worker "目录下打开一个名为 "Dockerfile "的新文件,并粘贴以下内容:

FROM mcr.microsoft.com/dotnet/runtime:6.0
COPY bin/Release/net6.0/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "Worker.dll"]

再次注意,我们假设安装的是.NET 6.0。如果你使用的是旧版本,如5.0,请相应地调整上面的引用。

现在我们准备对客户端进行编码。打开 "客户端 "目录下生成的 "Program.cs "文件,用下面的代码替换其内容。

using System;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

class Client
{
   static async Task Main(string[] args)
   {
     var sqs = new AmazonSQSClient();

    var output = await sqs.GetQueueUrlAsync("OutputQueue");
     var input = await sqs.GetQueueUrlAsync("InputQueue");
     long iStart = 1000000000000000001; // one quintillion one

    Console.WriteLine("Input number of large integers to factor, starting with one trillion one:");

    int count = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("Sending {0} numbers sent to cluster for factoring.", count);
     Console.WriteLine("From {0} to {1}", iStart, iStart + count);

    for (long i = iStart; i < iStart + count; i++)
     {
       await sqs.SendMessageAsync(input.QueueUrl, i.ToString());
     }

    Console.WriteLine("Results:");

    int finishedCount = 0;

    while (finishedCount < count)
     {
       var msg = await sqs.ReceiveMessageAsync(new ReceiveMessageRequest
       {
         QueueUrl = output.QueueUrl,
         MaxNumberOfMessages = 1,
         WaitTimeSeconds = 3
       });

      if (msg.Messages.Count != 0)
       {
         Console.WriteLine(msg.Messages[0].Body);
         await sqs.DeleteMessageAsync(output.QueueUrl, msg.Messages[0].ReceiptHandle);
         finishedCount++;
       }

    }
     Console.WriteLine("Factoring complete, destroy cluster when done.");
   }
}

上面的客户端代码提供了一个简单的命令行界面,提示用户他们想分解的大整数的数量,然后通过 "InputQueue "将这个数量的整数发送到ECS Fargate集群。然后客户端通过 "OutputQueue "等待相同数量的结果出现,打印结果,并在所有结果回来后终止。

现在我们有了Worker和客户端代码,我们只需要基础设施CDK代码。CDK的好处是,你可以用Typescript、JavaScript、Java或C#来编写它。由于我们系统的其他部分是用C#编写的,所以我们在这里也将使用它。

在 "CDK "目录下,打开生成的 "Program.cs "文件,用下面的代码替换其内容。

using Amazon.CDK;
using Amazon.CDK.AWS.ECS;
using Amazon.CDK.AWS.ECS.Patterns;
using Amazon.CDK.AWS.SQS;

public class Infrastructure : Stack
{
   static void Main(string[] args)
   {
     var app = new App();
     new Infrastructure(app, "HPCStack");
     app.Synth();
   }

  internal Infrastructure(
     Construct scope,
     string id,
     IStackProps props = null
   ) :
       base(scope, id, props)
   {
     var input =
       new Queue(this,
         "InputQueue",
         new QueueProps { QueueName = "InputQueue" });
     var output =
       new Queue(this,
         "OutputQueue",
         new QueueProps { QueueName = "OutputQueue" });
     var cluster =
       new Cluster(this,
         "HPCCluster",
         new ClusterProps { ClusterName = "HPCCluster" });
     var service =
         new QueueProcessingFargateService(this,
           "HPCService",
           new QueueProcessingFargateServiceProps
           {
             ServiceName = "HPCService",
             Cluster = cluster,
             MinScalingCapacity = 1,
             MaxScalingCapacity = 5,
             Image = ContainerImage.FromAsset("./worker"),
             MemoryLimitMiB = 2048,
             Queue = input
           });
     output.GrantSendMessages(service.TaskDefinition.TaskRole);
   }
}

CDK代码自动创建输入和输出队列,ECS Fargate集群,以及利用我们的Docker镜像的ECS任务定义。该集群允许根据需要从一个工人实例扩展到最多五个工人实例。每个实例在AWS中使用2GB的内存。

现在我们准备建立客户端和工作者和基础设施。导航到顶层的 "DesktopHPC "目录,运行以下命令来构建整个解决方案。

dotnet publish -c Release
接下来,启动CDK。引导CDK在你的AWS账户中设置了一些你将需要的资源。你应该只需要做这一次。使用 "cdk bootstrap "命令,参数格式为 "aws://ACCOUNT-NUMBER/REGION"。例如,如果你的AWS账户ID是123456789012,你想部署到us-west-2地区,请输入
cdk bootstrap aws://123456789012/us-west-2
当你准备好部署云基础设施时,输入
cdk deploy --app "dotnet run --project CDK/CDK.csproj"

你将被要求确认创建某些与安全有关的资源。回答 "y",CDK将开始工作,建立你的基础设施。

几分钟后,ECS Fargate集群应该可以使用了。

登录到AWS控制台,导航到 "Elastic Container Service -> Clusters"。你应该看到你的集群,名为 "HPCCluster",已经创建并准备就绪,如下图所示。

console

现在我们准备生成一些工作负载,看看它是如何扩展的。在你的桌面上,回到命令行,从DesktopHPC目录中运行客户端:

dotnet run --project Client
系统会提示你输入所需的整数,从一万亿分之一开始计算。试着输入 "1000"
Input number of large integers to factor, starting with one trillion one:
1000
Sending 100 numbers sent to cluster for factoring.
From 1000000000000000001 to 1000000000000000101
Results:
1000000000000000001 = 101 x 9901 x 999999000001
1000000000000000002 = 2 x 3 x 17 x 131 x 1427 x 52445056723
1000000000000000003 = 1000000000000000003
1000000000000000012 = 2 x 2 x 13 x 487 x 4623217 x 8541289
1000000000000000005 = 3 x 5 x 44087 x 691381 x 2187161
1000000000000000004 = 2 x 2 x 1801 x 246809 x 562425889
1000000000000000011 = 3 x 53 x 389 x 16167887342161

...

在运行过程中,观察ECS控制台,虽然开始时只有一个任务在运行,但几分钟后,你会看到任务数增加到5个,因子开始快速进入。

试着再次运行客户端,用更多的数字来计算因子。

清理工作
当你全部完成后,记得使用CDK来销毁云计算形成的堆栈,这样你就不会为你不再需要的集群收费了。

cdk destroy --app "dotnet run --project CDK/CDK.csproj" –f

确保destroy命令真的删除了你的ECS集群。使用AWS控制台验证该集群不再运行,以确定你不会为一个你不再需要的集群收费。



今天先到这儿,希望对云原生,技术领导力, 企业管理,系统架构设计与评估,团队管理, 项目管理, 产品管管,团队建设 有参考作用 , 您可能感兴趣的文章:
领导人怎样带领好团队
构建创业公司突击小团队
国际化环境下系统架构演化
微服务架构设计
视频直播平台的系统架构演化
微服务与Docker介绍
Docker与CI持续集成/CD
互联网电商购物车架构演变案例
互联网业务场景下消息队列架构
互联网高效研发团队管理演进之一
消息系统架构设计演进
互联网电商搜索架构演化之一
企业信息化与软件工程的迷思
企业项目化管理介绍
软件项目成功之要素
人际沟通风格介绍一
精益IT组织与分享式领导
学习型组织与企业
企业创新文化与等级观念
组织目标与个人目标
初创公司人才招聘与管理
人才公司环境与企业文化
企业文化、团队文化与知识共享
高效能的团队建设
项目管理沟通计划
构建高效的研发与自动化运维
某大型电商云平台实践
互联网数据库架构设计思路
IT基础架构规划方案一(网络系统规划)
餐饮行业解决方案之客户分析流程
餐饮行业解决方案之采购战略制定与实施流程
餐饮行业解决方案之业务设计流程
供应链需求调研CheckList
企业应用之性能实时度量系统演变

如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:

MegadotnetMicroMsg_thumb1_thumb1_thu[2]

作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 该文章也同时发布在我的独立博客中-Petter Liu Blog。

posted on 2022-01-08 11:11  PetterLiu  阅读(102)  评论(0编辑  收藏  举报