移动互联时代,多媒体开发怎能还用十年前的容器方案?
|
我原以为把 ffmpeg 二进制塞进 alpine:3.12 里跑个 WebRTC 转码,顶多调调 cgroup limits 就完事——结果凌晨三点在机房听它把宿主机的内存控制器干哑火了,风扇嘶吼声比隔壁联通基站还稳。当时窗外正下着雨,雨滴砸在机柜顶盖上是“嗒、嗒、嗒”的钝响,像有人用指甲盖抠铁皮。 老张蹲在 rack 侧边接电话,左手捏着半根没抽完的中南海,烟灰掉在 HPE DL360 的导轨槽里,他也没掸。我说这镜像得重做,他抬眼扫我一眼:“你上回说 glibc 版本不兼容,最后不也硬压过去了?”——可这次不是 glibc,是 kernel 模块和 cgroups v1 下 mlock() 与 memcg 的幽灵交互。我敢打包票:你在 cgroup.procs 里写进程 ID 写得再准,只要它内部开了 libvpx 的 simd 初始化,就会在某个核上偷偷占住 mm_struct 锁不放。这个我亲眼盯过 perf record -e 'sched:sched_switch' 十七分钟,不是猜的。 王工端着泡面进来,塑料叉子插在碗沿上晃悠,汤水没泼出来,但汤面上浮着三颗花椒——他不吃麻,就专挑这个涮。我顺手拿他筷子戳了下 /sys/fs/cgroup/memory/docker/.../memory.limit_in_bytes,返回值是 -1。我愣了两秒才反应过来:哦,这宿主早就关了 memory controller。十年前那个 docker run --memory=2g 的默认行为,现在早被删得只剩文档影子了。而我们那套 CI pipeline 还在用 buildkit 自动拉 2015 年的 base 镜像……你猜它默认启用 cgroups v2 吗?不启。连 mount 命令都懒得报错,就默默走 fallback。真·沉默式自杀。 去年十月在厦门,现场调试某短视频 SDK 接口压测。集群调度器疯狂把容器往低频 CPU 上塞,不是因为亲和性配置错了,是 runtime 不认识 cpuset.cpus.effective 这个字段——它只认 legacy 的 cpuset.cpus,而宿主机内核早切到 cgroup v2 默认挂载了。结果三百七十二个转码 Pod 全挤在四颗物理核上,GPU 共享内存池直接卡死,NVIDIA 的 nvidia-smi 界面刷出一串 EBUSY。我一边敲 dmesg | tail -20,一边看对面楼顶的移动基站指示灯忽明忽暗——和我们监控面板上 Redis 连接数暴跌的节奏完全对不上拍子。 桌上的外卖盒是“潮汕牛肉丸汤”,汤凉了,浮油凝成一小片一小片的、带锯齿边的膜。我用勺背刮了三次才刮净,手滑了,勺子掉进汤里,没响,就咕咚一下沉底。这时候李主任发来消息:“客户问能不能把 HLS 切片时间从十秒压到五百毫秒。”我没回。我盯着那个沉底的勺子,突然想起上周在 GitLab CI 里看到的那行脚本:FROM ubuntu:18.04。编译时用了 gcc-7,运行时 libc 是 2.27,但我们的音视频解码链路依赖一个用 avx512bw 指令做的 yuv420p 转 rgb 的 inline asm——而那台 runner 机器 CPU 是 Intel Xeon E5-2680 v4,压根不支持 avx512。它居然没 segfault,而是静默输出全黑帧。整整十六小时,没人发现。监控只报 CPU idle 高,没人去看 output buffer 的 timestamp 断点。 反常识结论就是:越“稳定”的旧方案,越适合掩盖 bug。就像你把十年车龄的老捷达开上高速,它不会报警,只是方向盘在一百二十码时微微左偏——你以为是胎压问题,其实是转向机齿条磨损。你查三天手册,修两次平衡,最后发现是动力转向泵油封裂了。而新方案至少会直接锁 steering wheel 并亮红灯。优胜劣汰不是温柔淘汰,是直接拔掉 ignition fuse。 上个月在杭州西溪园区,有个实习生问我:“为啥咱们不用 buildah 直接构建成 oci layout?Dockerfile 太重了。”我说你去改 Jenkinsfile 第 83 行,把 image: docker:dind 换成 image: quay.io/buildah/stable:latest。他改完,Pipeline 跑了四分十九秒,失败。日志最后一行写着:ERROR: failed to create LLB definition: dockerfile parse error: Unknown instruction: FROM --platform=linux/amd64。我看了眼构建节点 uname -m,返回 aarch64。他不知道 builder 镜像自己跑在 ARM 上,却要去拉 x86_64 的基础层。这事儿我没法解释——就像没法跟一个没见过磁带的人讲为什么 rewind 按钮必须按两下才能清空缓存一样。 再说个闲事:机房进门第三根立柱后面,贴着张泛黄的 A4 纸,上面用圆珠笔写着“UPS 电池组更换日期:2019.04”。下面还有行小字:“本次未换,电压合格”。这张纸我见过至少五次,每次巡检都看到,但没人撕。它存在,但不生效。就跟我们用的那个 docker-compose.yml 里写的 mem_limit: "4g" 一样。你打开 cgroup 目录看看,那个 memory.max 文件根本不存在。只有 memory.max_usage_in_bytes。而这个文件,从 5.4 内核起,就 deprecated 了。它还在那儿,像一张没撕的过期罚单。
文章配图,仅供参考 所以我今天下午准备动手切第一台 build 节点——先关掉 dockerd,再删掉 /var/lib/docker,再手动 mount overlay2 rootfs 到 /mnt/temp,用 runc spec 生成 config.json,然后……算了,先泡杯茶。王工的泡面汤已经彻底冷透,花椒沉底了,像几粒褐色的微型陨石。(编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


移动互联时代:端云协同优化三大突破
移动互联时代,你的设备还单机?该连了!
移动互联时代:应用驱动的万物互联新架构
物联网+移动互联时代下的数码安全新挑战