iOS开发 实习产出(给我自己看的 笔记而已)

news2026/4/30 0:48:18
app总览这个 app 是一个通过多设备协同进行 AR 数据采集 / 录制 / 上传的 iOS 应用主界面由 4 个一级 Tab 组成背后由一组领域模块支撑。一、主界面 4 个板块一级 Tabenum Tab {case prepare, record, upload, profile}Tab入口 View作用主要目录preparePrepareV2录制前准备配对蓝牙夹爪、选择 UMI 版本、多机同步等src/prepare_v2/recordRecordViewAR 相机录制主界面src/record/,src/record_v2/uploadUploadQueueView录制产物排队上传S3 / coscenesrc/upload/,src/upload_v2/,src/s3/,src/coscene/profileProfileView用户 / 设置src/user/,src/settings_ui/二、顶层 Dependencies各 Tab 共享的核心 Managerfinal class Dependencies: ObservableObject {let cfg: Utils.ObsRwUserConfiglet peers: PeersManagerlet ble: BluetoothEncoderManagerlet up: UploadManagerlet ar: ArManagerV1let inference: InferenceManagercfg用户配置src/config/,src/config_v2/peers多设备同步 / 发现src/peers/,src/nw/ble蓝牙夹爪编码器src/bluetooth/,src/gripper/up上传队列src/upload/,src/upload_v2/arARKit 姿态 / 轨迹src/ar/,src/ar_v2/,src/ar_v3/,src/arkit/inference端侧推理src/inference/三、按业务领域划分的支撑模块大致可以分成几层AR 传感ar/,ar_v2/,ar_v3/,arkit/,calib/标定,math/,opencv/外设 / 硬件bluetooth/,gripper/UMI2/UMI3 夹爪,usb/,device/,robot/多机协同peers/,nw/网络层,pubsub/,stream/录制流水线record/,record_v2/,camera_ui/,image/,img/,quality/,task/上传 / 云端upload/,upload_v2/,s3/,coscene/,totp/推理与实验inference/,expr/,stress_test/,nedf2/配置 用户config/,config_v2/,user/,settings_ui/UI / 基础设施ui/,ui_kit/,swift_ui/,foundation/,utils/,log/,thread/,py_like/,tools/四、一眼速览业务主线一条完整的使用链路基本就是 4 个 Tab 串起来的prepare连夹爪 选 UMI3 前缀 多机同步→recordAR 轨迹 拍摄 夹爪编码→upload本地队列上传到 S3/coscene→profile账号 / 设置。从录制到落盘的流程下面从按下开始到成为本地一条可上传的记录为止完整讲一遍录制数据在 app 内的落盘流程。为了看得清我按谁触发 → 在哪里 → 产生什么分阶段走。一、按下开始生成本次录制的身份证入口在录制页面的按钮它并不直接开始写文件而是做一串前置校验再把开始命令既广播给自己、也广播给同组的其他设备必须所有设备都处于空闲且健康状态。多机同步时只允许右腕那台触发。如果是 UMI3 的腕部机位必须先在首页填过合法的硬件版本前缀300-310且与当前相机位置一致否则弹窗拦下。校验通过后主机做两件事作为本次协同录制的身份锚:生成一个全局唯一的协同标识本次录制所有设备共用一个保证多机产物能合并成同一条记录。生成一个以当前时间命名的输出目录名三台机都用同一个名字。然后把开始这一条命令带上目录名、协同标识、起始 UNIX 时间一起广播出去。二、各端启动在文件系统里开出这一录制坑位每台设备的录制总控收到开始命令后在专门的帧队列里执行:在Documents/时间戳/下创建本次录制的独立目录。给视频写入器指定recording.mp4作为输出路径并按当前屏幕方向设置画面 transform、按夹爪代际选不同比特率老一代 10 Mbps新一代 2.5 Mbps。给深度图写入器指定同一目录。把本次录制的先验元数据组装成一个起始快照放进内存中的录制会话包含协同标识、用户指纹、多机模式、任务标签与描述、起始时间、起始方向、相机帧率、相对于主机的初始位姿等。状态切到录制中并广播模式变更事件。注意真正的帧数据还没有落盘只是打开了文件句柄和建立了内存容器。三、录制中边跑 AR 边把三路数据往外写ARKit 每出一帧都会走到录制中的分支。每一帧做三件事帧级问题检测是否离物体太远、跟踪是否失稳、蓝牙夹爪是否掉线、镜头是否装对……这些问题以第 N 帧出现了哪些问题的形式暂存在内存里。把标量数据追加到内存每帧追加一条记录 时间戳 ARKit 位姿 夹爪宽度 夹爪角度 其它辅助量。还会把第一帧单独保留用于最后生成元数据时填分辨率、深度图尺寸等。把像素/深度数据真正写入文件视频写入器把当前画面缩放后写进recording.mp4。深度图写入器把场景深度追加进depth_images.tar如果某一帧 ARKit 没给深度图会复用上一帧避免张数对不齐。所以录制期间磁盘上持续在增长的是 mp4 和深度图包其它每帧标量还在内存里累积等结束时再一次性写入。四、按下结束先停写、再定稿结束按钮也走同样的广播路径。录制总控收到结束命令后状态切到结束中广播模式变更。调用视频写入器和深度图写入器的 finish 等待完成确保 mp4/深度包都完整落盘。交给产物定稿器进行最后的收尾。五、定稿把一次录制变成一个可归档的目录这是整个流程最关键的一步都发生在产物定稿器里5.1 跑一遍离线质量检查在所有帧都录完后对采到的数据再跑一次状态机质检把这些事后才能发现的问题合并到之前的帧级问题里得到最终的问题字典。5.2 帧数一致性校验这一步会比较三者内存里记录的帧计数 ↔ 每帧标量时间戳的条数 ↔ 实际写进 mp4 的帧数 ↔ 深度图的帧数。如果帧计数和时间戳条数对不上直接判为严重存储异常广播一个存储异常事件本次录制作废。视频/深度图允许一定偏移随时长变化的容忍值。超过就判异常作废。如果三者都对得上才继续往下。5.3 把内存里的帧数据序列化到磁盘把前面累积的时间戳 / 位姿 / 夹爪宽度 / 夹爪角度 / 每帧问题 / 附加字段用 BSON 编码成frame_data.bson写进录制目录。5.4 腕部机位额外复制 3 张 ROI 掩膜如果这台是左腕或右腕会把夹爪宽度检测用到的 3 张 ROI 掩膜图roi_mask_0/1/2.png从Documents/gripper/拷贝到录制目录里用于事后离线重现夹爪宽度的计算。5.5 生成校验和 元数据 JSON对三个必需文件recording.mp4、frame_data.bson、depth_images.tar各算一个 sha256。生成metadata.json里面大致有代码版本、本机录制的唯一 id、协同标识、设备代际、用户 id、用户指纹、多机模式、相机位置头/左腕/右腕、硬件版本号、任务标签/描述/执行 id、起始时间ISO8601 UNIX、时长、帧数、帧率、视频宽高、深度图宽高/量程/位深/帧数、设备机型/系统版本/设备 id、起始方向、本机相对于主机的初始位姿、帧级问题、三个文件的 sha256 列表。到这一步磁盘上该目录的形态就稳定了长这样Documents/20260429_121855_xxxx/recording.mp4frame_data.bsondepth_images.tarmetadata.jsonroi_mask_0.png # 仅腕机位roi_mask_1.pngroi_mask_2.png六、进入上传队列成为 app 里的一条记录定稿器最后一步会把这个目录交给上传管理器。上传管理器做的事再做一次保护目录不能是空的且必要文件齐全否则拒收这时候直接失败返回。以本机录制 id 作为主键抽取元数据里的关键字段文件夹名、起始时间、任务标签、任务执行 id、用户指纹、相机位置、帧数、时长、本次的问题、总字节数组装成一条队列条目初始上传状态为待上传。在主线程做原子 append如果队列还在从磁盘加载中就挂到加载完成后再执行的延迟队列里避免先 append 又被覆盖。如果已有同名目录就拒绝重复入队。否则追加到内存队列并立刻把整个队列序列化回磁盘让 app 被杀掉后也不会丢记录。定稿成功后广播一个录制已保存事件携带目录、时间、元数据。底部 Tab 栏的上传角标数、上传页面的列表等都是订阅到这个事件之后刷新的。七、异常路径什么情况下这条记录会消失结束过程中任一步失败比如第一帧始终没到、元数据生成失败、sha256 失败、一致性校验失败、写frame_data.bson失败、写metadata.json失败、入队失败finish 里的 defer 会把整个录制目录从磁盘上删掉并广播结束失败事件状态回到空闲。用户主动取消同样是在空闲化之前把正在写的视频 / 深度图取消并把目录整个删掉。帧数严重不一致在发布存储异常事件后本次记录不会被加进上传队列也会随失败路径被删除。八、一张数据去向总结来源落点时机每帧画面缩放后recording.mp4录制中逐帧写每帧场景深度depth_images.tar录制中逐帧写缺帧时补上一张每帧时间戳 / ARKit 位姿 / 夹爪宽度 / 夹爪角度 / 每帧问题frame_data.bson结束时一次性写前置信息协同标识、任务、起始时间、起始方向 首帧分辨率 事后统计时长、总帧数、sha256 设备信息 相机位置 硬件版本metadata.json结束时一次性写夹爪 ROI 掩膜仅腕机位roi_mask_0/1/2.png结束时从Documents/gripper/复制目录元信息状态待上传、问题摘要、字节数等磁盘上的上传队列序列化入队成功后立即持久化一句话概括录制期间 mp4 和深度图是边拍边写其余结构化数据全部攒在内存里结束时由产物定稿器做一致性校验、一次性把内存数据写成 BSON JSON 校验和最后挂进持久化的上传队列。入队的那一瞬间它才算是 app 里一条可被看到、可被上传的录制记录。由app上传到平台的流程一、上传被触发的几种方式录制结束入队后app 不会自动上传。真正发起上传的入口只有以下几种用户主动触发在上传Tab 选中若干条记录点上传按钮也可以上传所有待上传。协同录制时被广播带起来协同录制中主机一旦在云端建好/复用了这条录制记录会通过同组广播把哪个录制对应哪个记录名告诉所有从机从机收到广播后如果自己队列里有同名待上传条目会自动开跑避免每台从机各自再去云端建一条同名的空记录。app 启动时的孤儿自愈上次 app 在上传中途被系统杀掉磁盘上残留一些标记为上传中的条目启动后会被一律重置回待上传等用户再次手动上传。失败重试失败的条目会被保留在队列里用户也可以选中、点重置为待上传再点上传。二、调度把选中的几条变成一个串行任务入口接收到一组要上传的文件后做这几件事队列还在从磁盘加载时直接挂起。app 启动后队列是异步加载的加载没完前主动避让调用被排到一个加载完后再执行的延迟队列里。去重入队把每条记录用文件夹名做去重只追加未在队列里的。判断是否已经有上传循环在跑如果已经在跑只把待跑总数加上去复用现有任务否则起一个新的后台异步任务开始 while 循环。后台循环每次做一件事从队列取下一条 → 把它的状态置为上传中 → 跑这条文件的上传 → 拿到结果成功 / 失败 / 取消→ 更新这条状态 → 累积成功/失败计数和已传字节数 → 把进度推给 UI → 进入下一条。整个 app 同一时间只跑一条串行但 UI 会持续看到全局进度已完成几条/共几条、已传字节/总字节、当前文件名、当前文件已传/总大小。为了避免高带宽下 URLSession 一秒上百次回调把主线程刷爆进度回调是在后台先累加 / 校正再每一帧派一次到主线程更新同一帧里所有进度字段一致更新。三、单条上传先做通用准备不管最终上传到哪个云每条记录都先在本地经过同一套准备3.1 路径与元数据校验找到Documents/时间戳/这个录制目录确认它真的存在、确实是目录。必须有metadata.json并且能正常解码成元数据对象解码失败直接报错带可读路径信息。3.2 选打包工作目录按当前选择的上传目标决定.tar.gz放哪儿DM3 平台放在Documents/dm3UploadResume/目录键/这种持久化 staging 子目录里。这样即使 app 重启 / 进程被杀下次进来还能续传。其他三种目标放在系统临时目录里跑完即扔。目录键是把 (录制目录名, 协同标识, 相机位置) 三段做百分号编码、用下划线拼起来这样下次 app 启动后能反向解析出来方便垃圾回收。3.3 打包成.tar.gz先用 tar 打成单文件.tar。然后做 gzip这里用了流式压缩每次只在内存里持有 1 MB 数据。如果用最直观的先把整个 tar 读进内存再压几 GB 录制立刻把 jetsam 触发然后被系统杀掉。具体做法是自己手写 RFC1952 的 gzip 头/尾10 字节 header 8 字节 CRC32 输入字节数中间走 Apple 系统库的 raw deflate边读边写边算 CRC。DM3 续传场景下如果 staging 子目录里上次的.tar.gz还在且非空直接复用不重新打可以省一次几十秒到几分钟的压缩。3.4 失败/取消时的清理约定整个uploadFile用一个 defer 兜底非 DM3 目标.tar和.tar.gz都在临时目录无脑全删。DM3 目标中间的.tar总是删.tar.gz留在 staging 给下次续传用只有当用户主动取消时才把 staging 整个清掉因为续传也没意义了。DM3 走到网络/服务端错误时故意不清理 staging下次进来 SDK 会用里面的 checkpoint 自动续传。SDK 软件开发工具包一句话别人把现成的功能封装好打包给你你直接调用不用自己从零写底层代码。里面一般包含代码库、接口 示例 demo 文档、配置文件四、四种上传目标分别怎么把 .tar.gz 推走4.1 上传到刻行默认路径这是 app 主要的上传目标流程最长算 sha256服务端要校验完整性。解析业务记录名刻行平台上一次录制等于一条记录三机协同时三段视频要挂在同一条记录下。优先级调度层透传过来的一般是从机收到广播带的本机内存缓存之前收到过广播自己是主机调建立或复用记录接口建好后立即广播给所有从机自己是从机但有同步对端等主机广播最多 15 秒超时降级自建保住可用性。拼好标签和自定义字段任务标签做成一个 label采集人 用户指纹、任务描述 录制时填的描述如果这次录制中检测到距离过远 / 夹爪量程过小 / 夹爪宽度缺失 / 跟踪特征不足这种轻问题给打黄色 SLAM 异常标其他严重问题打红色 SLAM 异常标。拿一次性预签名 URL调生成上传 URL接口传文件名、大小、sha256得到一个有限期的 PUT 直传地址。直传 .tar.gz用 URLSession 做 PUT带 progress delegate 实时回报已传/总数同时起一个每 5 秒打一行心跳日志的并行任务方便排查卡住了到底卡在哪PUT 完成时心跳自动取消。业务登记上传完文件还不算结束。必须再调同步文件信息接口把 (任务执行 id、文件名、大小、时长) 登记到业务侧。这一步要求登录态有效且不是访客如果没登录或是访客文件其实已经在桶里了但本地状态会标失败提示用户已上传未登记。只有走完这一整串含登记成功这条记录才会被标为已完成。4.2 上传到 DM3直接打到阿里云 OSS走的是阿里云 SDK 的分片可断点续传模式封装比较厚但行为很清晰拉 STS 凭证先用登录态 token 找后端要一次性的 endpoint / bucket / region / 路径前缀 (ak / sk / securityToken / 过期时间)。这一步如果失败直接报错不会进上传。构造 SDK 凭证 provider把如何拉 STS安全令牌服务这个动作包成一个同步闭包给 SDKSDK 在内部判断 token 在 5 分钟内将过期时会自动回调它再拉一次新的外面不需要自己起定时器。构造 SDK 客户端每个上传任务一个不全局复用不同账号/region 会切换 endpoint复用反而麻烦构造代价本身很轻。配三个超时/重试单请求 30 秒、整任务最长 24 小时、SDK 自动重试 3 次。endpoint 没带 scheme 时这里兜底加https://苹果 ATS 强制要求。拼云端路径dir/录制目录名_协同标识/相机位置 basename.tar.gz。其中 basename 是head/left/right中的一个相机位置不是这三个就直接透传空就用unknown。三机的协同标识是同一个所以三段录制最终落在同一个云端二级目录下。配置分片任务分片大小 5 MBOSS 限制 100 KB ~ 10000 片checkpoint 目录就是本地 staging 子目录CRC 校验开并把取消时不要删 checkpoint打开取消时由我们自己清避免和续传语义打架。跑上传把阿里云 SDK 那一套 OC 风格的 future 桥成 Swift 的 async进度回调照样转给上层。结果分支成功 → 主动清掉 staging连.tar.gz和 checkpoint 一起用户取消 → 主动清 staging网络/服务端错误 → 故意不清 staging下次进来 SDK 会自动 ListParts 跳过已完成分片继续传服务端孤儿分片不靠客户端 abort 接口而是依赖云端桶上配置的分片清理生命周期策略建议 7 天兜底。冷启动垃圾回收app 每次冷启动会扫一遍持久化的 staging 根目录下面这三种情况之一就把整个子目录删掉目录名解析不出来手撸残留 / 老版本结构(录制目录名, 相机位置) 已经不在当前活跃队列里了7 天没改过文件明显是孤儿。 不会动正在跑的或仍在队列里的。4.3 上传到 S3 / 兼容 S3 协议最简单先校验 S3 连接配置access key、secret、桶、endpoint、region、路径前缀。拼 object key 前缀/文件名.tar.gz。走 SigV4 签名做一次PutObject单次 PUT 把整个.tar.gz推上去进度回调照样转给上层。4.4 上传到自建通用服务走通用的 multipart POST 到用户配置的 URL由一个什么都干一点的客户端封装负责。这条路径主要用于自部署调试。五、状态与进度的写回每条记录贯穿整个上传都在动两组东西5.1 队列里的这一条的状态队列条目的关键字段本机录制 id、文件夹名、入队时间、起始时间、任务标签、任务执行 id、用户指纹、相机位置、帧数、时长、本次的问题字典、问题文字摘要、上传状态待上传 / 上传中 / 已完成 / 失败、上次尝试时间、失败原因、失败分类、字节数。主要写点开始跑这一条 → 状态 上传中成功 → 状态 已完成这条以后不会再被自动重跑失败 → 状态 失败并写入失败原因 / 失败分类详见下一节用户在循环跑到它之前点取消 → 状态从上传中回到待上传并把它从内存队列踢出。每次状态变更都会立刻把整张队列序列化回磁盘的uploadQueue.json同时维护一份.bak这样 app 任何时候被杀掉都不会丢记录。5.2 全局进度UI 看到的几个数字总文件数 / 已完成 / 失败数 / 总字节 / 已传字节 / 当前文件名 / 当前文件已传 / 当前文件总大小。这一组是节流后批量推到主线程的避免 URLSession 高频回调把主线程刷爆。5.3 失败分类失败时不会把原始错误直接展示给用户而是过一遍错误分类器归到几大类网络断开 / 鉴权失败 / 磁盘满 / 服务端 5xx / 业务登记失败 / 其它。这样 UI 上能给用户一个能理解的提示并且后续可以按鉴权失败这种类做统一的退避策略。六、取消、续传与孤儿处理6.1 用户点取消后台循环里会立刻看到取消标记 当前文件那把 async 抛出取消错误当前正在跑这条 → 状态从上传中回到待上传从内存队列踢出循环 break后续未跑的条目 → 整个内存队列被清空但磁盘上的状态仍是待上传DM3 目标的 staging 子目录会被主动清掉续传无意义其他目标的临时.tar.gz由 defer 兜底删掉。6.2 失败保留 重试刻行 / S3 / 通用临时.tar.gz已经被删重试会从头打包再传SDK 的 3 次重试 用户重试都打不进可断点续传语义。DM3staging 子目录里.tar.gz和 SDK checkpoint 都还在用户重试或下次 app 启动自动重试时会复用.tar.gz不重压再让 SDK 自动 ListParts跳过已上传分片继续传。这是为什么.tar.gz会有已存在则复用的判断。6.3 孤儿/碎片清理上传队列那一头app 启动时会重置上传中为待上传避免转圈死锁。DM3 staging 那一头每次冷启动跑一遍前面说的 GC解析失败 / 不在活跃队列 / 7 天未动。云端 OSS 那一头客户端不调 AbortMultipartUpload怕对桶策略形成强依赖孤儿分片由桶级生命周期策略兜底自动清理。七、一张总表整个上传链路的数据流向阶段输入关键动作输出触发用户点按钮 / 主机广播 / 启动重试入队去重 启或复用循环内存上传队列准备录制目录 metadata.json校验 选 staging or 临时目录工作目录打包录制目录tar → 1 MB chunk 流式 gzip CRC32 字节数.tar.gzDM3 持久化 / 其它临时走刻行.tar.gz 元数据算 sha256 → 解析记录名含主机广播→ 拿预签名 URL → PUT → 业务登记云端记录 业务侧已登记走 DM3.tar.gz 元数据 协同标识拉 STS → 构造 SDK 凭证/客户端 → 5 MB 分片 ResumableUpload checkpoint → 成功/失败差异化清理云端桶 同协同标识三段同前缀走 S3.tar.gz S3 配置校验 → SigV4 PutObject 单次 PUT云端桶里一个对象走通用.tar.gz 通用 URLmultipart POST自建服务接收完成状态上传过程中的事件节流推 UI 写uploadQueue.json含.bak 失败分类用户看到的状态 持久化队列取消用户点取消抛 cancel 状态回滚 清 stagingDM3/ 临时其它队列清空磁盘条目仍可重新发起八、几个容易忽略的设计点单条串行app 同一时间只跑一条文件避免几个 GB 的 .tar.gz 并发压垮内存和带宽也方便进度展示。流式 gzip 是命脉录制几分钟就能上 GB整文件读进内存做 gzip 一定 OOM内存耗尽流式 1 MB chunk 是必须的。DM3 续传强依赖持久化目录staging 是.tar.gz SDK checkpoint共生命周期目录它两个必须放在一起单独丢任何一个续传都坏。协同录制的记录名协调靠主机一次广播就把三机的挂哪条记录绑死避免每台从机各自建一条同名孤儿记录是这条上传链路里最微妙的一段一致性逻辑。业务登记是刻行链路的真终点文件就算 PUT 成功没登记成功这条记录就算失败这是为了让业务侧能查得到、能分配训练任务。DM3 直传不依赖客户端 abort服务端孤儿分片靠桶级策略兜底清理让客户端 IAM 只需要上传/列分片权限不需要中止分片部署侧成本更低。用户在上传Tab 选中条目并点上传后后台会起一个串行任务循环跑选中的每条录制目录单条流程是先校验目录与元数据 → 把整个录制目录用 tar 打包再做 1 MB 流式 gzip 压成.tar.gz避免大文件 OOM→ 按目标分发上传成功后写状态、推进度、持久化队列失败按类别记错可重试。两个目标的差异主要在第三步——走刻行CoScene临时目录里产出的.tar.gz算 sha256 后先解析这次录制对应的业务记录主机直接调建/复用接口并广播给从机从机优先用主机广播带的或缓存里的最多等主机 15 秒否则降级自建拿到记录后调云端要一个一次性预签名 PUT URL用 URLSession 直传.tar.gz并实时回报进度传完还要再调一次同步文件信息接口做业务登记任务执行 id、文件名、大小、时长登记成功才算这条完成临时.tar.gz全程跑完即扔。走 DM3阿里云 OSS.tar.gz落在Documents/dm3UploadResume/目录键/这种持久化 staging 子目录里已存在则直接复用不重压先用登录态拉一次 STS 拿到 endpoint/桶/路径前缀和临时 ak/sk/securityToken再把 STS 刷新逻辑包成阿里云 SDK 的凭证 provider过期前 5 分钟自动回调刷新每个任务起独立 SDK 客户端配 30 s 单请求 / 24 h 整任务超时和 3 次重试最后用 SDK 的可断点续传上传5 MB 一片checkpoint 写在同一 staging 目录云端路径是dir/录制目录名_协同标识/head|left|right.tar.gz三机协同时同一协同标识落在同一二级目录下成功 → 清 staging用户取消 → 清 staging网络/服务端错误 → 故意保留 staging 让下次进来跳过已传分片续传服务端孤儿分片由桶生命周期策略兜底每次冷启动还会扫一遍 staging 删除解析失败/不在活跃队列/7 天未动的孤儿。细拆刻行跟dm3上传逻辑一、两条路径在做的事其实是一样的不管走哪条本质都是把那个.tar.gz推到一个云端对象存储里。区别只在于凭什么权限去推和推的姿势。走刻行app 自己没有云端的钥匙它先找刻行后端要一把一次性临时门票带签名的 PUT URL再用普通 HTTP 一口气传上去。走 DM3app 找 DM3 后端要一把短期工牌STS 临时密钥带过期时间凭这把工牌直接以客户身份到阿里云对象存储那边按云厂商原生的分片续传协议传。一句话刻行那边是门票一次性 PUTDM3 是工牌原生协议分片。所以 DM3 比较啰嗦但能力上确实强不少。二、刻行那条路径的脆弱点把刻行的姿势再拆一下几个隐性约束就出来了那个签名 PUT URL 是一次性且有时效的必须一口气 PUT 完整个.tar.gz中途断了URL 可能就过期了下次得重新去要一次。它走的是 HTTP PUT 的整文件上传语义没有断点传到 80% 网断了下次只能从 0% 开始。一次性 PUT 由 URLSession 自己管你没法精确地告诉它这一段已经传过了不要重来。所有上传都得走刻行后端发 URL 这一跳刻行后端挂了传不了要换别的 region 也得它配合。对几十 MB 的录制重传一次大不了等几秒钟无所谓但 app 的录制经常是几百 MB 到几 GBPUT 到 90% 网络抖一下就全废这事在差网络下非常痛。三、DM3 是怎么把这些痛点逐一破掉的理解 DM3 那套设计的钥匙就是把凭证和上传解耦把上传过程变成可中断、可恢复的状态机。它一共做了 4 件互相咬合的事1. 用 STS 把长期账号换成短期工牌安全令牌服务核心就是发临时权限凭证DM3 后端不会把云厂商的长期 ak/sk 给客户端那等于把保险柜钥匙给陌生人。它每次只发一对临时凭证access key、secret、安全 token、过期时间再加上你这次能往哪个桶 / 哪个目录写。好处即使临时凭证泄露几小时就过期了破坏面很小。客户端拿这把工牌直连云厂商不再每分钟都去 ping DM3 后端发 URLDM3 后端只负责发凭证这一下瞬时压力低可用性更好。桶、地域是 STS 现说现给的后端要换 region、换桶、按账号路由都不用改 app。2. 凭证用的时候才刷——不是定时器是回调如果你写过定时器刷 token 的代码会知道一堆边界 caseapp 退后台定时器停了、刷新和上传请求打架、刷新失败要不要重试、临界点 ms 误差……这里改成把如何从 DM3 后端拉一次新凭证包成一个回调交给云 SDKSDK 内部判断当前凭证还剩 5 分钟内会过期吗是就当场同步回调一次这个闭包拉新的不是就直接复用旧的。app 这边一行定时器都没有不会有刷过头刷漏刷打架。底层有个细节SDK 要的是同步返回但拉凭证是异步网络请求为此那段代码用Task.detached信号量把异步硬转同步——这事看起来很怪但被严格限定在只在 SDK 后台线程的回调里调所以不会卡主线程。3. 真正的杀招原生分片 断点续传这一步是 DM3 比刻行强出最多的地方。分片把.tar.gz切成 5 MB 一块每块独立上传一次。一块失败只重传这一块不影响别的。断点续传上传任务在云端有个 uploadId一边传云端就一边记哪些块已经收到了。客户端这边对应也有一份本地 checkpoint 文件记着 uploadId、分片大小、已完成块号。把这两条合起来就有了非常关键的能力这次传到 60% 时进程被杀掉。下次启动 appSDK 看到本地 checkpoint会先去云端 ListParts 问一句我上次报的这个 uploadId你那边收到哪些块了然后只补传剩下那 40%并把所有块合并成最终对象。这就是为什么 DM3 路径里还需要一个持久化的 staging 目录——不像刻行那样把.tar.gz扔临时目录里跑完就丢DM3 要把.tar.gz和 SDK 的 checkpoint 绑在一起存到Documents下进程被杀、用户重启 app、网卡换 Wi-Fi 再回 4G 都能接着传。刻行那一条是传到 90% 断了从 0 重来DM3 是传到 90% 断了从 90 接着来。在几 GB 文件 弱网场景下这就是能上得去和永远上不上去的差别。4. 失败、取消、重启的三种状态机非常清晰DM3 这套之所以看起来深奥是因为它把三种异常做了截然不同的处理不像刻行只能一刀切重传情况本地 staging云端那个未完成的分片任务用户主动取消主动整个删掉续传也没意义了不调中止接口让云端按生命周期策略自动清网络/服务端错误故意保留保留下次进来 ListParts 续传上传成功删掉含 .tar.gz checkpoint自动转正孤儿分片自动消失app 冷启动后扫一遍三种条件之一就清目录名解析失败 / 不在活跃队列 / 7 天没动同上由桶生命周期兜底staging iPhone 上Documents/dm3UploadResume/下的一个本地暂存目录每条 DM3 上传任务一个里面同时放打好的.tar.gz和阿里云 SDK 的续传 checkpoint作用就是让上传可以跨进程被杀、跨重启、跨网络中断地从中间接着传。这里有几个故意为之的设计判断特别值得说取消时不调中止上传接口而是让云端的桶生命周期策略建议 7 天来兜底清理孤儿分片。原因是调这个接口需要给客户端一个额外的 IAM 权限部署时多一个坑不调它权限可以收得更紧放在那儿过几天自己烂掉反而更稳。错误时不删 checkpoint直觉上失败应该清场但这里反过来——失败保留重试才能续传。清干净的语义只在用户取消和传成功两个场景下才执行。冷启动 GC 是兜底万一某条上传被人为从队列里删除了 / 永远没机会重试 / 网络真的卡了一周那个 staging 目录会被自动回收不会无限占磁盘。四、形象一点的类比刻行那条你委托一个中间人去寄快递。每次寄你都要先打电话给中间人要一张今天寄到上海仓的提货单一次性、有时效然后你必须一口气把整个箱子送到。送一半箱子掉路上那张提货单作废你下次得重新打电话要一张整个箱子从头送。DM3 那条DM3 给你发了一张今天有效的临门工牌让你直接进阿里云仓库。你可以把箱子拆成 5 MB 一份的小盒子一个一个交仓库会逐个登记到你的任务单 uploadId下。送一半你走了没事明天回来打开你家里的小本子本地 checkpoint看上次送到第几个盒子再问仓库前台核对一下没送的接着送全部送完仓库自动把它们拼成一个完整的箱子这期间工牌过期了你的 SDK 助理会自动回去 DM3 前台再换一张新工牌你都感知不到。五、一句话回答强在哪DM3 比刻行那条路径强出来的能力本质就这五条断点续传不再全有或全无弱网/被杀/取消重启都能从中间接着传。凭证短期化长期密钥不下发泄露代价低。凭证自动刷新无感知不依赖任何定时器。不依赖一次性签名 URL不会出现签名过期了得回头再要一张的连锁失败。后端只在发凭证时被路过一次链路短DM3 后端故障不直接拖死上传。代价就是它必须额外维护持久化 staging 目录 冷启动 GC STS 同步桥接这三块工程量看起来比刻行那条复杂但只要文件足够大、网络足够烂这套复杂度立刻就会变成传得上去 vs 传不上去的硬差别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2567176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…