树莓派跑了个 M3U8 下载服务,内存从 600MB 降到 2MB
树莓派跑了个 M3U8 下载服务内存从 600MB 降到 2MB最近在树莓派上跑了个 M3U8 下载服务用 Rust 写的。跑了一周发现内存涨到 237MB峰值冲到过 607MB差点把树莓派撑死。先说说这个服务是干嘛的。就是提供一个 Web 页面贴个 M3U8 链接进去服务端下载完转成 MP4。用油猴脚本配合的话浏览视频网站时点一下就把链接发给服务器了不用在自己电脑上下载。问题的根源查了两天代码发现三个要命的地方1. 直传模式的内存泄漏服务有个直传功能下载的同时通过浏览器传回给用户。代码里用了一个 BTreeMap 缓存乱序到达的视频片段但没有任何大小限制。如果片段 0 下载慢了后面 139 个片段全堆在内存里。一个片段 2-5MB堆 100 多个就是 300-700MB。修复很简单加了个max_buffered上限超出就 sleep 等待消费掉再继续letmax_bufferedself.concurrent.saturating_mul(2).max(8);ifbuffer.len()max_buffered{tokio::time::sleep(Duration::from_millis(100)).await;}2. 回调风暴每下载完一个片段就触发一次进度更新每次更新都 spawn 一个异步任务。140 个片段 × 20 次更新 2800 个短暂任务调度开销全变成了堆碎片。改成 250ms 节流用 AtomicU64 记录上次更新时间间隔不足就跳过。3. 合并时整段读入内存下载完成后合并片段时每个片段都read_to_end读到 Vec 里再写出去大片段一把就吃掉 10MB。改成tokio::io::copy流式拷贝64KB 缓冲区搞定。修完后的效果改了之后重启空载时常驻内存从 237MB 掉到 1MB# 优化前跑了一周sudosystemctl status down Memory:237.6M(peak:607.9M)# 优化后刚启动空载sudosystemctl status down Memory:1.0M(peak:1.7M)跑了几个下载任务之后再测1.5 小时常驻 146MB峰值 273MB——比起旧版同期数据启动就 200M跑着跑着奔 607M已经稳定太多了# 优化后1.5 小时跑过多次下载任务sudosystemctl status down Memory:146.2M(peak:273.3M)再也不用担心树莓派 OOM 了。另外还加了个 Content-Type 检查有些 M3U8 链接过期后服务器返回 HTML 错误页以前要重试 4 次等 15 秒才报错现在 1 秒内快速失败。用到的技术栈Rust axumWeb 框架tokio异步运行时reqwestHTTP 客户端m3u8-rsM3U8 解析FFmpegTS 转 MP4代码放 GitHub 了https://github.com/Sunrisies/m3u8_download感兴趣的可以 clone 下来cargo build --release编出来 5MBscp 到树莓派上就能跑。依赖就一个 FFmpeg用来合并转码其他全静态编译。