ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

仿真云平台从零搭建:架构解析与避坑实战

仿真云平台从零搭建:架构解析与避坑实战 简介《Pera.SimCloud仿真云平台》是首届中国工业互联网大赛获奖工业APP巡览系列之三来自安世亚太的专题报告。资源适合工业互联网平台架构师、仿真工程师、工业APP产品经理及高校相关专业学生用于把握获奖仿真云平台的整体轮廓与落地场景。文档以图文形式呈现了仿真云生态系统、Pera.SimCloud平台架构、面向不同用户的门户设计以及用户远程登录桌面进行仿真分析等关键内容图表清晰能够帮助读者快速理解云端仿真平台的组成模块、典型应用方式以及平台化服务价值。资源包仅1个PDF文件大小2.98MB下载后无需解压在PC、平板或手机上均可直接阅读。目前已有53人学习浏览作为行业案例参考或论文素材对撰写工业互联网解决方案、规划仿真服务产品均有实际借鉴意义。1. 仿真不上云的日子卡死的不只是算力第一次接触Pera.SimCloud这个名字是在一次制造业数字化转型评审会上。甲方买了三套结构仿真软件月度license报告显示利用率平均不到三成——有人开着前处理界面去吃午饭授权挂在手里不释放另一边新产品组的网格划分任务排到了深夜。仿真上云不是把界面换成浏览器外壳而是把“人在桌面上操作软件”和“求解器在机房算题”这两件事拆开浏览器负责交互HPC池化算力license按需取用。这也是首届中国工业互联网大赛获奖工业APP巡览对大方向上的判断真正的工业APP是把仿真能力封装成可共享、可编排、可计量的服务而不只是给传统软件套一层网页皮肤。这篇笔记就围绕这个方向展开适合正在评估仿真上云、或者打算自己搭一套仿真云底座的仿真工程师与IT运维。2. 仿真云的架构分水岭交互、调度与License如何拆开又协同2.1 仿真云平台和远程桌面不是一码事交互与求解为什么要拆开传统仿真软件的工作模式是“一人一机一License”前处理、求解、后处理全在一个桌面进程里。License从打开软件时就checkout用户去接杯水、画半天网格授权都占着。算力也被锁死在本地工作站的内存里模型一大就得换机器。这是仿真资源利用率低的第一个黑洞。仿真云平台的思路就是把这串动作拆开。前处理保留在浏览器端的轻量化窗口里负责几何导入和边界条件设置求解器下沉到HPC节点以批处理作业形式运行后处理不再加载整套结果文件而是按需拉取特定步数的数据。Pera.SimCloud这类平台把这样一个三段式流程封装成Web操作用户在项目空间里提交任务、看状态、取结果业务上叫“工业APP”技术上本质是一个作业生命周期管理系统。这个拆法带来三个直接收益一是License只在求解阶段被占用前处理阶段完全不再消耗授权二是模型规模不再受个人电脑内存限制三是多个项目可以共享一个算力池按优先级排队。反过来说如果只是把Windows桌面投射到网页或者给仿真软件套一个远程鼠标键盘方案那只是“屏幕搬家”以上收益一个都拿不到。这也是判断一个平台是不是真仿真云的关键指标。2.2 VDI还是容器化把旧软件搬上云和把能力做成服务是两条路做仿真云平台技术调研时最先遇到的就是路线之争。VDI方案把完整Windows工作站搬到服务器上用户远程看到的是完整桌面。容器化方案则把每个求解器封装成镜像前端是Web界面后端接调度器。两条路都能叫“仿真云”但完全是两种交付形态。对比维度VDI方案容器化调度器方案交付形态整机桌面投射Web应用批处理作业对旧版本软件的兼容性高几乎无损中需要封装适配License管控弱随桌面会话占用强按作业排队取用多租户配额与计费弱不好按项目拆分强天然按作业计量实施周期快一两周能上线慢需要Web团队配合适合场景内部电脑集中管控工业互联网平台、多部门共享算力我一般会提醒用户如果核心痛点是数据安全、IT要收回电脑权限VDI足够如果目标是像Pera.SimCloud那样对外输出仿真能力或者集团里多个研发部门共用一套资源按作业调度的容器化架构才是正解。工业互联网平台常说的“把工业知识封装成工业APP”在仿真领域落地时靠的也是这套后端服务化能力而不是远程桌面。2.3 仿真云的资源语义CPU、License、GPU、存储分别由谁控制无论选哪条路线一套仿真云底座至少要管住四类资源而且它们的控制方式完全不同。很多项目上线后才补课就是因为没搞清这四类资源各自归谁管。资源控制方配置入口典型问题CPU核数调度器Slurm分区与QoS单用户独占集群License授权服务器License feature名调度器联动作业启动后抢不到授权被杀GPU可视化编码/求解器计算容器运行时显卡驱动两者用途混用存储共享文件系统本地盘挂载点与作业脚本scratch与结果区不分IOPS爆掉CPU核数由调度器控制。用户在网页上选核数对应的是调度器里的分区和QoS规划时按“每作业核数×并发作业数”核算总量而不是简单数机器核数。License由授权服务器控制。像FlexNet这类工具会在求解器启动时校验并发数平台要做的不是绕过它而是在调度层预留license排队。主流的做法是把feature名写进作业脚本让调度器等授权释放后再启动作业把“运行时报错”变成“队列中等待”。GPU要分两种用途一是给远程可视化做编码加速二是给支持GPU的求解器做真正的计算加速。两者不能混用否则会出现“显卡看着是A100但仿真计算一点没用上”的翻车现场。存储则要拆分scratch和结果区scratch是作业运行时的临时空间必须靠近计算节点结果区是持久化空间负责竣工验收和下载。这四类资源在部署阶段就要映射到调度器的配置和挂载点上后面调参才有的放矢。3. 自己从零搭一套仿真云底座四个可抄作业的步骤如果团队打算自建仿真云建议先搭一套最小闭环不急着追求功能齐全。最小系统只需要一台管理节点Web API调度控制、两台计算节点跑求解器、一块共享存储。全部使用开源组件架构上留出扩容口就行。3.1 用Rocky Linux把底座备齐Docker、调度器、GPU运行时计算节点统一装Rocky Linux 9.x管理节点装Slurm控制端计算节点装slurmd。Docker负责求解器容器运行时如果有远程可视化GPU编码需求还需要装nvidia-container-toolkit。# 计算节点基础环境准备 sudo dnf update -y # 安装Docker CE sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl enable --now docker # 安装nvidia-container-toolkit有GPU编码或GPU求解需求时 sudo dnf install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker # 安装Slurm worker端与NFS客户端 sudo dnf install -y slurm-slurmd slurm-pmi nfs-utils sudo systemctl enable --now slurmd这段命令做完节点已经具备“启动容器、注册进调度集群、挂载共享目录”三个基础能力。注意nvidia-ctk runtime configure执行后必须重启Docker否则docker run --gpus会报unknown runtime。Slurm的节点注册先不急等管理节点slurmctld起来后再一次性配置分区。节点角色建议按下面这张表划分别把管理节点和计算节点混用节点角色安装组件磁盘规划管理节点slurmctld、Web API、NFS Server系统盘结果盘计算节点slurmd、Docker、nvidia-container-toolkit本地NVMe作为scratchLicense服务器license daemon轻量可虚拟机管理节点额外安装slurmctld和MariaDB用于记账。第一套环境可以不起slurmdbd直接让slurmctld管理队列能少一个排错面。Rocky下的安装包名是slurm-slurmctld装完先别急着启动等配置文件写好了再拉起。3.2 把求解器封装成镜像容器里只放求解器不放前处理封装求解器镜像有一条原则镜像里只装求解器运行库和命令行入口不装图形界面。原因是云平台里所有人的前处理都在浏览器端完成容器只需要能被调度器以命令行方式唤起就够了界面装进去只会让镜像膨胀、启动变慢。FROM centos:7 # 仿真求解器大多依赖老版本运行库不建议追新基础镜像 RUN yum install -y libXext libSM libXrender libGL \ mkdir -p /opt/solver /scratch /result # 拷贝求解器安装目录按实际安装包调整路径 COPY solver_install /opt/solver/ # License服务器地址通过环境变量注入不写死在镜像里 ENV LICENSE_HOSTlic-server.example.local \ LICENSE_PORT27000 \ MLM_LICENSE_FILE27000lic-server.example.local # 容器入口是命令行脚本接收模型路径与scratch路径 ENTRYPOINT [/opt/solver/bin/run_solver]这个Dockerfile的核心是环境变量注入和目录规划。/scratch在运行时被调度器映射到计算节点的本地NVMe盘/result映射到共享存储的作业目录。License地址由平台统一注入避免在镜像里埋IP后期授权服务器迁移时不用重打镜像。镜像打完后先手动跑一次docker run --rm -v /tmp/model:/scratch solver-image --help能打印出求解器的参数帮助就算成功。这一步翻车最多的不是软件配置而是CentOS 7容器内缺字体和图形库求解器启动时做license图形校验直接崩溃日志里只有一句缺少xxx.so。遇到这种问题就回到Dockerfile里把缺的库补上重新构建。离线环境里镜像传递用常规做法先导出再导入# 在有网的构建机上打镜像导出为压缩包 docker save solver-image:1.2 | gzip solver-image-1.2.tar.gz # 拷到计算节点后加载 docker load solver-image-1.2.tar.gz镜像要保留版本标签别总用latest。仿真求解器版本和模型格式强相关用户模型用的是旧版网格平台升级了解析器老模型可能直接打不开保留多版本镜像才能做到平滑回退。3.3 从Web表单到Slurm作业一行API把任务提交接起来Web端和后端的连接点是任务提交API。典型流程是用户在页面勾选求解器、模型、核数后端拿到参数生成sbatch脚本调用sbatch提交。下面这段Python代码就是最小实现。# quick_submit.py import subprocess import tempfile def build_sbatch(model_path: str, solver: str, cores: int) - str: job_name model_path.split(/)[-1][:8] return f#!/bin/bash #SBATCH --job-name{job_name} #SBATCH --nodes1 #SBATCH --ntasks-per-node{cores} #SBATCH --cpus-per-task1 #SBATCH --output/result/{job_name}/log_%j.txt #SBATCH --licenses{solver}_feature:1 export MLM_LICENSE_FILE27000lic-server srun /opt/solver/run_{solver} --input {model_path} --scratch $SLURM_JOB_ID def submit(model_path: str, solver: str, cores: int) - str: script build_sbatch(model_path, solver, cores) with tempfile.NamedTemporaryFile(w, suffix.slurm, deleteFalse) as fd: fd.write(script) result subprocess.run([sbatch, fd.name], capture_outputTrue, textTrue) if result.returncode ! 0: raise RuntimeError(result.stderr) return result.stdout.strip().split()[-1] # 返回作业ID代码里有两个容易被忽略的细节。一是--licenses参数它让调度器在启动作业前检查license是否可用不可用就排队等待避免作业起来后因授权不足被求解器杀掉。老版本Slurm不支持这个参数需要在外部用license pool脚本定期查询替代方案是把license当作通用资源接入调度逻辑。二是$SLURM_JOB_ID作为本地scratch目录名保证同一节点并发多个作业时各自占用不同临时目录不会互相覆盖结果文件。把submit()接到任意Web框架的路由里一个最小可用的任务提交链路就通了。Web框架负责把用户上传的模型转成服务端路径再把solver与cores参数透传给这个函数。模型上传这里有个隐藏坑超过2GB的模型文件不要走Web服务转发会占用大量内存和连接常规做法是前端直传对象存储API只传路径引用。3.4 上线前的最小验证三步确认平台闭环装完计算节点、打好镜像、跑通API后先不要急着接入用户按下面三步验证闭环# 第一步查看节点是否全部注册并进入idle状态 sinfo -N -o %.10n %.6t %.10c %.10m %G # 第二步提交一个1核的echo作业验证调度链路 sbatch --wrap echo hello_simcloud hostname squeue # 第三步用真实模型提交一次求解作业检查日志和结果文件 sacct -j 1024 --formatJobID,JobName,State,Elapsed,ExitCode cat /result/frame_plate/log_*.txt三步分别对应“节点调度可用”“作业排队可用”“求解闭环可用”。见过不少平台卡在第二步——节点明明idle作业提交后却一直Pending最后查出来是管理节点和计算节点的slurm.conf版本不一致握手失败但不报错。这类版本问题在装的时候就要用sinfo和slurmd -C逐项核对。验证通过后建议把“提交作业→等待调度→启动容器→写入结果→前端可见”这个链路截图存档作为后续问题定位的基线。后续任何改动先拿这个基线用例回归一遍比查半天日志都快。4. 仿真云跑得快不快先盯两组参数并发配置与存储IO平台搭好后决定用户体感的是参数层。仿真云的性能瓶颈几乎从来不在“CPU不够快”而在并发策略和存储IO这两处。Pera.SimCloud这类商用平台在做交付时通常会对这两组参数给出默认值自建时就要自己调出来。4.1 并发配置三件套用户数、作业核数与License并发上限第一组参数管“同一时刻有多少活能干”。定这几项参数时先要盘点手上的总量集群总核数、授权服务器允许的并发feature数、日常活跃用户数。有了这三个数再套下面的基准。参数建议基准说明同时在线用户数License最大并发数×0.7留出余量避免全部在线用户同时提交时把授权打满单个用户最大核数集群总核数÷预计活跃作业数防一个人占满整个集群其他部门排队到天亮默认单作业核数按中小网格规模标定默认核数低了作业等得久高了浪费分区策略交互短作业/批处理长作业分开前处理交互任务优先占cont批量仿真求解用batch举个具体例子128核集群单作业默认24核并发作业上限取5那么单个用户的GrpTRES设96核4个作业就能防止一个用户把集群占满而同在线用户数按license并发10个乘以0.7算就是7人。这套数字不是拍脑袋是从“每个并发量下等待时长”的曲线里试出来的。# 配置单用户资源上限示例 sacctmgr modify user zhangsan set GrpTREScpu96Slurm在配置层面要打开backfill调度否则大作业排队时会挡住后面的小作业形成“一人占坑、全员陪等”。核心配置如下SchedulerTypesched/backfill SelectTypeselect/cons_tres SelectTypeParametersCR_Core_Memorycons_tres的作用是把调度粒度从“整节点”细化到“核内存”小作业就能插空落到大作业留下的缝隙里。配合License排队参数后调度器会同时考虑CPU、内存、License三类资源哪一类不够都会让作业停在队列里而不是等到运行时报错。License来自Slurm配置里的License字段feature名要跟授权服务器上的名字完全一致。4.2 Scratch与结果存储IOPS比容量更容易先爆存储是仿真云运维里踩坑最多的地方。很多团队第一版只规划了共享存储容量忽略了IOPS结果显式动力学算例一跑起来CPU利用率只有百分之二三十。看监控时CPU没满但作业就是跑得慢卡在存储的写等待上。原因是显式求解器每个时间步都会产生若干小块状态文件大量小文件随机写在NFS上时网络文件系统的元数据开销会远远大于数据写入本身磁盘成了木桶短板。这是仿真云平台运维里最常见的一个误区只算容量够了不算IOPS再强的CPU也白搭。正确的做法是把Scratch和结果区拆开。Scratch是作业运行时的临时目录必须放在计算节点的本地NVMe盘上作业开始时创建以$SLURM_JOB_ID命名的目录跑完把结果打包传回共享存储后立即删除。NVMe盘的随机IOPS比NFS高一个数量级这一步通常能把显式计算的墙钟时间降三成以上。# 在slurm.conf里为每个节点声明临时盘空间 NodeNamenode0[1-4] Gresscratch:500G # 作业脚本内部使用本地临时目录的写法 SCRATCH_LOCAL/scratch/${SLURM_JOB_ID} mkdir -p ${SCRATCH_LOCAL} srun /opt/solver/run --input model.db --scratch ${SCRATCH_LOCAL} cp -r ${SCRATCH_LOCAL}/result /result/${SLURM_JOB_ID}/ rm -rf ${SCRATCH_LOCAL}结果回传要封装成脚本并对小文件先做tar打包再拷贝避免上千个小文件逐个走NFS元数据操作。结果区建议用ZFS或Lustre这类适合大文件顺序读写的文件系统容量规划按“活跃项目结果×3”预留。还有一个容易被忽略的环节作业跑完后的scratch不要立刻删留一个debug保留期比如24小时由cron定期清理这样用户当天晚上来要中间文件时还能找得回来。4.3 远程可视化参数分辨率、帧率、编码器这样调前处理操作和后处理旋转场景对远程可视化的流畅度要求不同。前处理要求即时反馈拖一个关键点光标要跟手后处理主要是看云图可以接受轻微延迟。默认参数通常偏保守自建时要针对这两个场景分别调。参数前处理建议值后处理建议值说明分辨率1920×10801920×1080超过2K后码率翻倍体感提升有限帧率10fps8fps前处理交互要高一点后处理可降编码器H.264硬件编码H.264硬件编码CPU编码在高分辨率下性能断崖式下降空闲降帧60秒无操作降到2fps300秒无操作降到1fps大幅压缩带宽占用帧率是体感和性能的分界点。仿真操作不像打游戏10fps已经能满足绝大部分拖拽和旋转操作低于5fps时用户会感到明显的画面迟滞。带宽方面1080p10fps在H.264硬件编码下大约占2~4Mbps如果这个数字跑到10Mbps以上优先查是不是走成了CPU编码或帧率默认30fps没改。GPU编码卡的数量按并发会话估算一张T4可以支撑并发4到6路的10fps编码会话。如果线上同时操作人数超过这个数优先限制前处理并发而不是堆显卡。前处理会话是持续性连接占着编码器不放后处理会话通常是间歇操作可以做成按需连接空闲30秒自动断开节省编码资源。5. 仿真云平台上线避坑指南五个高频事故的现象、原因与解法部署和交付阶段最常遇到的问题集中在这五个方向每一条都是真实上线血泪经验按“现象→原因→解决”的顺序整理排错时直接对照检查。5.1 页面操作一卡一卡先查帧率再查编码器现象浏览器里打开前处理界面拖拽模型时画面明显迟滞用户反馈“一步一卡”。运维看网络带宽占用在8Mbps以上且CPU占用飙升。原因远程可视化默认配置跑在CPU编码上而且帧率设成了30fps。CPU软编码在1080p分辨率下计算量巨大既占用计算节点的CPU资源又产出过高码率最终两头堵。解决在可视化服务端配置里把编码方式改成H.264硬件编码并将帧率降到10fps。改完后带宽会回落到3Mbps以内画面拖拽手感反而提升因为编码延迟从80ms级降到20ms级。GPU编码资源不够时优先保前处理会话后处理会话允许降帧。改完参数后要拿同一台客户端做前后对比别只盯着服务端的CPU曲线。5.2 作业运行几分钟就被杀死License排队与作业排队必须联动现象用户提交作业后状态从running变成failed求解器日志没有任何明显报错只是在启动阶段卡了几分钟然后abort。原因最常见的是License并发达到上限。调度器看到CPU和内存有空闲就把作业调度起来但求解器进程向授权服务器申请feature时报并发上限握手失败后自动退出。有些版本会重试几次才退出所以表现为“运行几分钟后失败”与真正的计算崩溃很难区分。解决在sbatch脚本里加上--licensessolver_feature:1让调度器在作业排队阶段就检查License资源。同时要在slurm.conf的License字段里声明授权服务器地址slurmctld才能感知到授权状况。部署License监控脚本用lmstat -a -c 27000lic-server定期抓取占用情况把License冲突次数的趋势图做到监控面板上。遇到紧急生产任务时临时抬高license授权数不是解法限流并发用户数才是治本。5.3 容器里跑得比工作站还慢MPI跨NUMA访问现象用户反馈同一个模型在云平台上跑比原来在单台工作站上还慢20%。检查CPU利用率却发现所有核都在干活没有排队等待。原因容器默认继承了宿主机所有NUMA节点MPI进程被调度器分配到了跨NUMA的核上内存访问走了远端路径带宽猛降。单台工作站因为物理拓扑简单通常不会出现这个问题迁移到多路服务器容器环境后就暴露出来。解决在sbatch脚本里显式绑定CPU和内存配置#SBATCH --cpu-bindcores和#SBATCH --mem-bindlocal让作业的MPI进程固定在同一个NUMA域内。# 避免容器仿真跨NUMA的作业脚本片段 #SBATCH --cpu-bindcores #SBATCH --mem-bindlocal srun --cpu-bindcores --mem-bindlocal /opt/solver/run ...有个必查项宿主机BIOS开了超线程后核心编号是交替排列的直接用默认分配可能导致同一MPI进程的两个rank落在同一个物理核上性能折损更厉害。用lstopo输出拓扑图核对分区配置比在代码里反复试参数更快。容器启动时还要注意--cpuset-mems参数把它限制到单NUMA节点。5.4 计算节点重启后作业全部Pending检查slurmd自启现象某台计算节点重启后平台上所有作业开始排队sinfo显示该节点drain状态一直不变。原因slurmd服务没有设置为开机自启节点重启后没有向管理节点重新注册。管理节点认为它还在处理旧作业会继续保持drain状态导致调度器认为集群可用核减少大量作业排队。解决在计算节点上执行systemctl enable --now slurmd然后到管理节点用scontrol update NodeNamenode03 Stateidle把节点重新置为idle。建议在部署脚本里把slurmd、docker、nfs-utils三者的开机自启一次性写入初始化脚本避免每次重启都要人工介入。这个问题在无人值守的深夜重启场景下最伤人第二天早上用户全在问为什么作业跑了一晚上都没动。5.5 结果太大拖垮浏览器限制步数与服务端抽稀现象后处理打开一个大型瞬态仿真结果网页加载到一半直接崩溃提示内存不足或连接断开。原因浏览器端的WebGL渲染能力有限完整结果文件动辄几GB几十万个网格单元全量推给浏览器撑不住是必然的。这跟本地桌面软件不一样桌面软件吃的是本机内存浏览器还要额外过一层传输和编码。解决在结果导出环节做抽稀。后端只导出用户在界面勾选的物理量和时间步范围对于所有时间步都需要的用户按等间隔步数抽样导出。同时在前端限制单次渲染的网格单元数超过阈值提示用户切换到子区域。这些逻辑在架构上属于“后处理服务”如果平台没有单独的后处理服务可以先限制导出步数作为临场手段。运维侧还要加一道防线对单个结果文件的下载大小做上限控制超大结果一律走异步打包避免同步下载拖垮Web服务。6. 从能用到好用做一次平台体检再谈混合云该不该上系统稳定运行后能让平台持续用得下去的不是功能数量而是运营数据。接手一套仿真云平台时第一件事不是加功能而是把license利用率和作业等待时长两份报表拉出来这两个指标基本能判断平台健康度。license利用率计算的是“实际被占用的feature时长÷授权总时长”。如果这个值长期低于50%说明买多了或者用户习惯不好如果频繁达到100%而且冲突日志在增长说明并发规划接近上限该扩容或错峰。作业等待时长看的是从提交到启动的间隔中位数超过30分钟就要检查调度参数是否过保守、是否有大作业长期占坑。混合云弹性是另一个经常被高估的方向。不少团队上了平台第一年就规划混合云实际做下来才发现价值有限。判断标准很简单本地排队平均时长超过30分钟云端求解时间大于数据传输时间数据经过脱敏且可被云端作业限制访问三个条件全部满足才值得做。场景适合时常规做法是作业在本地排队热点模型预推送到云端存储云端作业结束后只把小体积的抽稀结果文件传回大结果留在对象存储里按需下载。这样能控制成本也能避免“算一夜、传三天”的尴尬。最后讲一个教训。上线的第一套仿真云平台当时没做license饱和监控第二个月业务部门拿着月度报表找过来才知道深夜批处理时段license冲突堵了十几个作业。从那以后做的每一套平台都先装好报表再开放用户。运营数据是平台的眼睛希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进